当前位置:  开发笔记 > 编程语言 > 正文

在Javascript中简单的游戏循环的最佳方式?

如何解决《在Javascript中简单的游戏循环的最佳方式?》经验,为你挑选了3个好方法。

有一种简单的方法可以在JavaScript中制作游戏循环吗?就像是...

onTimerTick() {
  // update game state
}

1-14x0r.. 32

根据您的应用程序,使用JavaScript实现此目的的方法有很多种.setInterval()或甚至是while()语句都可以解决这个问题.这不适用于游戏循环.JavaScript由浏览器解释,因此容易中断.中断将使你的游戏回放感到紧张.

CSS3的webkitRequestAnimationFrame属性旨在通过管理渲染循环本身来纠正这个问题.然而,这仍然不是最有效的方法,如果你有很多对象被更新,它将容易出现抖动.

这是一个很好的入门网站:

http://nokarma.org/2011/02/02/javascript-game-development-the-game-loop/index.html

这个网站有一些关于制作游戏循环的基础知识的很好的信息.它无论如何都不会触及任何类型的面向对象设计.实现精确计时的最准确方法是使用日期函数.

while ((new Date).getTime() > nextGameTick && loops < maxFrameSkip) {
  Game.update();
  nextGameTick += skipTicks;
  loops++;
}

这没有考虑setTimeout在高频下如何漂移.这也会导致事情变得不同步并变得紧张.JavaScript每秒会漂移+/- 18ms.

var start, tick = 0;
var f = function() {
    if (!start) start = new Date().getTime();
    var now = new Date().getTime();
    if (now < start + tick*1000) {
        setTimeout(f, 0);
    } else {
        tick++;
        var diff = now - start;
        var drift = diff % 1000;
        $('
  • ').text(drift + "ms").appendTo('#results'); setTimeout(f, 990); } }; setTimeout(f, 990);
  • 现在让我们把所有这些都放到一个有效的例子中.我们想将我们的游戏循环注入到WebKit的托管渲染循环中.这将有助于平滑渲染的图形.我们还想分割绘制和更新功能.这将在计算何时应绘制下一帧之前更新渲染场景中的对象.如果更新需要很长时间,游戏循环也应该跳过绘制框架.

    的index.html

    
        
             
        
        
        
            
        
    
    

    Game.js

    var Game = {};
    
    Game.fps = 60;
    Game.maxFrameSkip = 10;
    Game.skipTicks = 1000 / Game.fps;
    
    Game.initialize = function() {
        this.entities = [];
        this.viewport = document.body;
    
        this.input = new Input();
    
        this.debug = new Debug();
        this.debug.initialize(this.viewport);
    
        this.screen = new Screen();
        this.screen.initialize(this.viewport);
        this.screen.setWorld(new World());
    };
    
    Game.update = function(tick) {
        Game.tick = tick;
        this.input.update();
        this.debug.update();
        this.screen.update();
    };
    
    Game.draw = function() {
        this.debug.draw();
        this.screen.clear();
        this.screen.draw();
    };
    
    Game.pause = function() {
        this.paused = (this.paused) ? false : true;
    };
    
    /*
     * Runs the actual loop inside browser
     */
    Game.run = (function() {
        var loops = 0;
        var nextGameTick = (new Date).getTime();
        var startTime = (new Date).getTime();
        return function() {
            loops = 0;
            while (!Game.paused && (new Date).getTime() > nextGameTick && loops < Game.maxFrameSkip) {
                Game.update(nextGameTick - startTime);
                nextGameTick += Game.skipTicks;
                loops++;
            }
            Game.draw();
        };
    })();
    
    (function() {
        var onEachFrame;
        if (window.requestAnimationFrame) {
           onEachFrame = function(cb) {
              var _cb = function() {
                    cb();
                 requestAnimationFrame(_cb);
              };
              _cb();
           };
        } else if (window.webkitRequestAnimationFrame) {
           onEachFrame = function(cb) {
              var _cb = function() {
                 cb();
                 webkitRequestAnimationFrame(_cb);
              };
              _cb();
           };
        } else if (window.mozRequestAnimationFrame) {
            onEachFrame = function(cb) {
                var _cb = function() {
                    cb();
                    mozRequestAnimationFrame(_cb);
                };
                _cb();
            };
        } else {
            onEachFrame = function(cb) {
                setInterval(cb, Game.skipTicks);
            };
        }
    
        window.onEachFrame = onEachFrame;
    })();
    

    更多信息

    您可以在此处找到完整的工作示例和所有代码.我已将此答案转换为可下载的javascript框架,您可以从中构建游戏.

    https://code.google.com/p/twod-js/



    1> 1-14x0r..:

    根据您的应用程序,使用JavaScript实现此目的的方法有很多种.setInterval()或甚至是while()语句都可以解决这个问题.这不适用于游戏循环.JavaScript由浏览器解释,因此容易中断.中断将使你的游戏回放感到紧张.

    CSS3的webkitRequestAnimationFrame属性旨在通过管理渲染循环本身来纠正这个问题.然而,这仍然不是最有效的方法,如果你有很多对象被更新,它将容易出现抖动.

    这是一个很好的入门网站:

    http://nokarma.org/2011/02/02/javascript-game-development-the-game-loop/index.html

    这个网站有一些关于制作游戏循环的基础知识的很好的信息.它无论如何都不会触及任何类型的面向对象设计.实现精确计时的最准确方法是使用日期函数.

    while ((new Date).getTime() > nextGameTick && loops < maxFrameSkip) {
      Game.update();
      nextGameTick += skipTicks;
      loops++;
    }
    

    这没有考虑setTimeout在高频下如何漂移.这也会导致事情变得不同步并变得紧张.JavaScript每秒会漂移+/- 18ms.

    var start, tick = 0;
    var f = function() {
        if (!start) start = new Date().getTime();
        var now = new Date().getTime();
        if (now < start + tick*1000) {
            setTimeout(f, 0);
        } else {
            tick++;
            var diff = now - start;
            var drift = diff % 1000;
            $('
  • ').text(drift + "ms").appendTo('#results'); setTimeout(f, 990); } }; setTimeout(f, 990);
  • 现在让我们把所有这些都放到一个有效的例子中.我们想将我们的游戏循环注入到WebKit的托管渲染循环中.这将有助于平滑渲染的图形.我们还想分割绘制和更新功能.这将在计算何时应绘制下一帧之前更新渲染场景中的对象.如果更新需要很长时间,游戏循环也应该跳过绘制框架.

    的index.html

    
        
             
        
        
        
            
        
    
    

    Game.js

    var Game = {};
    
    Game.fps = 60;
    Game.maxFrameSkip = 10;
    Game.skipTicks = 1000 / Game.fps;
    
    Game.initialize = function() {
        this.entities = [];
        this.viewport = document.body;
    
        this.input = new Input();
    
        this.debug = new Debug();
        this.debug.initialize(this.viewport);
    
        this.screen = new Screen();
        this.screen.initialize(this.viewport);
        this.screen.setWorld(new World());
    };
    
    Game.update = function(tick) {
        Game.tick = tick;
        this.input.update();
        this.debug.update();
        this.screen.update();
    };
    
    Game.draw = function() {
        this.debug.draw();
        this.screen.clear();
        this.screen.draw();
    };
    
    Game.pause = function() {
        this.paused = (this.paused) ? false : true;
    };
    
    /*
     * Runs the actual loop inside browser
     */
    Game.run = (function() {
        var loops = 0;
        var nextGameTick = (new Date).getTime();
        var startTime = (new Date).getTime();
        return function() {
            loops = 0;
            while (!Game.paused && (new Date).getTime() > nextGameTick && loops < Game.maxFrameSkip) {
                Game.update(nextGameTick - startTime);
                nextGameTick += Game.skipTicks;
                loops++;
            }
            Game.draw();
        };
    })();
    
    (function() {
        var onEachFrame;
        if (window.requestAnimationFrame) {
           onEachFrame = function(cb) {
              var _cb = function() {
                    cb();
                 requestAnimationFrame(_cb);
              };
              _cb();
           };
        } else if (window.webkitRequestAnimationFrame) {
           onEachFrame = function(cb) {
              var _cb = function() {
                 cb();
                 webkitRequestAnimationFrame(_cb);
              };
              _cb();
           };
        } else if (window.mozRequestAnimationFrame) {
            onEachFrame = function(cb) {
                var _cb = function() {
                    cb();
                    mozRequestAnimationFrame(_cb);
                };
                _cb();
            };
        } else {
            onEachFrame = function(cb) {
                setInterval(cb, Game.skipTicks);
            };
        }
    
        window.onEachFrame = onEachFrame;
    })();
    

    更多信息

    您可以在此处找到完整的工作示例和所有代码.我已将此答案转换为可下载的javascript框架,您可以从中构建游戏.

    https://code.google.com/p/twod-js/


    -1这是一个格式不佳,表达不佳的漫无边际的答案,有无数的拼写和语法错误.请阅读[Answering How-To](http://stackoverflow.com/help/how-to-answer).
    您的答案是页面上最正确,最新的答案,但是现在示例代码太多了。未来的读者将不会在乎HTML布局,world.js,player.js,camera.js或tile.js。请仅包括与使用requestAnimationFrame处理游戏循环的计时相关的答案元素。

    2> James..:
    setInterval(onTimerTick, 33); // 33 milliseconds = ~ 30 frames per sec
    
    function onTimerTick() {
        // Do stuff.
    }
    


    @Dav:没有理由这样做.函数声明在同一作用域中的逐步代码之前生效.

    3> Cody Crumrin..:

    requestAnimationFrame现在是大多数浏览器的绝佳选择.它使用setInterval执行您正在执行的操作,但是以烘焙方式执行.可能最好的事情是它只在你的标签聚焦时运行.如果你想让事情在后台运行,那么这可能是使用它的一个原因,但是经常(特别是对于渲染循环,只在看到时很重要),当标签不活动时,不使用资源是很好的.

    用法非常简单:

    function gameLoop(){
      window.requestAnimationFrame(gameLoop);
      Game.update();
    }
    

    我讨厌在旧线程上发帖,但这是"javascript游戏循环"的顶级谷歌结果,所以它确实需要包含requestAnimationFrame.

    从paulirish复制的旧浏览器的Pollyfill:

    (function() {
        var lastTime = 0;
        var vendors = ['ms', 'moz', 'webkit', 'o'];
        for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
            window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
            window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] 
                                       || window[vendors[x]+'CancelRequestAnimationFrame'];
        }
    
        if (!window.requestAnimationFrame)
            window.requestAnimationFrame = function(callback, element) {
                var currTime = new Date().getTime();
                var timeToCall = Math.max(0, 16 - (currTime - lastTime));
                var id = window.setTimeout(function() { callback(currTime + timeToCall); }, 
                  timeToCall);
                lastTime = currTime + timeToCall;
                return id;
            };
    
        if (!window.cancelAnimationFrame)
            window.cancelAnimationFrame = function(id) {
                clearTimeout(id);
            };
    }());
    

    有关creativeJS的更深入的解释和使用提示

    推荐阅读
    赛亚兔备_393
    这个屌丝很懒,什么也没留下!
    DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
    Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有