Reputation: 416
I have an array that it filled with objects that hold a attribute that is either called "move" or "turn" and specify how to animate a image on a canvas. Upon clicking a button, i want to loop over the array and animate the elements in the correct order, i.e. move the object, turn it, move it again.
This is the code:
var animation = false;
this.executePlan = function(){ // part of object
var self = this // part of object
for (var i = 0; i < this.moves.length; i++){
var move = this.moves[i];
if (move.type == "move"){
var path = new Path({x: self.x, y: self.y}, {x: move.x, y: move.y});
animation = setInterval(function(){
console.log("move");
ctx.clearRect(0, 0, res, res);
self.draw();
self.x += path.vector.x;
self.y += path.vector.y;
path.vector.s--;
if (path.vector.s <= 0){
clearInterval(animation);
}
},
10);
}
else if (move.type == "turn"){
animation = setInterval(function(){
console.log("turn");
if (move.a > 0){
self.facing++;
move.a--;
}
else {
self.facing--;
move.a++;
}
ctx.clearRect(0, 0, res, res);
ctx.save();
ctx.translate(self.x, self.y);
ctx.rotate(self.facing*Math.PI/180);
ctx.drawImage(self.img, -self.size/2, -self.size/2, self.size, self.size);
ctx.restore();
if (move.a == 0){
clearInterval(animation);
}
},
30);
}
}
}
For the purpose of this example, i have to animate a straight movement path, than a turn, than a straight movement path and im under the impression that the code should hold, i.e. first array element triggers if clause, second triggers elseif clause, first triggers if clause.
However, what happens is that the various intervall do overlap, which leads to my image moving out of the canvas, while rotating all the time - instead of moving, then rotating and finally moving straight again
How can i fix the code and what exactly is the error ?
thanks,
Upvotes: 1
Views: 229
Reputation: 60143
The issue is that you're starting both/all animations at the same time.
You need some mechanism to start subsequent animations only after the earlier animations are done. My suggestion would be to change your for loop into a function, where each animation is responsible for calling the function again (with an incremented i
) when its animation is complete.
EDIT
An example of the approach I suggested (completely untested):
var animation = false;
this.executePlan = function() {
var self = this;
function doStep(i) {
var move = this.moves[i];
if (move.type == "move") {
var path = new Path({ x: self.x, y: self.y }, { x: move.x, y: move.y });
animation = setInterval(function() {
console.log("move");
ctx.clearRect(0, 0, res, res);
self.draw();
self.x += path.vector.x;
self.y += path.vector.y;
path.vector.s--;
if (path.vector.s <= 0) {
clearInterval(animation);
if (i + 1 < this.moves.length) {
doStep(i + 1); // if there's more, do the next step
}
}
}, 10);
}
else if (move.type == "turn") {
animation = setInterval(function() {
console.log("turn");
if (move.a > 0){
self.facing++;
move.a--;
}
else {
self.facing--;
move.a++;
}
ctx.clearRect(0, 0, res, res);
ctx.save();
ctx.translate(self.x, self.y);
ctx.rotate(self.facing*Math.PI/180);
ctx.drawImage(self.img, -self.size/2, -self.size/2, self.size, self.size);
ctx.restore();
if (move.a == 0) {
clearInterval(animation);
if (i + 1 < this.moves.length) {
doStep(i + 1); // if there's more, do the next step
}
}
}, 30);
}
}
doStep(0); // start the first animation
}
Upvotes: 1