开发者

How to speed up this moving algorithm? In Javascript

I have an Array of 16 billiard balls in JS and want to move each ball smoothly with its direction and speed.

For that I set up a timer, calling UpdateThis(开发者_StackOverflow社区) every 42ms (for 24 fps).

The problem is that UpdateThis() takes 53ms as firebug states.

Now UpdateThis iterates over every ball and calls UpdateBall(ball).

I assume that the problem lies there.

UpdateBall looks like this:

function UpdateBall(ball)
{
if(ball.direction.x != 0 && ball.direction.y != 0) {
    //ball moving!
    for(var i = 0; i < balls.length; i++) {
        //CheckCollision(ball, balls[i]); //even without this it takes 53 ms!
    }

    var ps = VAdd(ball.position, VMul(ball.direction, ball.speed)); //Multiply Direction with speed and add to position!
    if(ps.x < Bx || ps.y < By || ps.x > Bw || ps.y > Bh) { //Bounce off the wall!
        ball.direction = VMul(ball.direction, -1); //Invert direction
        ball.speed *= 1;
        ps = VAdd(ball.position, VMul(ball.direction, ball.speed)); //Calc new position!
    }
    ball.position = ps;
    ball.MoveTo(); //See explanation at the bottom.
    ball.speed *= GRK; //Gravity
    if(ball.speed < 0.05) {
        ball.speed = 0;
    }
  }
}

it seems that the most time is spent in ball.MoveTo() which looks like this:

function() 
{
     this.image.style.left = this.position.x + "px";
     this.image.style.top = this.position.y + "px"; 
}

-- UPDATE --

function UpdateThis() {
    for(var i = 0; i < balls.length; i++) {
         var cur = balls[i];
         UpdateBall(cur);
         balls[i] = cur;
    }
  }

and onload looks like

nx = setInterval(function() { UpdateThis(); }, 42);

Does somebody have any ideas on how to speed this up?

-- UPDATE 2 --

You can download the folder with the HTML file here (the password is password)


What about separating the position updates from the drawing? So have something like this (untested code):

function DrawBall(ball)
{
    ball.MoveTo(); //Take this line out of UpdateBall
}

-

function UpdateThis() {
    for(var i = 0; i < balls.length; i++) {
         var cur = balls[i];
         UpdateBall(cur);
         balls[i] = cur;
    }
}

-

function DrawThis() {
    for(var i = 0; i < balls.length; i++) {
         DrawBall(balls[i]);
    }
    setTimeout(function() { DrawThis(); }, 42);
}

-

nx = setInterval(function() { UpdateThis(); }, 42);
setTimeout(function() { DrawThis(); }, 42);

If indeed it's the moving of the position that's slow, this way the logic update still happens at 42ms, and the framerate is no faster than 42ms but it can skip frames. (I haven't actually tried this, so this is all theoretical and you may need to tweak some stuff)


Why moving may be (and most probably is) slow?

Move functionality could be slow, because it has more things to do than simple variable assignment. It has to actually render some element to some other place. You could test this if you run this on IE9. I anticipate it should run faster since it uses hardware video acceleration.

As for the other routine I hope others will dissect it. :)

Questions for you

  1. Can you please describe how do balls move? Sporadically? How do you call UpdateBall() for each ball? Do you queue those calls?

  2. Provide VMul and VAdd functionality

  3. Have you played with styling? Maybe relative positioning of balls' immediate parent may speed up rendering. And setting overflow:hidden on it as well. I don't know. Depends on how you've done it. Hence a JSFiddle would be very helpful.

A suggestion

Instead of using setInterval to call your function you should maybe just queue them and let them execute as fast as it gets. And just for the sake of it, provide a central setInterval with some watcher that they don't run too fast.

But I guess that it still utilizes your processor to 100% which isn't good anyway.

Very important note: Don't run you app while Firebug's enabled because it's a well known fact that Javascript executes much slower when Firebug is running.


That's tough, if MoveTo() is in fact your bottleneck, since there is not a whole lot going on there. About the only things I can think of, right off hand, are

1) Cache the style property of the image and position for faster lookups. Everytime you see a dot in the object chain it's requires stepping through the scope chain. Ideally you can cache this property at the time the parent of MoveTo() is constructed.

2) Are the 'px' strings required? It may result in an invalid CSS specification, but it may still work. I have a hard time believing 2 string concats would really change all that much though.

The main problem here is likely the fact that anytime you change the DOM, the browsers re-flows the entire page. Your only other option may be to refactor such that instead of changing the styles, you actually remove the previous contents, and replace it with the a document fragment describing the new state. This would result in only 2 re-flows for the entire step (1 for removal, 1 for addition), instead of 2 for each ball.

EDIT: Regarding #1 above, when I say cache, I don't mean just locally in the function call. But perhaps as a closure in the parent object. For example:

var Ball = function(img){
    var style = img.style;
    var posX;
    var posY;

    function MoveTo(){
        style.left = posX + "px";
        style.right = posY + "px"; 
    }
};
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜