canvas动画教程-2 基础设施

本文介绍并封装了canvas动画中常用的类,如Stage、Renderer、Loader、Sprite和Graphics,通过一个实例展示了如何使用这些类实现动画效果。文章还提供了源码链接,便于读者深入学习。

上一篇介绍了canvas的基本用法和canvas动画的原理,最后提到为了编程方便,我们会封装一些类。这篇文章对封装的这些类进行简单的介绍。

Stage

舞台。一个项目中只有一个舞台对象,所有可视对象都被添加进舞台的children数组中。舞台对象拥有一个render属性,是Renderer类的一个实例,用于对可视对象进行渲染。Stage提供两个方法,其实现如下:

addChild: function (child) {
    this.children.push(child);
},
render: function () {
    if (this.update) {
        this.update();
    }
    this.renderer.render(this.children);
    requestNextAnimationFrame(this.render.bind(this));
},
复制代码

addChild用于将可视对象添加进children中,render方法相当于上一节中提到的animate方法,用于实现动画循环。其中this.update方法为动画的更新逻辑,每一帧都会执行一次。执行完更新逻辑后重新渲染可视对象,就实现了动画的效果。

Renderer

用于实现渲染,提供一个render方法:

render: function (displayObjectArr) {
    if (!this.ctx || typeof this.ctx.drawImage !== 'function') {
        return;
    }

    this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height);

    for (var i = 0, n = displayObjectArr.length; i < n; i++) {
        displayObjectArr[i].draw(this.ctx);
    }
}
复制代码

该方法在stage中调用,先清除上一帧的内容,然后分别调用每一个可视对象的draw方法进行绘制。可视对象的draw方法由可视对象自己实现,这里只负责调用即可。

Loader

用于加载图片资源。提供三个方法:

add: function(src){
    this._srcArr.push(src);
},
load: function(callback){
    var _this = this;
    var count = 0;
    for (var i = 0; i < this._srcArr.length; i++) {
        var imgObj = this._srcArr[i];
        var src = imgObj.src;
        var img = new Image();
        img.onload = function(){
            count++;
            _this._imgs[imgObj.name] = img;
            if (count === _this._srcArr.length) {
                if (callback) {
                    callback();
                }
            }
        }
        img.onerror = function(){
            count++;
            console.log(src + ' 下载失败');
        }
        img.src = src;
    }
},
get: function(key){
    return this._imgs[key];
}
复制代码

add用于添加图片对象,该对象包括name和src两个属性。load用于实现加载。get方法用于通过图片的name获取图片对象。

Sprite

精灵,是一种可视对象,可以理解为一个集成了动画的图形对象,它包含了绘制出这个图形所需要的所有信息,包括一个图片对象,以及它的位置、宽高、角度以及锚点位置等信息。通过这些信息,我们就能将精灵对象绘制在canvas画布上,具体绘制方法如下:

draw: function (ctx) {
    ctx.save();

    ctx.translate(this.x, this.y);
    if (this.rotation) {
        ctx.rotate(this.rotation);
    }
    ctx.translate(-this.pivotX, -this.pivotY);
    ctx.drawImage(this.image, 0, 0, this.image.width, this.image.height, 0, 0,
        this.width || this.image.width, this.height || this.image.height);

    ctx.restore();
}
复制代码

通过改变该对象的x、y、width、height、rotation、pivotX和pivotY属性,就可以改变图片在当前帧中出现的位置、大小、角度等。

Graphics

是另一种可视对象,用于绘制多边形。该对象同样也保存了绘制一个多边形所需要的全部信息,可以用它来绘制线条、矩形、圆等。这个类的实现比较复杂,方法也比较多,不一一介绍,有兴趣的可以去看看源码。这里只说明一下它绘制的思想:多边形对象拥有一个私有数组属性_actions,每一个跟绘制逻辑有关的方法其实是往_actions数组里添加了一个“动作”,这些动作其实就是绘制的具体步骤。在调用draw方法时,会依次执行这些绘制的动作,这样,多边形就被绘制在了canvas画布上。

Polyfill

实现了两个方法,主要用于兼容各个浏览器。一个是requestNextAnimationFrame,是requestAnimationFrame的一个polyfill实现,用法与requestAnimationFrame相同,在浏览器支持requestAnimationFrame时使用requestAnimationFrame,不支持时则使用setTimeout代替;另一个是函数的bind方法,在浏览器支持bind方法时使用原生的bind,不支持时则使用自定义的bind。

例子

OK,写了这么多,究竟好不好用?让我们来试一下:

//定义一个舞台
var stage = new Stage(document.getElementById('canvas'));

//加载资源
var loader = new Loader();
loader.add({name: 'ball', src: './images/ball.png'});
loader.load(createScene);

//创建场景
function createScene() {
    //创建Sprite的一个实例对象ball
    var ball = new Sprite({
        x: 20,
        y: 20,
        width: 16,
        height: 16,
        pivotX: 32,
        pivotY: 32,
        image: loader.get('ball')
    });
    //将ball加入舞台
    stage.addChild(ball);
    
    //定义更新逻辑
    stage.update = function () {
        
        ball.x += 2;
        ball.y += 1;

        ball.rotation += 0.1;
        
        if (ball.width < 64) {
            ball.width += 1;
            ball.height += 1;
        }
    }
    
    //开始绘制
    stage.render();
}
}
复制代码

不出意外的话,可以看到如下动画效果:

小结

本文对canvas动画中用到的一些类及其实现进行了介绍,并通过一个例子演示了其用法。由于这个系列文章的主要目的是介绍一些基础canvas动画效果的实现原理及方法,而不是实现一个canvas动画引擎,所以只对这些类进行了简单的实现,能够满足后续演示的需求即可。要深入了解比较完备的实现,可以研究一下当前流行的一些框架的源码,如阿里的Hilo,以及国外的phaser等。
对于canvas的基础介绍到这里就结束了,下一篇文章开始,我们来正式介绍如何实现一些特定的动画效果。
奉上本系列文章所涉及的源码的git地址,喜欢的话麻烦给个star哦!

相关文章列表

转载于:https://juejin.im/post/5bb9db98f265da0ae8012c9c

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值