如何加快这个移动算法?在Javascript中

时间:2011-06-06 19:41:10

标签: javascript game-physics


我在JS中有一个16个台球阵列,希望用它的方向和速度顺畅地移动每个球。
为此,我设置了一个计时器,每42毫秒调用UpdateThis()(24 fps) 问题是UpdateThis()需要53毫秒作为萤火虫状态。
现在UpdateThis遍历每一个球,然后拨打UpdateBall(ball) 我认为存在问题。
UpdateBall看起来像这样:

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;
    }
  }
}

似乎在ball.MoveTo()花费的时间最多,如下所示:

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


- 更新 -

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

和onload看起来像

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

有人对如何提高速度有任何想法吗?

- 更新2 -

您可以下载包含HTML文件here(密码为密码)

的文件夹

3 个答案:

答案 0 :(得分:2)

为什么移动可能(并且很可能)慢?

移动功能可能很慢,因为它比简单的变量赋值有更多的事情要做。它必须实际渲染一些元素到其他地方。如果你在IE9上运行它,你可以测试这个。我预计它应该运行得更快,因为它使用硬件视频加速。

至于其他常规,我希望其他人会解剖它。 :)

为您提出的问题

  1. 你能描述一下球是如何移动的吗?偶尔?你如何为每个球打UpdateBall()?你排队这些电话吗?

  2. 提供VMulVAdd功能

  3. 你玩过造型吗?也许球的直接父母的相对定位可以加速渲染。并在其上设置overflow:hidden。我不知道。取决于你是如何做到的。因此,JSFiddle会非常有帮助。

  4. 建议

    不是使用setInterval来调用你的函数,你应该将它们排队并让它们尽可能快地执行。只是为了它,提供一个中央setInterval和一些观察者,它们运行得不会太快。

    但我猜它仍然会将你的处理器用于100%,这无论如何都不好。

      

    非常重要的注意事项:启用Firebug时不要运行应用程序,因为众所周知,当Firebug运行时Javascript执行速度要慢得多。

答案 1 :(得分:2)

如何将位置更新与图纸分开?所以有类似的东西(未经测试的代码):

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);

如果确实是位置移动缓慢,这样逻辑更新仍然会在42ms发生,并且帧速率不会超过42ms,但它可以跳过帧。 (我实际上没有试过这个,所以这都是理论上的,你可能需要调整一些东西)

答案 2 :(得分:1)

这很难,如果MoveTo()实际上是你的瓶颈,因为那里没有很多东西。关于我能想到的唯一一件事,就是

1)缓存图像的样式属性和位置,以便更快地进行查找。每次在对象链中看到一个点时,都需要单步执行范围链。理想情况下,您可以在构造MoveTo()的父级时缓存此属性。

2)是否需要'px'字符串?它可能导致无效的CSS规范,但它仍然可以工作。我很难相信2弦串联会真的改变那么多。

这里的主要问题可能是,无论何时更改DOM,浏览器都会重新流动整个页面。您唯一的其他选择可能是重构,以便您实际上删除以前的内容,而不是更改样式,并将其替换为描述新状态的文档片段。这将导致整个步骤只有2个重新流动(1个用于移除,1个用于添加),而不是每个球2个。

编辑:关于上面的#1,当我说缓存时,我并不仅仅意味着在函数调用中本地。但也许作为父对象的闭包。例如:

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

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