具有多个setTimeout的JavaScript动画

时间:2013-09-28 21:43:25

标签: javascript html5 canvas

我正在尝试使用setTimeout为3种不同的形状制作动画,我的问题是如何使用多个setTimeout来动画3种不同的形状也有更好的方法可以使用setInterval

window.onload = draw;
var x = 5;
var y = 5;

radius = 50;

var x2 = 50;
var y2 = 120;

var x3 = 53;
var y3 = 230;
var context;

var loopTimer;

function draw(){
var canvas = document.getElementById('canvas');
 context = canvas.getContext('2d');
context.save();
context.clearRect(0,0,720,550);

rectangle(x,y);
circle(x2,y2);
circle2(x3,y3);

}

function rectangle(x,y){
//drawing a rectangle 
context.fillStyle = "rgba(93,119,188,237)";
context.clearRect(0,0,720,550);
context.rect(x, y, 50, 50);
context.fill();
context.lineWidth = 7;
context.strokeStyle = 'yellow';
context.stroke();
x += 1;
loopTimer = setTimeout('rectangle('+x+','+y+')',50);
}

function circle(x2,y2){
//darwong a circle
context.beginPath();
context.clearRect(0,0,720,550);
context.fillStyle = "#0000ff";  
//Draw a circle of radius 20 at the current coordinates on the canvas. 
context.arc(x2, y2, radius, 0, Math.PI*2, true); 
context.closePath();
context.fill();
x2 += 1;
loopTimer = setTimeout('circle('+x2+','+y2+')',20);
}

function circle2(x3,y3){
//drawing a second circle 
context.beginPath();
context.clearRect(0,0,720,550);
context.fillStyle = 'green';
context.arc(x3, y3, radius, 0, Math.PI*2, true); 
context.closePath();
context.fill();
context.lineWidth = 5;//border around the circle 
context.strokeStyle = 'red';
context.stroke();
x3 += 1;
loopTimer = setTimeout('circle2('+x3+','+y3+')',20);
}

2 个答案:

答案 0 :(得分:6)

动画对象

进行数字动画时,不需要多个单一的计时器。

关键是将属性绑定到动画对象,例如它的位置,速度(或步长),颜色,形状等。

其逻辑步骤是创建自定义对象,我们可以收集此信息并使用更新功能在循环中的一个步骤中为我们完成所有更新。

实施例

<强> ONLINE DEMO HERE

让我们创建一个对象集合,我们存储所有对象:

var animObjects = [];

没什么好看的 - 只是一个数组。

单循环

为了说明这是多么简单,我将首先展示循环本身,然后剖析对象。循环只是遍历我们的集合并在每个对象上调用update方法:

function loop() {

    /// clear canvas before redrawing all objects   
    ctx.clearRect(0, 0, demo.width, demo.height);

    /// loop through the object collection and update each object
    for(var i = 0, animObject; animObject = animObjects[i]; i++) {
        animObject.update();
    }

    /// use this instead of setTimeout/setInterval (!)
    requestAnimationFrame(loop);
}

现在,您注意到我们在这里使用了requestAnimationFrame(rAF)而不是setTimeoutsetInterval。 rAF允许我们与监视器的更新频率同步,而setTimout / setInterval则不能。此外,如果我们需要为很多东西制作动画,那么rAF比其他两个效率更高,这将使我们受益。

动画对象

现在让我们看一下这个对象,为什么我们只需要调用更新和动画?

正如我们之前看到的,我们只需调用:

即可创建一个动画圆圈对象
var animObject = new animCircle(context, x, y, radius, color, stepX, stepY);

这允许我们设置我们想要使用的上下文(如果我们使用多个画布层),每帧的起始位置,颜色和步数。请注意,可以在动画期间更改这些属性(例如,更改半径和颜色)。

对象本身看起来像这样 -

function animCircle(ctx, x, y, r, color, stepX, stepY) {

    /// keep a reference to 'this' context for external calls
    var me = this;

    /// make the parameters public so we can alter them
    this.x = x;
    this.y = y;
    this.radius = r;
    this.color = color;
    this.stepX = stepX;
    this.stepY = stepY;

    /// this will update the object by incrementing x and y
    this.update = function() {

        me.x += me.stepX;
        me.y += me.stepY;

        /// additional updates can be inserted here

        render();
    }

    /// and this takes care of drawing the object with current settings
    function render() {
        ctx.beginPath();
        ctx.arc(me.x, me.y, me.radius, 0, 2 * Math.PI);
        ctx.closePath();
        ctx.fillStyle = me.color;
        ctx.fill();
    }
    return this;
}

这就是它的全部!

对象update()方法将为我们完成所有计算,并调用内部render()方法。

您可以在不同的位置和速度创建许多这些对象,并通过单个循环为所有对象设置动画。

我只为圆圈创建了一个对象以保持简单。您应该能够为矩形创建一个对象,并以此为基础创建对象。您当然可以扩展对象以跟踪其他事物,例如笔触颜色,角度等。

为了演示,我还让对象从画布的边缘反弹。请根据需要进行调整。

答案 1 :(得分:1)

如果我的问题正确...为什么你不创建像drawCircle这样的三个不同的函数? drawWhatever并创建三个setTimeouts?或类似的东西......?

  • 为什么你这样使用曼尼?没有理由这样做:

    var loopTimer = setTimeout('draw('+ x +','+ y +')',20);