1

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,

2
  • Single word answer CLOSURES. Commented Aug 14, 2016 at 17:34
  • Akshay Khandelwal wat ? Commented Aug 14, 2016 at 18:00

1 Answer 1

1

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
}
Sign up to request clarification or add additional context in comments.

8 Comments

Good answer. One note: your doStep function isn't recursive. In fact it would be a problem if it were, since a long series of steps would consume stack space for each call. The function has the appearance of recursion, but that's misleading. Because the nested calls to doStep are inside timer callbacks, they are executed after the original doStep call returns. So it's really a series of scheduled calls where each one schedules the next, not recursion or reentrancy.
Thanks. Ill look into this, very much appreciate the example mockup.
I'm not sure if your definition of "recursive" is too restrictive or not, but perhaps a better wording would be "Write a function which results in that function being called again."
@MichaelGeary I dropped the word "recursive" to be on the safe side.
Well, its working. I didnt know i can ust create a new function inside a function like that. Interesting. Much appreciate your effort. GL HF.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.