0

我正在尝试创建一个简单的游戏循环并尝试在 JS 中使用 OOP 范例。这是我的代码:

HTML

<body onload="Game.OnLoad('gameField')" onkeydown="Game.KeyDown(event)">
    <p id="info">1</p>
    <p id="info2">2</p>
    <canvas id="gameField" 
            width="896px" 
            height="717px" 
            class="game-field" 
            style="border: 4px solid aqua"
            onclick="Game.MouseClick(event)"></canvas>
</body>

JavaScript

// class Timer
// version: 1
// only tick() functionality available
// right now
function Timer() {
    var date = new Date();

    var prevTick = 0;
    var currTick = 0;
    // update timer with tick
    this.tick = function() {
        prevTick = currTick;
        currTick = date.getTime();
    }
    // get time between two ticks
    this.getLastTickInterval = function() {
        return currTick - prevTick;
    }
}

// global object Game
// which handles game loop
// and provide interfaces for     
var Game = new function() {
    // variables:
    this.canvas = 0;
    var gameLoopId = 0;
    this.timer = new Timer();
    // events:
    this.KeyDown = function(e) {}

    // game loop:    
    this.Run = function() {
        this.timer.tick();
        this.Update(this.timer.getLastTickInterval());
        this.Draw();
    }
    this.Update = function(dt) {
        document.getElementById("info").innerHTML = dt;
    }
    this.Draw = function() {}
    this.StopGameLoop = function() {
        clearInterval(gameLoopId);
    }
    this.OnLoad = function(canvasName) {
        this.canvas = document.getElementById(canvasName);
        this.timer.tick();

        // start game loop
        setInterval(this.Run, 1000);
    }
}​

小提琴

我正在尝试使 Game 类全球化。其他类必须使用new.

类 Game 和 Timer 放置在名为 Game.js 和 Timer.js 的不同文件中。当我在 Chrome 中运行此代码时,我在 DevTools 中遇到错误:行"Uncaught TypeError: Cannot call method 'tick' of undefined"中的Game.Run函数this.timer.tick();

所以我想知道,我的代码有什么问题?谢谢您的回复。

4

2 回答 2

1

你的问题在于上下文。当您调用滴答声时this,是窗口,而不是游戏。例如,您可以通过设置:

var self = this;        
this.Run = function() {
    self.timer.tick();
    self.Update(self.timer.getLastTickInterval());
    self.Draw();
}
于 2012-10-23T13:18:19.403 回答
0

您的代码中需要考虑的几件事:

关于您的问题,setInterval 或 setTimeout 之类的方法会使上下文松散。最简单的解决方案是将上下文绑定到回调:

setInterval(this.Run.bind(this), 1000);

其次,避免在对象函数中添加私有方法。在这种情况下,每个 Game 实例都会有自己的一组函数(内存泄漏)。更喜欢使用原型:

function Game () {
    this.canvas = null;
}
Game.prototype = {
    init: function() {}
    render: function () {}
};

最后,我看到你每秒钟重画一次,这没关系。但是如果你想要 60fps,你可以使用requestAnimationFrame来绘制定向循环。

ps:只是为了非常挑剔,函数的名称应该是camelCase,所以以小写开头。

于 2016-11-15T09:13:05.633 回答