Canvas动画:精灵动画(序列帧动画)

柴英博
2023-12-01

精灵动画(序列帧动画)

播放精灵动画用到的绘图方法是drawImage(image,sx,sy,sw,sh,dx,dy,dw,dh);
精灵动画原理:每次只分割出其中一副图像并绘制出来,每隔一段时间便重绘下一幅动画帧,如此便可以做到按顺序播放动画帧的每张图片。

window.onload=function(){
        var oCanvas = document.getElementById('c1');
        var oCtx = oCanvas.getContext('2d');
        var x=100,y=100;
        var nFrame=0;
        var oFishImg = new Image();
        oFishImg.src = "images/鱼动画.png";
        oFishImg.onload = function(){
            setInterval(function(){
                oCtx.clearRect(0,0,oCanvas.width,oCanvas.height);
                oCtx.drawImage(oFishImg,0,nFrame*148,201,148,20,20,201,148);
                nFrame++;
                if(nFrame>=4) {
                    nFrame=0;
                    }
                },30);
            }
        }

精灵帧预渲染

在精灵动画制作中,需要重复绘制不同动画帧,我们可以先把图像绘制到一个不可见的画布上,当需要更换动画帧时,再把这个预先绘制好的画布渲染到可见画布,提高了渲染的效率。

var oCanvas = document.getElementById('c1');
var oCtx = oCanvas.getContext('2d');
var x=20,y=20;
var nFrame=0;
var oFishImg = new Image();
oFishImg.src = "images/鱼动画.png";
oFishImg.onload = function(){
    var frames=[];
    for(var i=0;i<4;i++){
        var can = document.createElement('canvas');
        can.width=201;
        can.height=148;
        var ctx=can.getContext('2d');
        ctx.drawImage(oFishImg,0,i*148,201,148,0,0,201,148);
        frames[i]=can;
    }

    setInterval(function(){
        oCtx.clearRect(0,0,oCanvas.width,oCanvas.height);
        oCtx.drawImage(frames[nFrame],x,y);
        nFrame++;
        if(nFrame>=4) {
            nFrame=0;
        }
    },30);
};

精灵对象封装

在游戏或动画中往往需要创建出多个动画,如同时有几条鱼在游,如果只是简单的把代码复制几份,那么代码就会变成冗余且混乱。
可以考虑使用面向对象的方法重写代码,使代码整洁并且方便调用。
Fish类

var Fish = function (image, x, y, width, height) {
    this.image = image;
    this.x = x;
    this.y = y;
    this.averageY = y;
    this.width = width;
    this.height = height;
    this.frm = 0;
    this.dis = 0;
    this.velocity = 2;
    this.disV = 0;
};

Fish.prototype.draw = function (ctx) {
    ctx.save();
    ctx.translate(this.x, this.y);
    ctx.drawImage(this.image, 0, this.frm * this.height, this.width, this.height, 0, 0, this.width, this.height);
    ctx.restore();

    this.x += this.velocity;

    this.disV++;
    if (this.disV >= 90) {
        this.velocity = 1 + 2 * Math.random();
    }

    if (this.x >= 800) {
        this.x = -200;
    }

    this.y = this.averageY + 50 * Math.sin(Math.PI / 100 * this.x);

    this.dis++;
    if (this.dis >= 20) {
        this.dis = 0;
        this.frm++;
        if (this.frm >= 4) this.frm = 0;
    }
};

Fish类调用

var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var image = new Image();
var image2 = new Image();
var image3 = new Image();
var image4 = new Image();
var background = new Image();
background.src = "海底.png";
image.src = "鱼动画.png";
image2.src = "鱼动画2.png";
image3.src = "鱼动画3.png";
image4.src = "鱼动画4.png";

image4.onload = function () {
    var fish1 = new Fish(image, -200, 20, 201, 148);
    var fish2 = new Fish(image2, 20, 200, 200, 173);
    var fish3 = new Fish(image3, 240, 50, 200, 186);
    var fish4 = new Fish(image4, 480, 110, 200, 170);
setInterval(function() {
        context.clearRect(0, 0, 800, 374);
        context.drawImage(background, 0, 0);

        fish1.draw(context);
        fish2.draw(context);
        fish3.draw(context);
        fish4.draw(context);

}, 1000 / 60);
};
 类似资料: