1
\$\begingroup\$

I tried different ways to make constant animations using JavaScript and HTML. The problem is that they are never perfect.

If I want to move a square exactly 5 pixels every 50 miliseconds I would use that code:

var leftPosition = 0;

function move() {
    leftPosition += 5;
    document.getElementById("square").style.left = leftPosition + "px";
}

window.onload = function() {
    setInterval(move, 50);
};

What I mean by not perfect is that the square will sometimes move slightly faster or slower during it's course. To notice that you have to really pay attention to the moving animation.

I already tried to using requestAnimationFrame but happened the same thing. Is there a way to improve it?

\$\endgroup\$

2 Answers 2

2
\$\begingroup\$

Realize that setInterval() is more of a target framerate than the actual framerate. As in, the browser will attempt to hit that framerate but may end up slower than that if is doing a lot of work. Thus you really just use setInterval() to set your game loop in motion and then use delta time for all movements. That's where you determine how much time has actually elapsed since the last frame and then multiply all movements by that delta time factor.

\$\endgroup\$
3
  • \$\begingroup\$ I already tried the delta time way. It didn't change anything from my eye perception. I still see the animation moving slightly faster or slower during it's course. I also tried using requestAnimationFrame instead of setInterval with no sucess. \$\endgroup\$
    – João
    Commented Jul 29, 2013 at 3:51
  • \$\begingroup\$ The real question isn't if it's possible to move from A to B in a specific time, but if it's possible to make it move at the same constant speed during it's trajectory. \$\endgroup\$
    – João
    Commented Jul 29, 2013 at 3:54
  • \$\begingroup\$ Delta time isn't about the total time of the movement, it's about how much time passed since last frame. If delta time didn't work for your needs, either you didn't do it right or your perception is extremely picky. \$\endgroup\$
    – jhocking
    Commented Aug 2, 2013 at 0:47
1
\$\begingroup\$

leftPosition += 5; will never give you smooth experience, I believe that's your main problem, you should do something like this:

float perFrameSpeed = positionDelta / targetFPS / animationFrames;

Where positionDelta is a delta between current position and position after animation, targetFPS - your loop fps (e.g requestAnamationFrame(function(){...}, 1000 / targetFPS)), animationFrames - how much frames should take performing animation.

And than, inside your loop, you will incr box position by this value until it reaches the desired position. That's your main problem i gas.

But you have one more - document.getElementById("square").style.left = leftPosition + "px"; In case of constant speed it's much better to cache actual element before doing animation, e.g.

var box = document.getElementById('boxId');
// ....
box.style.left = leftPosition + "px";

But, actually, if you are working with DOM elements and don't really care about old browsers, it's much better in your case just to use CSS3, I believe there are a lot of libraries that can generate and attach CSS3 animations at run time, but I strongly recommend to give a try to zepto.js. It's clean, lightweight, fast, and you can solve problems like this really easily, just by doing something like:

Zepto(function($) {
    $('#box').animate({
        left: '50px' // animate from current position to left: 50px 
    }, 500,/*speed in ms*/, 'ease-out'/*animation curve*/, function() {
        // animation done you can handle it here if you want to
    });
});

By doing so you will have VERY smooth looking animation (of course if browser has CSS3 support) even with really small animation deltas and it's also works, in most cases, perfectly on almost all mobile devices.

Of course there are a lot more inside this lib, you can check out the docs.

Hope this helps.

\$\endgroup\$
3
  • \$\begingroup\$ I tried using canvas and delta, the problem persists. \$\endgroup\$
    – João
    Commented Jul 29, 2013 at 10:11
  • \$\begingroup\$ If you are using setInterval problem would be there anyway, sometimes almost not visible, the reason is that you don't really consider function execution time, JS is single threaded so you get something like: setTimeout(showFrame, setIntervalTimer + showFrameFunctionExecutionTime); In short - you should consider execution time. \$\endgroup\$
    – user22320
    Commented Jul 29, 2013 at 10:52
  • \$\begingroup\$ btw - setInterval doesn't really work at all, as for me I simple almost never using it. \$\endgroup\$
    – user22320
    Commented Jul 29, 2013 at 10:59

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .