我正在审查一些游戏代码,我有一件我不太了解的内容。
var game = (function(){
// Start with our constructor
function Game(){
this.viewport = document.getElementById('viewport');
this.ctx = this.viewport.getContext('2d');
};
Game.prototype.updateAnimation = function(t){
// work out the delta time
this.dt = this.lastFrameTime ? ((t - this.lastFrameTime)/1000.0).fixed() : 0.016;
// store last frame time
this.lastFrameTime = t;
// run relevent updates here
// queue the next animation time.
this.animationId = window.requestAnimationFrame( this.updateAnimation.bind(this), this.viewport );
}
// return game class
return Game;
})();
然后
// call new game object
var clientGame = new game();
// call event loop
clientGame.updateAnimation(new Date().getTime());
请求window.requestAnimationFrame( this.updateAnimation.bind(this), this.viewport );
运行时。它如何知道参数t
的价值。它似乎每次更新,但我不明白为什么。有人可以解释一下发生什么事吗?感谢。
Number
原型链上附加了一个名为fixed()
的函数。这是为了清晰起见
Number.prototype.fixed = function(n) { n = n || 3; return parseFloat(this.toFixed(n)); };
答案 0 :(得分:2)
首先,代码可以写得更好,每次都不需要再次绑定函数,只需要执行一次(例如在对象初始化期间)
其次,函数requestAnimationFrame
只接受一个参数,因此对第二个参数没有意义,第一个参数是浏览器发送给回调的t
。
方法.bind
不会更改函数参数(可能除了arguments.callee
,但这是多余的)但只有函数的context
,因此第一个参数保持t
}(timestamp
)
更多信息https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame
修改
因此用户正在使用一些polyfill,它允许向requestAnimationFrame发送两个参数
答案 1 :(得分:1)
所以requestAnimationFrame
有一个参数,一个回调,它将时间戳作为参数。
bind函数返回原始函数但在不同的范围内。因此,requestAnimationFrame
会使用时间戳调用updateAnimation,这是您的时间来源。
现在要了解bind
调用背后的原因,您需要了解JavaScript中的范围。
当您定义一个函数并将其作为参数传递给另一个函数时,您实际上正在调用第二个函数中的第一个函数。这意味着如果你有一个类实例并且想要将一个实例方法作为回调传递给一个函数,你需要使用一个保留当前作用域的箭头函数,或者将该方法绑定到正确的作用域(你的类实例)。 / p>
我希望以下示例更好地展示我正在谈论的内容。
class OuterScope {
constructor() {
this.label = 'test';
}
print() {
console.log(this.label);
}
}
function innerScope(callback) {
callback();
}
var scope = new OuterScope();
innerScope(scope.print); // throws error because the scope the function is called in doesn't have a property called label
innerScope(scope.print.bind(scope)); // prints label
现在将其应用于您的requestAnimationFrame
问题:
class Game {
updateAnimation(t) {
// this.lastFrameTime would always be undefined when called without binding
this.dt = this.lastFrameTime ? ((t - this.lastFrameTime)/1000.0).fixed() : 0.016;
// store last frame time
this.lastFrameTime = t;
window.requestAnimationFrame(this.updateAnimation.bind(this)); // updateAnimation now always runs in the scope of the current Game instance
// window.requestAnimationFrame(this.updateAnimation); // updateAnimation runs in the scope of the window
}
}
window.requestAnimationFrame = function requestAnimationFrame(callback) {
callback(new Date().getTime()); // calls the callback with one argument
}