1

我一直在尝试设置一个 javascript 游戏循环,但遇到了两个问题。我发现在 chrome 中,当我失去浏览器窗口的焦点然后单击返回我正在运行的动画时,它会快速运行它应该在后台渲染的帧。我还注意到,当以我拥有的当前速度移动时,动画是模糊的,但其他人已经能够让他们的画布绘图快速移动并且看起来仍然清晰。我知道他们似乎对此有很多了解,但我无法理解我的问题到底是什么。我认为这是创建游戏循环的推荐方式。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
    <title>Frame Test</title>
    <link href="/css/bootstrap.css" media="all" rel="stylesheet" type="text/css" />
    <script language="javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"
        type="text/javascript">
    </script>
    <script language="javascript" src="js/jquery.hotkeys.js" type="text/javascript"></script>
    <script language="javascript" src="js/key_status.js" type="text/javascript"></script>
    <script language="javascript" src="js/util.js" type="text/javascript"></script>
    <script language="javascript" src="js/sprite.js" type="text/javascript"></script>
</head>
<body>
    <button id="button1">
        Toggle Loop</button>
    <h1 id="frameCount">
        Game Loop Test</h1>
    <canvas id="gameCanvas" width="800" height="500">
<p>Your browser doesn't support canvas.</p>
</canvas>
    <script type='text/javascript'>



        // demo code used for playing around with javascript-canvas animations
        var frameCount = 0;
        var drawingCanvas = document.getElementById('gameCanvas');
        // Check the element is in the DOM and the browser supports canvas
        if (drawingCanvas.getContext) {
            var context = drawingCanvas.getContext('2d');
            var x = 100;
            var y = 100;
            var right = true;
            context.strokeStyle = "#000000";
            context.fillStyle = "Green";
            context.beginPath();
            context.arc(x, y, 50, 0, Math.PI * 2, true);
            context.closePath();
            context.stroke();
            context.fill();

        }



        function Timer(settings) {
            this.settings = settings;
            this.timer = null;
            this.on = false;  //Bool that represents if the timer is running or stoped
            this.fps = settings.fps || 30;  //Target frames per second value
            this.interval = Math.floor(1000 / 30);
            this.timeInit = null;  //Initial time taken when start is called

            return this;
        }

        Timer.prototype =
            {
                run: function () {
                    var $this = this;

                    this.settings.run();
                    this.timeInit += this.interval;

                    this.timer = setTimeout(
                function () { $this.run() },
                this.timeInit - (new Date).getTime()
            );
                },

                start: function () {
                    if (this.timer == null) {
                        this.timeInit = (new Date).getTime();
                        this.run();
                        this.on = true;
                    }
                },

                stop: function () {
                    clearTimeout(this.timer);
                    this.timer = null;
                    this.on = false;
                },

                toggle: function () {

                    if (this.on) { this.stop(); }
                    else { this.start(); }
                }
            }

        var timer = new Timer({
            fps: 30,
            run: function () {
                //---------------------------------------------run game code here------------------------------------------------------
                //Currently Chorme is playing a catch up game with the frames to be drawn when the user leaves the browser window and then returns
                //A simple canvas animation is drawn here to try and figure out how to solve this issue.  (Most likely related to the timer implimentation)
                //Once figured out probably the only code in this loop should be something like
                //updateGameLogic();
                //updateGameCanvas();


                frameCount++;
                if (drawingCanvas.getContext) {
                    // Initaliase a 2-dimensional drawing context

                    //Canvas commands go here
                    context.clearRect((x - 52), 48, (x + 52), 104);

                    // Create the yellow face
                    context.strokeStyle = "#000000";
                    context.fillStyle = "Green";
                    context.beginPath();
                    if (right) {
                        x = x + 6;
                        if (x > 500)
                            right = false;
                    } else {
                        x = x - 6;
                        if (x < 100)
                            right = true;
                    }
                    context.arc(x, 100, 50, 0, Math.PI * 2, true);
                    context.closePath();
                    context.stroke();
                    context.fill();
                }
                document.getElementById("frameCount").innerHTML = frameCount;
                //---------------------------------------------end of game loop--------------------------------------------------------
            }
        });
        document.getElementById("button1").onclick = function () { timer.toggle(); };
        frameCount++;
        document.getElementById("frameCount").innerHTML = frameCount;

    </script>
</body>
</html>

- - - - - - -更新 - - - - - - - - - - -

我使用了 requestanimation 帧,这已经解决了帧速率问题,但是当动画运行时我仍然会得到奇怪的重影/模糊。知道我应该怎么画这个东西吗?

4

1 回答 1

3

好的,您的部分问题是,当您切换标签时,Chrome 会降低其性能。

基本上,当您离开时,Chrome 会将页面上的所有计算速度减慢到 1 或 2 fps(电池节电,并且当前选项卡的性能更高)。
以您拥有的方式使用 setTimeout 基本上是安排所有这些调用,这些调用坐下来等待用户回来(或最多仅以 1fps 运行)。

当用户回来时,你有数百个这样的堆叠调用,等待处理,因为它们被提前安排好了,它们都已经过了“等待”时间,所以它们都将执行尽可能快(快进),直到堆栈被清空到您必须开始等待下一次调用的 32 毫秒。

解决此问题的方法是在有人离开时停止计时器——暂停游戏。
在一些以有意义的方式支持画布游戏的浏览器上,还支持 PageVisibility API。你应该调查一下。对于其他浏览器,它会不那么简单,但是您可以将window例如绑定到模糊事件。

请确保当您重新启动时,您还清除了更新的间隔。

最终,我建议转到`requestAnimationFrame,因为它会智能地处理帧速率,并且还会处理由于堆栈调用而看到的节流,但是你的计时器看起来像是一个不错的替代浏览器的浏览器还没有它。

至于模糊性,这需要更多的洞察力。
如果你在谈论图像,我脑海中浮现的原因是你的画布的宽度/高度是在 CSS 中设置的,或者你的精灵没有以 1:1 的比例使用图像他们被拉出来了。

它也可以归结为图像的亚像素定位或旋转。

希望能有所帮助。

...实际上,在再次查看您的代码后,尝试从 HTML 中的画布中删除“宽度”和“高度”,然后canvas.width = 800; canvas.height = 500;在 JS 中进行更改,看看是否有帮助。

于 2012-11-03T04:05:44.573 回答