【问题标题】:JavaScript animation with multiple setTimeout具有多个 setTimeout 的 JavaScript 动画
【发布时间】:2013-09-29 17:10:25
【问题描述】:

我正在尝试使用 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);
}

【问题讨论】:

    标签: javascript html canvas


    【解决方案1】:

    动画对象

    在制作数字动画时,永远不需要多个计时器。

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

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

    示例

    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 比其他两个更有效,如果我们需要为很多东西制作动画,这将使我们受益。

    动画对象

    现在我们来看看对象,为什么我们只需要调用 update 和 things animate?

    正如我们之前看到的,我们只需调用以下命令即可创建动画圆形对象:

    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() 方法。

    您可以以不同的位置和速度创建许多这样的对象,并从一个循环中为所有对象设置动画。

    我只为圆圈创建了一个对象以保持简单。您应该能够使用它作为基础创建一个矩形对象以及您拥有的对象。您当然可以扩展对象以跟踪其他内容,例如笔触颜色、角度等。

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

    【讨论】:

    • 非常感谢您的帮助
    • 你能解释一下下面的循环吗:for(var i = 0, ao; ao = animObjects[i]; i++) { ao.update(); } 我不明白你是如何声明 ao 的;
    • 还有多久调用一次循环函数?
    • @KarishKarish ao 在 for 第一个语句 (var i = 0, ao) 之前声明。我在演示中使用了缩写名称,用于 animObject。循环以计算机允许的速度运行,通常为每秒 60 帧。我以为我提到了基于时间的动画,但我似乎忘记了:如果您需要以一定速度运行的动画,无论 FPS 是多少,您都需要根据时间触发运动/动作。
    【解决方案2】:

    如果我的问题是正确的...为什么您不创建三个不同的函数,例如 drawCircle? drawWhatever 并创建三个 setTimeouts?或类似的东西...?

    • 你为什么用这么多 ' ?没有理由这样做:

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

    【讨论】:

    • 谢谢你,我正在考虑,但不确定它是否是最好的方法
    • 我认为这是一个好方法。分开的、有组织的代码总是更好的选择:P 如果您对答案感到满意,请标记答案。
    • 所以我应该只使用一个 var loopTimer = setTimeout('draw('+x+','+y+')',20);并在每个函数中调用它?
    • 慢?有多慢?为什么慢?这对我来说没有意义。它只是简单的圆圈绘制。
    • 经过一些更改后它可以工作,但由于某种原因,它不会在动画时删除保留的形状。以下行:context.clearRect(0,0,720,550);不能正常工作
    猜你喜欢
    • 1970-01-01
    • 2015-06-26
    • 1970-01-01
    • 2015-03-07
    • 1970-01-01
    • 2012-05-20
    • 1970-01-01
    • 2018-08-11
    • 1970-01-01
    相关资源
    最近更新 更多