我想在每次点击 requestFrameAnimation 时开始一个新的动画
I want to start a new animation every time I click with requestFrameAnimation
我有多个问题。
每次我点击时动画会变快。 已解决 @Jorge Fuentes González
每次我点击
最后一个动画停止移动 已解决@Kaiido
我已经改变了我能想到的一切,但仍然是同样的问题。任何帮助,将不胜感激。谢谢!
function drawFrame(frameX, frameY, canvasX, canvasY) {
ctx.drawImage(img,
frameX * width, frameY * height,
width, height,
x_click, y_click,
scaledWidth, scaledHeight);
}
// Number of frames in animation
var cycleLoop = [3, 2, 1, 0, 7, 6, 5];
// Position of sprite in sheet
var currentLoopIndex = 0;
var frameCount = 0;
function step() {
frameCount++;
if (frameCount < 30) {
window.requestAnimationFrame(step);
return;
}
frameCount = 0;
// ctx.clearRect(0, 0, canvas.width, canvas.height);
drawFrame(cycleLoop[currentLoopIndex++], 0, 0, 0);
// Starts animation over
if (currentLoopIndex >= cycleLoop.length) {
// If you want to loop back in oposite direction after full animation
cycleLoop.reverse();
// Reseting position of which sprite to use
currentLoopIndex = 0;
}
window.requestAnimationFrame(step);
}
canvas.addEventListener("mousedown", getPosition, false);
function getPosition(event) {
x_click = event.x;
y_click = event.y;
x_click -= canvas.offsetLeft * 10;
y_click -= canvas.offsetTop * 10;
step();
}
==============================
JS Fiddle:
https://jsfiddle.net/HYUTS/q4fazt6L/9/
=======================================
当您再次单击时,window.requestAnimationFrame 仍然是 运行ning,并且当您单击时,您会为动画添加每帧的另一个刻度,使速度加倍,因为每次调用 step() 两次现在画框。再次点击时应该取消之前的动画帧,使用 window.cancelAnimationFrame()
https://developer.mozilla.org/en-US/docs/Web/API/Window/cancelAnimationFrame
像这样:
...
var animationID;
//in step() save the id in every call
function step() {
...
animationID = window.requestAnimationFrame(step);
...
}
//In getPosition cancel the current animation
function.getPosition(event) {
...
window.cancelAnimationFrame(animationId);
...
}
如果你想要多个动画运行ning,为每个动画创建一个对象并使函数step()成为它们的属性,然后在运行 window.requestAnimationFrame(this.step)
里面步()。您还必须保存动画所需的每个变量,例如 currentLoopIndex
作为对象的一部分。
每次点击,都会调用step();
,会调用window.requestAnimationFrame(step);
,会调用step()
下一个动画帧。我没有看到任何停止点,所以循环将永远被调用。
所以,当你第一次调用step()
时,step()
会一直调用下去,如果你再次点击,又会调用step()
"line"第二次调用将再次调用 window.requestAnimationFrame(step);
,所以现在您将有两个 "lines" 调用 step()
。这就是动画速度更快的原因,因为在每个动画帧上 step()
将被调用两次,使计算加倍。
你要做的是检查动画是否已经 运行ning(带有标志)并且不要再次 运行 ,或者在开始之前 window.cancelAnimationFrame(ID)
step()
再次循环。请注意,在每次单击时,您必须重新启动控制动画的变量,例如 frameCount
和 currentLoopIndex
function drawFrame(frameX, frameY, canvasX, canvasY) {
ctx.drawImage(img,
frameX * width, frameY * height,
width, height,
x_click, y_click,
scaledWidth, scaledHeight);
}
// Number of frames in animation
var cycleLoop = [3, 2, 1, 0, 7, 6, 5];
// Position of sprite in sheet
var currentLoopIndex = 0;
var frameCount = 0;
var animationid = null;
function step() {
frameCount++;
if (frameCount < 30) {
animationid = window.requestAnimationFrame(step);
return;
}
frameCount = 0;
// ctx.clearRect(0, 0, canvas.width, canvas.height);
drawFrame(cycleLoop[currentLoopIndex++], 0, 0, 0);
// Starts animation over
if (currentLoopIndex >= cycleLoop.length) {
// If you want to loop back in oposite direction after full animation
cycleLoop.reverse();
// Reseting position of which sprite to use
currentLoopIndex = 0;
}
animationid = window.requestAnimationFrame(step);
}
canvas.addEventListener("mousedown", getPosition, false);
function getPosition(event) {
x_click = event.x;
y_click = event.y;
x_click -= canvas.offsetLeft * 10;
y_click -= canvas.offsetTop * 10;
frameCount = currentLoopIndex = 0;
window.cancelAnimationFrame(animationid);
step();
}
根据您的情况,第一步是为每个 animatables 创建不同的对象,这样它们就可以独立绘制和更新。
之后,您必须将逻辑分成几个部分。
一个基本设置是有一个在后台不断运行的主循环,它将调用所有更高级别的对象更新函数,然后是所有绘图函数。
正是在这些更高级别的方法中,您将检查是否应该实际丢弃它们。主循环不必处理它。
在下面的示例中,我为您的 animatable 对象创建了一个 class。这些对象现在将拥有自己的状态,并且能够根据自己的意愿独立于其他对象进行更新。
使用此设置,在场景中添加一个新对象只是将其推入数组的问题。
// Our Animatable class (ES5 style...)
// Each object as its own frameCount and its own loopIndex
function Animatable(x, y) {
this.x = x;
this.y = y;
this.frameCount = 0;
this.loopIndex = 0;
this.cycleLoop = [3, 2, 1, 0, 7, 6, 5];
}
Animatable.prototype = {
update: function() {
this.frameCount++;
if (this.frameCount < 30) {
return;
}
this.frameCount = 0;
this.loopIndex++
if (this.loopIndex >= this.cycleLoop.length) {
// If you want to loop back in oposite direction after full animation
this.cycleLoop.reverse();
// Reseting position of which sprite to use
this.loopIndex = 0;
}
},
draw: function() {
// check the image is loaded
if (!img.naturalWidth) return;
var frameX = this.cycleLoop[this.loopIndex];
ctx.drawImage(img,
frameX * width, 0,
width, height,
this.x - scaledWidth/2, this.y - scaledHeight/2,
scaledWidth, scaledHeight);
}
};
// the main anim loop, independent
function startAnimLoop() {
animloop();
function animloop() {
requestAnimationFrame(animloop);
// updates
animatables.forEach(update);
// drawings
ctx.clearRect(0,0,canvas.width, canvas.height);
animatables.forEach(draw);
}
function update(animatable) {
animatable.update();
}
function draw(animatable) {
animatable.draw();
}
}
// one image for all
var img = new Image();
img.src = 'https://imgur.com/u2hjhwq.png';
img.onload = startAnimLoop;
// here we will hold all our objects
var animatables = [new Animatable(50, 50)]; // start with a single one
var canvas = document.querySelector('canvas');
var ctx = canvas.getContext('2d');
// some constant from OP's fiddle
var scale = 1.5;
var width = 100; // Bigger numbers push left <-, smaller right ->
var height = 100;
var scaledWidth = scale * width;
var scaledHeight = scale * height;
canvas.onclick = function(evt) {
var rect = canvas.getBoundingClientRect();
var x = evt.clientX - rect.left;
var y = evt.clientY - rect.top;
// we simply create a new object ;-)
animatables.push(new Animatable(x, y));
};
canvas{border:1px solid}
<canvas id="canvas" width="500" height="500"></canvas>
我有多个问题。
每次我点击时动画会变快。已解决 @Jorge Fuentes González每次我点击 最后一个动画停止移动已解决@Kaiido
我已经改变了我能想到的一切,但仍然是同样的问题。任何帮助,将不胜感激。谢谢!
function drawFrame(frameX, frameY, canvasX, canvasY) {
ctx.drawImage(img,
frameX * width, frameY * height,
width, height,
x_click, y_click,
scaledWidth, scaledHeight);
}
// Number of frames in animation
var cycleLoop = [3, 2, 1, 0, 7, 6, 5];
// Position of sprite in sheet
var currentLoopIndex = 0;
var frameCount = 0;
function step() {
frameCount++;
if (frameCount < 30) {
window.requestAnimationFrame(step);
return;
}
frameCount = 0;
// ctx.clearRect(0, 0, canvas.width, canvas.height);
drawFrame(cycleLoop[currentLoopIndex++], 0, 0, 0);
// Starts animation over
if (currentLoopIndex >= cycleLoop.length) {
// If you want to loop back in oposite direction after full animation
cycleLoop.reverse();
// Reseting position of which sprite to use
currentLoopIndex = 0;
}
window.requestAnimationFrame(step);
}
canvas.addEventListener("mousedown", getPosition, false);
function getPosition(event) {
x_click = event.x;
y_click = event.y;
x_click -= canvas.offsetLeft * 10;
y_click -= canvas.offsetTop * 10;
step();
}
============================== JS Fiddle:
https://jsfiddle.net/HYUTS/q4fazt6L/9/
=======================================
window.requestAnimationFrame 仍然是 运行ning,并且当您单击时,您会为动画添加每帧的另一个刻度,使速度加倍,因为每次调用 step() 两次现在画框。再次点击时应该取消之前的动画帧,使用 window.cancelAnimationFrame()
https://developer.mozilla.org/en-US/docs/Web/API/Window/cancelAnimationFrame
像这样:
...
var animationID;
//in step() save the id in every call
function step() {
...
animationID = window.requestAnimationFrame(step);
...
}
//In getPosition cancel the current animation
function.getPosition(event) {
...
window.cancelAnimationFrame(animationId);
...
}
如果你想要多个动画运行ning,为每个动画创建一个对象并使函数step()成为它们的属性,然后在运行 window.requestAnimationFrame(this.step)
里面步()。您还必须保存动画所需的每个变量,例如 currentLoopIndex
作为对象的一部分。
每次点击,都会调用step();
,会调用window.requestAnimationFrame(step);
,会调用step()
下一个动画帧。我没有看到任何停止点,所以循环将永远被调用。
所以,当你第一次调用step()
时,step()
会一直调用下去,如果你再次点击,又会调用step()
"line"第二次调用将再次调用 window.requestAnimationFrame(step);
,所以现在您将有两个 "lines" 调用 step()
。这就是动画速度更快的原因,因为在每个动画帧上 step()
将被调用两次,使计算加倍。
你要做的是检查动画是否已经 运行ning(带有标志)并且不要再次 运行 ,或者在开始之前 window.cancelAnimationFrame(ID)
step()
再次循环。请注意,在每次单击时,您必须重新启动控制动画的变量,例如 frameCount
和 currentLoopIndex
function drawFrame(frameX, frameY, canvasX, canvasY) {
ctx.drawImage(img,
frameX * width, frameY * height,
width, height,
x_click, y_click,
scaledWidth, scaledHeight);
}
// Number of frames in animation
var cycleLoop = [3, 2, 1, 0, 7, 6, 5];
// Position of sprite in sheet
var currentLoopIndex = 0;
var frameCount = 0;
var animationid = null;
function step() {
frameCount++;
if (frameCount < 30) {
animationid = window.requestAnimationFrame(step);
return;
}
frameCount = 0;
// ctx.clearRect(0, 0, canvas.width, canvas.height);
drawFrame(cycleLoop[currentLoopIndex++], 0, 0, 0);
// Starts animation over
if (currentLoopIndex >= cycleLoop.length) {
// If you want to loop back in oposite direction after full animation
cycleLoop.reverse();
// Reseting position of which sprite to use
currentLoopIndex = 0;
}
animationid = window.requestAnimationFrame(step);
}
canvas.addEventListener("mousedown", getPosition, false);
function getPosition(event) {
x_click = event.x;
y_click = event.y;
x_click -= canvas.offsetLeft * 10;
y_click -= canvas.offsetTop * 10;
frameCount = currentLoopIndex = 0;
window.cancelAnimationFrame(animationid);
step();
}
根据您的情况,第一步是为每个 animatables 创建不同的对象,这样它们就可以独立绘制和更新。
之后,您必须将逻辑分成几个部分。
一个基本设置是有一个在后台不断运行的主循环,它将调用所有更高级别的对象更新函数,然后是所有绘图函数。
正是在这些更高级别的方法中,您将检查是否应该实际丢弃它们。主循环不必处理它。
在下面的示例中,我为您的 animatable 对象创建了一个 class。这些对象现在将拥有自己的状态,并且能够根据自己的意愿独立于其他对象进行更新。
使用此设置,在场景中添加一个新对象只是将其推入数组的问题。
// Our Animatable class (ES5 style...)
// Each object as its own frameCount and its own loopIndex
function Animatable(x, y) {
this.x = x;
this.y = y;
this.frameCount = 0;
this.loopIndex = 0;
this.cycleLoop = [3, 2, 1, 0, 7, 6, 5];
}
Animatable.prototype = {
update: function() {
this.frameCount++;
if (this.frameCount < 30) {
return;
}
this.frameCount = 0;
this.loopIndex++
if (this.loopIndex >= this.cycleLoop.length) {
// If you want to loop back in oposite direction after full animation
this.cycleLoop.reverse();
// Reseting position of which sprite to use
this.loopIndex = 0;
}
},
draw: function() {
// check the image is loaded
if (!img.naturalWidth) return;
var frameX = this.cycleLoop[this.loopIndex];
ctx.drawImage(img,
frameX * width, 0,
width, height,
this.x - scaledWidth/2, this.y - scaledHeight/2,
scaledWidth, scaledHeight);
}
};
// the main anim loop, independent
function startAnimLoop() {
animloop();
function animloop() {
requestAnimationFrame(animloop);
// updates
animatables.forEach(update);
// drawings
ctx.clearRect(0,0,canvas.width, canvas.height);
animatables.forEach(draw);
}
function update(animatable) {
animatable.update();
}
function draw(animatable) {
animatable.draw();
}
}
// one image for all
var img = new Image();
img.src = 'https://imgur.com/u2hjhwq.png';
img.onload = startAnimLoop;
// here we will hold all our objects
var animatables = [new Animatable(50, 50)]; // start with a single one
var canvas = document.querySelector('canvas');
var ctx = canvas.getContext('2d');
// some constant from OP's fiddle
var scale = 1.5;
var width = 100; // Bigger numbers push left <-, smaller right ->
var height = 100;
var scaledWidth = scale * width;
var scaledHeight = scale * height;
canvas.onclick = function(evt) {
var rect = canvas.getBoundingClientRect();
var x = evt.clientX - rect.left;
var y = evt.clientY - rect.top;
// we simply create a new object ;-)
animatables.push(new Animatable(x, y));
};
canvas{border:1px solid}
<canvas id="canvas" width="500" height="500"></canvas>