具有长时间步长的重力(使用javascript)

时间:2013-04-08 13:22:12

标签: javascript html5 canvas

我想创建一个带引力的简单动画(http://jsfiddle.net/2pcr9/4/在chrome和firefox中测试过)。我在使用画布的Javascript中这样做。使用(:46):

使用可变时间步长计算重力和速度
this.realDelta = (now - this.prevTime) / 1000;
this.realTime += this.realDelta;

每个球都有这个代码来计算速度和位置(:148):

this.vy += this.gravity * time.delta;
this.x += this.vx * time.delta;
this.y += this.vy * time.delta;

现在,当您查看窗口时,此原型可以正常工作。

但是如果你隐藏当前窗口(切换到浏览器的另一个标签页),window.requestAnimationFrame就会停止。如果等待5秒钟,然后打开窗口,window.requestAnimationFrame将恢复。问题是realDelta现在是5秒,并且速度太大了。

我可以添加一个检查,不允许realDelta大于秒(:46):

this.realDelta = (now - this.prevTime) / 1000;
if (this.realDelta > 1) {
    this.realDelta = 1;
}
this.realTime += this.realDelta;

但这并没有真正解决问题。

现在我不明白如何解决这个问题。我应该检查窗口是否隐藏并暂停计时器(并在窗口再次可见时恢复计时器)。或者我的速度计算有错误吗?其他html5游戏如何解决这个'dt'问题太大了?

由于

2 个答案:

答案 0 :(得分:2)

在您的绘图功能中,您可以通过多次运行您的功能来补偿错过的帧以赶上:

var TIME_INTERVAL = 1000/60;
var timeElapsed = 0;
requestAnimFrame(draw, TIME_INTERVAL);

function draw() { 
    timeElapsed += now - this.prevTime;
    this.prevTime = now;
    while(timeElapsed > TIME_INTERVAL)
    {
        timeElapsed -= TIME_INTERVAL;
        // Run Draw
    }

    requestAnimFrame(draw, TIME_INTERVAL);
}

当然,如果用户选项卡的时间太长,他们可能会重新进行大量计算。如果RequestAnimFrame不可用,您还可以考虑运行备份:

var TIME_INTERVAL = 1000/60;
var timeElapsed = 0;
var backup = setInterval(draw, TIME_INTERVAL*5);
requestAnimFrame(draw, TIME_INTERVAL);

function draw() {
    clearInterval(backup);

    timeElapsed += now - this.prevTime;
    this.prevTime = now;
    while(timeElapsed > TIME_INTERVAL)
    {
        timeElapsed -= TIME_INTERVAL;
        // Run Draw
    }

    backup = setInterval(draw, TIME_INTERVAL*5);
    requestAnimFrame(draw, TIME_INTERVAL);
}

答案 1 :(得分:1)

使用这些jQuery事件来开始/停止帧计算:

(你可以试试没有jQuery - 直接的javascript,但X-browser的东西会让你发疯!)

$(window).blur(function(e) {
    // User has changed tabs away from your window
    // So freeze your incrementing until the user returns 
});


$(window).focus(function(e) {
    // User has returned to your tab
    // So begin your incrementing again
});

唯一的问题是在某些浏览器中这些事件被多次触发,因此您可能还想设置一个开/关标志,以便您只对第一次触发做出反应。