Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/html/69.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何一个接一个地设置多个HTML5画布对象的动画?_Javascript_Html_Html5 Canvas - Fatal编程技术网

Javascript 如何一个接一个地设置多个HTML5画布对象的动画?

Javascript 如何一个接一个地设置多个HTML5画布对象的动画?,javascript,html,html5-canvas,Javascript,Html,Html5 Canvas,我想用HTML5画布和JavaScript制作一个动画。其思想是为不同的对象编写类,如下所示: class Line { constructor(x1, y1, x2, y2) { this.x1 = x1; this.y1 = y2; ... } draw() { } } class Circle { constructor(x, y, radius) {

我想用HTML5画布和JavaScript制作一个动画。其思想是为不同的对象编写类,如下所示:

    class Line {
      constructor(x1, y1, x2, y2) {
        this.x1 = x1;
        this.y1 = y2;
        ...
      }

      draw() {
        }
    }

    class Circle {
      constructor(x, y, radius) {
        this.x = x;
        ...
      }

      draw() {}
    }

    ...
然后,在主代码中,您所要做的就是一个接一个地绘制形状,中间有停顿:

let line1 = new Line(x1, y1, x2, y2);
let circle = new Circle(x, y, r);
let line2 = new Line(x1, y1, x2, y2);

line1.draw()
pause()
circle.draw()
pause()
line2.draw()

...

有没有一种简单的方法(不必处理承诺和嵌套的回调函数),例如通过使用某个库?

一个好问题,因为您不想做的事情(使用承诺和/或回调)实际上意味着在脚本中硬编码动画,重复使用的可能性有限,并可能在将来进行修改时造成困难

我使用的一个解决方案是创建一个函数的故事书来绘制框架,这样您就可以

()=>line1.draw()
写进书中,而不是

line1.draw()
这将立即绘制它,并尝试将其返回值添加到书本中

下一部分(没有特定的顺序)是一个玩家,它使用时间步进遍历故事书并调用函数来绘制框架。至少,它需要一些方法来编写脚本

  • 添加框架绘图功能
  • 在前进到下一帧之前添加延迟,并且
  • 播放动画
使delay函数在调用故事书中的下一个条目之前等待若干帧可以使其保持简单,但会根据帧速率创建计时,而帧速率可能不是恒定的

这里有一个纯JavaScript的简化示例,用于更改背景颜色(而不是画布操作)以进行演示—如果无法使其正常工作,请查看参考

“严格使用”;
类动物饲养者{
构造函数(){
this.storyBook=[];
此参数为0;
this.drawFrame=this.drawFrame.bind(this);
this.frameNum=0;
}
添加框架(框架抽屉){
这个。故事书。推(框架抽屉);
}
pauseFrames(n){
this.storyBook.push(()=>this.pause=n);
}
play(){
this.frameNum=0;
这个.drawFrame();
}
牵引架(){
如果(this.pause>0){
--这是暂停;
requestAnimationFrame(this.drawFrame);
}
else if(this.frameNumstyle.backgroundColor=“绿色”);
球员波塞弗拉姆斯(60);
player.addFrame(()=>style.backgroundColor=“黄色”);
球员暂停比赛(5);
player.addFrame(()=>style.backgroundColor=“橙色”);
球员波塞弗拉姆斯(60);
player.addFrame(()=>style.backgroundColor=“红色”);
球员波塞弗拉姆斯(60);
player.addFrame(()=>style.backgroundColor=“”);
函数tryMe(){
console.clear();
player.play();
}
试用我
关键帧 你可以使用关键帧来制作几乎任何东西的动画效果

下面的示例(本打算做更多的总结,但我太迟了,你已经接受了答案)展示了一个非常基本的关键帧实用程序如何创建动画

关键帧只是一个
时间
和一个

关键帧将添加到为值命名的轨迹中

因此,名称
x
(位置)和键{time:0,value:100},{time:1000,value:900}将在0到1秒的时间内将
x
属性从
100
更改为
900

例如一个圆

const circle = {
    x: 0,
    y: 0,
    r: 10,
    col : "",
    draw() { 
        ctx.fillStyle = this.col;
        ctx.beginPath(); 
        ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2); 
        ctx.fill() 
    }
};
可以随时间更改其任何属性

首先创建轨迹对象并定义关键点

const circleTracks = createTracks();

// properties to animate
circleTracks.addTrack("x");
circleTracks.addTrack("y");
circleTracks.addTrack("r");
circleTracks.addTrack("col");
然后在特定的时间戳添加关键帧

circleTracks.addKeysAtTime(0, {x: 220, y :85, r: 20, col: "#F00"});
circleTracks.addKeysAtTime(1000, {x: 220, y :50, r: 50, col: "#0F0"});
circleTracks.addKeysAtTime(2000, {x: 420, y :100, r: 20, col: "#00F"});
circleTracks.addKeysAtTime(3000, {x: 180, y :160, r: 10, col: "#444"});
circleTracks.addKeysAtTime(4000, {x: 20, y :100, r: 20});
circleTracks.addKeysAtTime(5000, {x: 220, y :85, r: 10, col: "#888"});
circleTracks.addKeysAtTime(5500, {r: 10, col: "#08F"});
circleTracks.addKeysAtTime(6000, {r: 340, col: "#00F"});
准备好后,清理钥匙(您可以按时间顺序添加)

从头开始

circleTracks.seek(0);
并更新对象

circleTracks.update(circle);
要设置动画,只需调用tick和update函数,并绘制圆

circleTracks.tick();
circleTracks.update(circle);
circle.draw();
例子 单击以开始动画。 当动画结束时,您可以使用
tracks.seek(时间)

这是最基本的关键帧动画

关键帧最好的一点是,它们将动画与代码分离,让您可以将动画作为简单的数据结构导入和导出

const ctx=canvas.getContext(“2d”);
requestAnimationFrame(主循环);
常量allTracks=[];
函数addKeyframedObject(轨迹、对象){
tracks.clean();
寻道(0);
跟踪。更新(对象);
push({tracks,object});
}
常数帧/秒=60,刻度=1000/帧/秒//
常量键=(时间,值)=>({time,value});
var=false;
var showscriber=false;
var currentTime=0;
函数mainLoop(){
clearRect(0,0,ctx.canvas.width,ctx.canvas.height);
如果(玩){
用于(所有轨迹的常数){
动画.tracks.tick();
动画.tracks.update(动画.object);
}
}
用于(所有轨迹的常数){
动画.object.draw();
}
if(显示洗涤器){
slide.update();
slide.draw();
如果(slide.value!==当前时间){
currentTime=slide.value;
用于(所有轨迹的常数){
动画.tracks.seek(当前时间);
动画.tracks.update(动画.object);
}
}
}否则{
if(mouse.button){playing=true}
}
如果(所有轨迹[0].tracks.time>6300){
showScriber=true
玩=假;
}
requestAnimationFrame(主循环);
}
常量文本={
x:canvas.width/2,
y:canvas.height/2,
阿尔法:1,
正文:“,
draw(){
ctx.font=“24px arial”;
ctx.textAlign=“中心”;
ctx.textb基线=“中间”;
ctx.fillStyle=“#000”;
ctx.globalAlpha=this.alpha;
ctx.fillText(this.text,this.x,this.y);
ctx.globalAlpha=1;
}
}
常数循环
circleTracks.tick();
circleTracks.update(circle);
circle.draw();