我在JS中有一个由16个台球组成的数组,希望每个球都能以其方向和速度平稳移动
为此,我设置了一个计时器,每42ms调用UpdateThis()
(每秒24帧)
问题是UpdateThis()
以53ms作为萤火虫状态。
现在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;
}
}
加载看起来像
nx = setInterval(function() { UpdateThis(); }, 42);
有人对如何加快速度有什么想法吗?
--更新2-
您可以在此处下载带有HTML文件的文件夹(密码为密码)
将位置更新从图形中分离出来怎么样?所以有这样的东西(未经测试的代码):
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,但它可以跳过帧。(我实际上还没有尝试过,所以这都是理论上的,你可能需要调整一些东西)
为什么移动可能(而且很可能)很慢
移动功能可能很慢,因为它要做的事情比简单的变量分配多。它必须实际将某个元素渲染到其他位置。如果你在IE9上运行这个,你可以测试它。我预计它应该运行得更快,因为它使用硬件视频加速。
至于另一个程序,我希望其他人能仔细分析一下
您的问题
-
你能描述一下球是如何移动的吗?零星如何为每个球调用
UpdateBall()
?你把这些电话排队吗? -
提供
VMul
和VAdd
功能 -
你玩过造型吗?也许球的直接父对象的相对位置可以加快渲染速度。并在其上设置
overflow:hidden
。我不知道。这取决于你是如何做到的。因此,JSFiddle会很有帮助。
一个建议
与其使用setInterval
来调用函数,不如将它们排队,让它们以最快的速度执行。因此,为中央setInterval
提供一些观察程序,使其不会运行得太快。
但我想它仍然100%利用你的处理器,这无论如何都不好。
非常重要的注意事项:不要在启用Firebug时运行应用程序,因为众所周知,当Firebug运行时,Javascript执行速度要慢得多。
如果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";
}
};