从数组中动画画布

时间:2016-10-09 00:34:51

标签: javascript arrays canvas html5-canvas jquery-animate

一个导致矩形从画布的顶部移动到底部的函数,唯一可以改变的是矩形的x位置...所以说createRect(x)。每次调用时,指定x位置的新矩形都会从上到下移动。

想要一个存储一系列不同x值的数组,然后以正确的顺序调用该函数。时间更复杂。我希望能够指定说第一个是5秒,之后是10秒,依此类推。这是我挣扎的一点,因为据我所知,我可以通过一个循环遍历数组并为每个值创建矩形,但不确定时间。

示例数组数据:

  • 4,10 // x位置4,10秒后创建矩形
  • 7,15
  • 2,15 // x位置2,15秒后创建矩形
  • 20,19

结果可能是多个矩形同时移动或一起出现在画布上。提前谢谢你的帮助, 丹

1 个答案:

答案 0 :(得分:0)

不要使用计时器事件来动画许多项目!

制作动画时,您需要与显示器刷新率保持同步,以便您的动画非常流畅。

不要返回

从渲染函数返回到空闲状态实际上是更新DOM的请求。

您不能只在自己的时间内设置时间事件并在每个项目上呈现。每次将函数退出到空闲上下文(没有代码运行)时,浏览器都会假定您完成了渲染并将显示所有更改。这将减慢一切,减少剪切,闪烁,丢失渲染和janky play等动画制品。使用计时器为各个项目制作动画是一种非常糟糕的动画制作方式。

统治所有人的一项功能

要制作任何动画,您必须通过一次通话完成。当你退出时,你应该完全重新渲染你的场景,它应该准备好呈现给显示器。

这可以使用requestAnimationFrame(callBack)(rAF)这个函数来完成,正如名称所暗示的那样,是专为动画而设计的。

你这样使用它

function mainLoop(time){ // when this function is call the time is provided 
                         // by the browser.
    // from this point to the end of the function nothing will reach the 
    // display

    // render everything you need to

    // request the next frame
    requestAnimationFrame(mainLoop);

    // only after you exit will what you have rendered be presented to the 
    // display. The browser will make sure it is present in sync with the 
    // display hardware refresh rate and the rest of the DOM

}
// start the animation
requestAnimationFrame(mainLoop);

rAF函数就像一个setTimeout但没有你设置时间。当它调用您的函数时,它还会在页面加载后的ms 1/1000中添加时间。您可以使用此计时器来控制动画。 (我发现从其他来源获取时间,日期或表现不如时间参数准确。)

<强>代码

以下是使用rAF和每帧一次调用解决问题的方法。

<强>箱

保留方框的一些代码。什么时候开始。框开始{x :?,y:?}以及框需要移动多长时间。

var boxes = [];
function addBox(when,where,howLong){
    var b;
    boxes.push(b = {
        when : when,
        where : where,
        len : howLong,
    });
    return b;
}

主循环

主要更新功能。管理时间和调用渲染功能&quot; updateAll()&#39;

var globalTime; //as time is important make a global for it
var startTime; // we need to have a referance point

function mainLoop(time){
    if(startTime === undefined){
         startTime = time;
    }
    globalTime = time-startTime; // set time
    updateAll();  // call the main logic
    requestAnimationFrame(mainLoop);
}
requestAnimationFrame(mainLoop);

<强>设置

代码随机添加框,因为我很懒。

const boxSize = 20; // pixel size
const playFor = 30; // how long all this will take
const numBoxes = 20; 
function setup(){
    var i
    for(i = 0; i < numBoxes; i ++){
        addBox(
            Math.random() * (playFor-1) * 1000 + 1000, // get time to start box
            {
                 x :Math.floor(Math.random() * (canvas.width - boxSize)) + boxSize / 2,
                 y : canvas.height + boxSize / 2 // start below bottom
            },
            Math.random() * 5 * 1000 + 1000  // play for over 1 sec less than 6
        );
    }
}
setup(); // make some random boxes

全部更新...

现在更新功能。这会渲染,并在需要时移动框。当一个盒子完成它的东西将它从数组中删除,所以我们不必处理它。

function updateAll(){
    ctx.clearRect(0,0,canvas.width,canvas.height); // clear the screen

    // iterate box array and check for new starts
    for(var i = 0; i < boxes.length; i ++){
        var b = boxes[i];
        if(!b.moving){ // is box not moving ???
             // check th time
             if(b.when < globalTime){  // it needs to start
                  b.moving = true; // flag it to move
             }
         }
         if(b.moving){ // move boxes that need it
              var pos = globalTime - b.when; // get pos in time
              if(pos < b.len){ // not at end yet 
                  pos /= b.len; // normalize time pos
                  pos = (b.where.y - (-boxSize /2)) * pos; // distance to past the top
                  // now draw the box;
                  ctx.fillRect(b.where.x - boxSize /2, b.where.y - boxSize - pos, boxSize, boxSize);
              }else{  // box has reached the end dont need it no more
                  // any last words Box!!
                  boxes.splice(i,1); // Bang
                  i -= 1;  // clean up the loop counter
              }
         }
    }
}

这就是你所需要的。这些盒子都会在正确的时间移动,即使丢帧也会保持完美的时间,更新频率并不重要。

演示

该演示展示了它的实际效果。当盒子耗尽时,演示会继续运行,它会增加更多时间并重置时间(没有任何演示无效)

&#13;
&#13;
const boxSize = 30; // pixel size
const playFor = 60; // how long all this will take
const numBoxes = 120; 


var canvas = document.createElement("canvas");
canvas.style.position = "absolute";       // pos absolute to avoid scroll bars
canvas.style.top = canvas.style.left = "0px"; 
canvas.width = innerWidth;
canvas.height = innerHeight;

document.body.appendChild(canvas);
var ctx = canvas.getContext("2d");


var boxes = [];
function addBox(when,where,howLong){
    var b;
    boxes.push(b = {
        when : when,
        where : where,
        len : howLong,
    });
    return b;
}


var globalTime; //as time is important make a global for it
var startTime; // we need to have a referance point

function mainLoop(time){
    if(startTime === undefined){
         startTime = time;
    }
    globalTime = time-startTime; // set time
    updateAll();  // call the main logic
    requestAnimationFrame(mainLoop);
}
requestAnimationFrame(mainLoop);

function setup(){
    var i
    for(i = 0; i < numBoxes; i ++){
        addBox(
            Math.random() * (playFor-1) * 1000 + 1000, // get time to start box
            {
                 x :Math.floor(Math.random() * (canvas.width - boxSize)) + boxSize / 2,
                 y : canvas.height + boxSize / 2 // start below bottom
            },
            Math.random() * 5 * 1000 + 1000  // play for over 1 sec less than 6
        );
    }
}
setup(); // make some random boxes

function updateAll(){
    ctx.clearRect(0,0,canvas.width,canvas.height); // clear the screen

    // iterate box array and check for new starts
    for(var i = 0; i < boxes.length; i ++){
        var b = boxes[i];
        if(!b.moving){ // is box not moving ???
             // check th time
             if(b.when < globalTime){  // it needs to start
                  b.moving = true; // flag it to move
             }
         }
         if(b.moving){ // move boxes that need it
              var pos = globalTime - b.when; // get pos in time
              if(pos < b.len){ // not at end yet 
                  pos /= b.len; // normalize time pos
                  pos = (b.where.y - (-boxSize /2)) * pos; // distance to past the top
                  // now draw the box;
                  ctx.fillRect(b.where.x - boxSize /2, b.where.y - boxSize - pos, boxSize, boxSize);
              }else{  // box has reached the end dont need it no more
                  // any last words Box!!
                  boxes.splice(i,1); // Bang
                  i -= 1;  // clean up the loop counter
              }
         }
    }
    if(boxes.length === 0){ //no more boxes so add more
        setup();
        startTime = undefined; // reset start time for new boxes.
    }

}
  
          
&#13;
&#13;
&#13;