【问题标题】:Laggy movement with canvas game画布游戏的滞后运动
【发布时间】:2012-09-07 14:00:30
【问题描述】:

大家不完全确定我做错了什么。我玩过一些 HTML5 游戏,但它们似乎遇到了不同的问题。绘图滞后于运动,看起来很奇怪。这似乎不是这里的情况。

在我的游戏中,绘图看起来不错,但随着他的移动,它就像每一秒一样滞后。(移动是箭头键)。如果我将他设置为自动移动,它也不需要箭头键,所以我认为这不是关键检测问题。

垃圾收集器几乎每秒都在运行。不过我不认为我会喷出那么多物体。

我使用的是 Chrome 21 (MacOSX) 和 Firefox 14。

http://tempdrew.dreamhosters.com/spine/

这里是相关代码的 js fiddle。

http://jsfiddle.net/ju3ag/

这在 chrome canary 上很好。我不知道这是否只是因为金丝雀中的 javascript 比标准 chrome 快得多。这在最新的 Firefox 中很糟糕。我不确定我做错了什么。我正在根据时间更新运动。如果我把它拿出来,虽然它仍然很糟糕。

我只是想知道是否有任何东西会让任何人脱颖而出。感谢您的帮助。

    sg = Class.extend({


});

sg.entities = [];
sg.buttonStates = [];

sg.createEntity = function (entity) {    
    this.entities.push(entity);    
};


window.requestAnimFrame = (function () {
    return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
    function (callback, element) {
        window.setTimeout(callback, 1000 / 60);
    };

})();


(function defineUtil() {

    sg.util = {};

    sg.util.getRandomInt = function getRandomInt(min, max) {
        return Math.floor(Math.random() * (max - min + 1)) + min;
    };

    sg.util.getRandomNumber = function getRandomNumber(min, max) {
        return Math.random() * (max - min) + min;
    };

})();


/*************************/
(function createEntity() {

    var Entity = Class.extend({

        init: function (x, y) {

            this.name = 'Entity';
            this.health = 100;

            this.pos = {
                x: x,
                y: y
            };

            this.vel = {
                x: 0,
                y: 0
            };

            this.accel = {
                x: 0,
                y: 0
            }

            console.log(this.name + ' created ' + x + ' ' + y);
        },

        update: function (elapsed) {

        },

        draw: function (ctx) {

        }

    });

    sg.Entity = Entity;

})();





/************************/

// -- player.js
(function createPlayer() {

    var Player = sg.Entity.extend({

        x: 0,
        y: 0,
        moveLeft: false,
        moveRight: false,
        speed : 5,

        init: function (x, y) {

            this.x = x;
            this.y = y;
            this.name = 'Player';
        },

        draw: function (ctx) {

            var x = this.x,
                y = this.y;

            ctx.beginPath();
            ctx.rect(x, y, 40, 50);
            ctx.fillStyle = 'white';
            ctx.fill();
            ctx.lineWidth = .5;
            ctx.strokeStyle = 'rgba(0,0,0,.3)';
            ctx.stroke();
            ctx.fillStyle = 'rgba(0,0,0,.5)';
            ctx.fillRect(x + 25, y + 15, 5, 5);
        },

        update: function (elapsed) {
            var distance = (60 / 1000) * elapsed;
            if (this.moveLeft) {
                this.x += this.speed * distance;
            } else if (this.moveRight) {
                this.x -= this.speed * distance;
            }
        },

        keyDown: function (e) {

            if (e.keyCode === 39) {
                this.moveLeft = true;
            } else if (e.keyCode === 37) {
                this.moveRight = true;
            } else {
                this.moveLeft = false;
                this.moveRight = false;
            }
        },

        keyUp: function (e) {

            if (e.keyCode === 39) {
                this.moveLeft = false;
            } else if (e.keyCode === 37) {
                this.moveRight = false;
            }
        }

    });


    sg.Player = Player;

})();




/**********************************/


(function createGame() {

    var Game = Class.extend({

        canvas: null,
        context: null,
        width: null,
        height: null,

        init: function (width, height) {

            this.canvas = document.getElementById('canvas');
            this.context = this.canvas.getContext('2d');

            this.width = width || 800;
            this.height = height || 600;

            this.canvas.width = this.width;
            this.canvas.height = this.height;
        },

        clear: function () {
            this.context.clearRect(0, 0, this.width, this.height);
        },

        draw: function () {

            this.clear();       

            for (var i = 0; i < sg.entities.length; i++) {
                sg.entities[i].draw(this.context);
            }
        },

        update: function (elapsed) {

            for (var i = 0; i < sg.entities.length; i++) {
                sg.entities[i].update(elapsed);
            }
        },

        keyDown: function (e) {

            for (var i = 0; i < sg.entities.length; i++) {

                if (typeof sg.entities[i].keyDown === 'function') {
                    sg.entities[i].keyDown(e);
                }
            }
        },


        keyUp: function (e) {

            for (var i = 0; i < sg.entities.length; i++) {
                if (typeof sg.entities[i].keyUp === 'function') {
                    sg.entities[i].keyUp(e);
                }
            }
        }

    });

    sg.Game = Game;

    var game = sg.currentGame = new sg.Game(800, 600);


    var player = new sg.Player(200, 459);

    sg.createEntity(player);

    function update(elapsed) {

        game.update(elapsed);
    }

    var lastUpdate = Date.now();

    function draw() {

        var now = Date.now();
        var elapsed = (now - lastUpdate);
        lastUpdate = now;

        game.draw();
        update(elapsed);
        requestAnimFrame(draw);
    }

    window.addEventListener('keydown', sg.currentGame.keyDown, false);
    window.addEventListener('keyup', sg.currentGame.keyUp, false);

    draw();

})();

【问题讨论】:

  • 您是否尝试过在 Chrome 调试器工具中分析内存?我猜一个失​​控的内存泄漏可能会比你需要的更频繁地触发 GC。
  • 补充一点,它在最新的 Chrome 和 Firefox (Windows 7) 上对我来说运行得非常好
  • 几天前我做了一个 CPU 配置文件,但没有什么突出的。内存配置文件也不突出。这是我在任何其他画布游戏中看到的典型情况。内存增加,然后 GC 命中。从我所见,GC 仅每 30 秒左右命中一次。至少 GC 命中率很高。我只是想知道您是否因为 Windows 上的 GPU 加速画布而没有注意到。我认为当前的 Chrome 没有适用于 MacOSX 的功能。也许金丝雀会。
  • 是的,我分析了第一个链接并没有严重影响内存......令人困惑!但正如我所说,对我来说效果很好。您正在做所有正确的事情 - 在事件处理程序中处理尽可能少,使用 RequestAnimationFrame 安排动画等。
  • 只是没有意义。我可以毫无问题地玩画布愤怒的小鸟。这只是简单的动作,太可怕了。

标签: javascript html canvas


【解决方案1】:

keydown/keyup 事件在一次按下和另一次按下之间等待一点时间。

这是我解决问题的方法(不确定这是否正是您的问题);添加一个 setInterval,每 20 毫秒检查一次是否有按键按下(对角线移动不止一个)。

    var keys = {};
    $(document).bind('keyup', function(e){
        delete keys[e.which];
    });
    $(document).bind('keydown', function(e){
        keys[e.which] = true;
    });

    setInterval(keyEvent, 20);

    function keyEvent(){
        for(var idKeyPressed in keys){
            switch(idKeyPressed){
                case "87": // "W" key; Move to the top
                    // Do something
                    break;
            }
        }
    }

希望有帮助:)

【讨论】:

  • 关于关键事件延迟的有趣理论......但我看不出这将如何解决它?
  • 是的。感谢您的帮助,但没有按键的移动也会出现此问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-01-29
  • 1970-01-01
  • 2013-07-02
  • 2013-03-12
  • 1970-01-01
  • 1970-01-01
  • 2017-09-19
相关资源
最近更新 更多