1

私はjavascriptゲームループを設定しようとしていますが、2つの問題が発生しています。ブラウザウィンドウのフォーカスを失い、実行中のアニメーションをクリックして戻ると、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ミリ秒待機し始めるまで、可能な限り高速(早送り)します。

これに対する解決策は、誰かが去ったときにタイマーを停止することです-ゲームを一時停止します。
意味のある方法でキャンバスゲームをサポートする一部のブラウザでは、PageVisibilityAPIもサポートされています。あなたはそれを調べる必要があります。他のブラウザの場合、それはそれほど単純ではありませんが、たとえば、blurイベントに関連付けることができますwindow

再起動するときは、更新の間隔もクリアするようにしてください。

最終的には、 `requestAnimationFrameに移行することをお勧めします。これは、フレームレートをインテリジェントに処理し、呼び出しがスタックされているために表示されるスロットルも処理するためですが、タイマーは、まだ持っていないブラウザの適切な代替品のように見えますそれ。

ぼやけについては、より多くの洞察が必要です。
画像について話している場合、頭のてっぺんから離れた理由は、キャンバスの幅/高さがどこかでCSSに設定されているか、スプライトが画像から1:1のスケールで使用されていないことです。彼らはから引っ張られています。

また、画像のサブピクセルポジショニング、つまり回転に帰着することもあります。

それが少し役立つことを願っています。

...実際には、コードをもう一度確認した後、HTMLでキャンバスから「幅」と「高さ」を削除し、代わりcanvas.width = 800; canvas.height = 500;にJSで変更して、それが役立つかどうかを確認してください。

于 2012-11-03T04:05:44.573 に答える