HTML5画布,无法同时运行多个动画
HTML5 Canvas, Having Trouble Running Multiple Animations At Once
我已经编写了两个数组的代码,这两个数组都包含四角形状的坐标(实际上是开始帧和结束帧)、画布ID和时间值。然后,该函数计算每个角的dX和dY,并使用window.performance.now()
创建时间戳。然后,在每个requestAnimationFrame()
上,它通过使用dX、dY、旧时间戳、新时间戳和函数调用的时间值来计算坐标。它看起来像这样:
function doAnim(cv, startFrame, endFrame, animTime)
{
this.canvas = document.getElementById(cv);
this.ctx = this.canvas.getContext('2d');
if(startFrame.length != endFrame.length)
{
return('Error: Keyframe arrays do not match in length');
};
this.animChange = new Array();
for(i=1;i<=startFrame.length;i++)
{
var a = startFrame[i];
var b = endFrame[i]
var c = b - a;
this.animChange[i] = c;
}
this.timerStart = window.performance.now();
function draw()
{
this.requestAnimationFrame(draw, cv);
this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height);
this.currentFrame = new Array();
for(i=1;i<=startFrame.length;i++)
{
this.currentFrame[i] = startFrame[i]+(this.animChange[i]*((window.performance.now()-this.timerStart)/animTime));
}
if((window.performance.now()-this.timerStart)>=animTime)
{
this.ctx.beginPath()
this.ctx.moveTo(endFrame[1], endFrame[2]);
this.ctx.lineTo(endFrame[3], endFrame[4]);
this.ctx.lineTo(endFrame[5], endFrame[6]);
this.ctx.lineTo(endFrame[7], endFrame[8]);
this.ctx.fill();
return;
}
else
{
this.ctx.beginPath()
this.ctx.moveTo(this.currentFrame[1], this.currentFrame[2]);
this.ctx.lineTo(this.currentFrame[3], this.currentFrame[4]);
this.ctx.lineTo(this.currentFrame[5], this.currentFrame[6]);
this.ctx.lineTo(this.currentFrame[7], this.currentFrame[8]);
this.ctx.fill();
}
}
draw();
}
目标是使对象的多个动画同时发生。我采用了整个坐标方法,因为我希望对象看起来像是来自地平线,从而产生假3D透视效果(所有对象的起始帧都是画布中心的一个点),而且我不想扭曲对象的纹理。
好吧,它适用于单个动画,但如果我试图在第一个动画运行时在一个完全不同的画布上开始一个新动画,那么第一个动画就会停止运行。
正如你从我的JS中看到的,我试图通过免费使用this
来绕过这一点(我还不完全理解this
是如何工作的,我读到的每一个解释都让我更加困惑),但它没有起作用。我还尝试了一种可怕的方法,将所有函数自己的变量存储在一个全局数组中(第一次运行函数时,所有变量都放在条目1-30中,第二次放在31-60中,等等)。不出所料,这也没有奏效。
这里有一个JSFiddle,所以您可以亲眼看到这个场景,并使用我的代码。我正式没有主意了。任何帮助都将不胜感激。
与链接的markE一样,尝试多次调用requestAnimationFrame是行不通的。相反,您可以创建多个对象,然后在每帧中对它们调用某种函数。我使用您的代码创建了一个示例:https://jsfiddle.net/samcarlin/2bxn1r79/7/
var anim0frame1 = new Array();
anim0frame1[1] = 0;
anim0frame1[2] = 0;
anim0frame1[3] = 50;
anim0frame1[4] = 0;
anim0frame1[5] = 50;
anim0frame1[6] = 150;
anim0frame1[7] = 0;
anim0frame1[8] = 150;
var anim0frame2 = new Array();
anim0frame2[1] = 200;
anim0frame2[2] = 200;
anim0frame2[3] = 300;
anim0frame2[4] = 250;
anim0frame2[5] = 300;
anim0frame2[6] = 300;
anim0frame2[7] = 200;
anim0frame2[8] = 250;
//Call global
animations = [];
requestAnimationFrame( GlobalStep );
function GlobalStep(delta){
//Functions called by request animation frame have the new time as an argument
//so delta should be approximately the same as window.performance.now()
//especially in realtime applications, which this is
//Check if we have any animation objects
if(animations.length > 0){
//Iterate through and call draw on all animations
for(var i=0; i<animations.length; i++){
if(animations[i].draw(delta)){
//Basically we have it so if the draw function returns true we stop animating the object
//And remove it from the array, so have the draw function return true when animation is complete
animations[i].splice(i, 0);
//We removed an object from the array, so we decrement i
i--;
}
}
}
//And of course call requestAnimationFrame
requestAnimationFrame( GlobalStep );
}
function AnimationObject(cv, startFrame, endFrame, animTime){
//Add this object to the objects arrays
animations.push(this);
//We need to store start and end frame
this.startFrame = startFrame;
this.endFrame = endFrame;
this.animTime = animTime;
//Your code
this.canvas = document.getElementById(cv);
this.ctx = this.canvas.getContext('2d');
if (startFrame.length != endFrame.length) {
return ('Error: Keyframe arrays do not match in length');
};
this.animChange = new Array();
for (i = 1; i <= startFrame.length; i++) {
var a = startFrame[i];
var b = endFrame[i]
var c = b - a;
this.animChange[i] = c;
}
this.timerStart = window.performance.now();
}
//This adds a function to an object, but in such a way that every object shares the same function
//Imagine a kitchen, each object is a person, and this function is a spoon
//by defining this function in this manner Object.prototype.function_name = function(arguments){}
//We make it so one function definition is needed, essentially allowing all the people to share one spoon,
//the 'this' variable still refers to whichever object we call this method, and we save memory etc.
AnimationObject.prototype.draw = function(newTime){
//I added this to start frame so we get what we stored earlier
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
this.currentFrame = new Array();
for (i = 1; i <= this.startFrame.length; i++) {
this.currentFrame[i] = this.startFrame[i] + (this.animChange[i] * ((newTime - this.timerStart) / this.animTime));
}
if ((newTime - this.timerStart) >= this.animTime) {
this.ctx.beginPath()
this.ctx.moveTo(this.endFrame[1], this.endFrame[2]);
this.ctx.lineTo(this.endFrame[3], this.endFrame[4]);
this.ctx.lineTo(this.endFrame[5], this.endFrame[6]);
this.ctx.lineTo(this.endFrame[7], this.endFrame[8]);
this.ctx.fill();
return;
} else {
this.ctx.beginPath()
this.ctx.moveTo(this.currentFrame[1], this.currentFrame[2]);
this.ctx.lineTo(this.currentFrame[3], this.currentFrame[4]);
this.ctx.lineTo(this.currentFrame[5], this.currentFrame[6]);
this.ctx.lineTo(this.currentFrame[7], this.currentFrame[8]);
this.ctx.fill();
}
}
注意事项:每次按下按钮时,都会添加一个新对象,并简单地为每一帧覆盖以前的对象,你应该实现你的程序,以便它检查特定的动画是否已经开始,你也可以使用内置机制在完成时停止动画(阅读代码中的注释)
您还需要更改按钮点击代码
<button onclick="new AnimationObject('canvas1', anim0frame1, anim0frame2, 3000);">
最后,如果您有进一步的问题,请随时联系我
- 动画、计时和运行循环等问题
- HTML5(Bootstrap)通过函数调用运行动画
- 为什么我的脚本正在运行动画,但没有显示它
- 画布动画似乎不会以60帧/秒的速度运行
- 仅在尚未运行jQuery UI的情况下运行动画
- Jquery toggleClass toggle的类,但不会多次运行动画
- 如何在另一个动画正在进行时延迟运行动画
- 运行动画,然后删除元素
- 如何通过Javascript运行动画
- Span元素不从jQuery运行动画
- 点击浏览器返回按钮运行动画
- 如何在每次输入变化时运行动画
- 简单的预加载器,加载所有的资源,并在显示网站和运行动画之前缓存它们
- 用Javascript运行动画后删除html标签
- 在jquery中运行动画后激活add类
- 同时运行动画不工作
- jQuery 运行动画,在文档加载时阻止默认值
- Skrollr 运行动画一次,然后停止
- 当这个动画准备好时再次运行动画
- 更好的方式来运行动画的有限循环