Access to the variable 'this' in the function passed to setInterval / setTimeout

I am creating a simple game with a symbol that can jump, move right and move left.

I am having problems with a transition function that uses setInterval .

Here is the function:

  jumpUp: function (speed) { setInterval(function () { this.yPos += 10; this.playerElement.css("top", '-=' + 10); alert("dude, im not moving....so stop trying"); //for some reson, this line works and other dont. }, 100); } 

I must add that the code works without setInterval . I really don't know why it does not work when I add setInterval .

My questions:

  • What stops the execution of this code?
  • Is setInterval good way to make a character look like jumping and landing? Or should I use a different method?

EDIT 1:

fiddle

+4
source share
4 answers

The problem is using this . When you call the setInterval function, this will be a global object ( window in browsers). You need to save this value when you call setInterval . One way to do this is to store the this value in a variable, which will then be closed by an anonymous function (which is closure):

  jumpUp: function (speed) { var self = this; setInterval(function () { self.yPos += 10; self.playerElement.css("top", '-=' + 10); }, 100); } 

EDIT:

To answer the second question, the best approach to animating a sprite (for example, your character) is to maintain the speed of the character, and then have one game loop that will calculate the next position of the sprite based on this information. A very simple example:

 // Somewhere else in the code: function tick() { // move player by player.velocity.x and player.velocity.y // code to decelerate player gradually, stop player when they hit a wall/floor, etc... // A very simple example: if (player.velocity.y > 0) { player.velocity.y -= 1 } // call next tick() (setTimeout, or preferably requestAnimationFrame) } // In the player code: velocity: {x: 0, y: 0}, jumpUp: function () { this.velocity.y -= 10; }, moveRight: function () { this.velocity.x += 10; } 
+5
source

As darma and darmonmon have shown, you have a problem with that.

Try using the following code:

 jumpUp: function (speed) { var that = this; setInterval(function () { that.yPos += 10; that.playerElement.css("top", '-=' + 10); }, 100); } 

I added a variable to maintain a reference to everything that should be.

+1
source

In addition to your closure problem, this is likely to cause an intermittent jump.

Here's another pattern that watches the clock to find out how much time has passed between each function call ( setInterval not consistent):

 jumpUp: function (speed) // speed in pixels per second { var last = +new Date(); var c = this; var jumptick = function () { var interval = +new Date() - last; c.yPos += speed * interval; c.playerElement.css("top", c.yPos); if (/* condition for reaching maximum height */) speed = -speed; if (! /* condition for reaching ground */) setTimeout(jumptick); // could add an interval but this will lead to fastest frame rate }; jumptick(); } 
+1
source

Setinterval is not the best way to achieve this, because it will use a lot of resources. You also need to consider the frame rate when you move your character, otherwise it will quickly move around a fast computer / browser and slow down on a slow machine.

A good method uses the requestAnimationFrame method. You can find the javascript file in google that will make it compatible with crossbrowser.

Then, every time you call your function, you will need to check the time elapsed between the frame and move the sprites accordingly. This works more, but in this case your game will work the same on any machine.

+1
source

All Articles