1

我想用重力创建一个简单的动画(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”过大的问题?

谢谢

4

2 回答 2

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);
}
于 2013-04-08T16:37:32.633 回答
1

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

(你可以尝试不使用 jQuery——直接的 javascript,但是 X 浏览器的东西会让你发疯!)

$(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
});

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

于 2013-04-08T16:24:43.370 回答