LoginSignup
17
15

More than 5 years have passed since last update.

[JavaScript] ゲームループを作る記事を見てみる

Last updated at Posted at 2016-01-28

こちらの記事を参考に、ゲームループの処理を見てみます。
(やってることは分かるんですが、自分の中にしっかり落とし込めるまで理解できてなかったのでメモとして書いておきます)

ゲームループ

ゲームは常に画面が動き続け、かつユーザからの操作を待ちます。
また最近のゲームでは物理演算などが当たり前に利用されているので、そうした計算処理を一定の間隔でループさせて処理する必要があります。
そうした諸々の処理のループを一般的に「ゲームループ」と呼びます。

詳細についてはこのあたりの記事が参考になりそうです。

解説

さて、ではさっそく記事を見ていきます。
といってもやっていることは比較的単純で、記事の言葉を引用すると以下になります。

1秒間に可能な限り多くのフレームを描画しようとしながら、1秒毎に決められた回数のロジックを実行するよう試みます。

ということです。

紹介されているコードを少し整形して紹介。

Game.fps = 50;

Game.run = (function() {
    var loops = 0;
    var skipTicks = 1000 / Game.fps;
    var maxFrameSkip = 10;
    var nextGameTick = Date.now();

    return function {
        loops = 0;

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

        Game.draw();
    };
})();

// Start the game loop
Game._intervalId = setInterval(Game.run, 0);

[追記]
以下、コメントで間違いを指摘いただいたので修正しています。

skipTicks1000msFPS で割っています。つまり 1FPS あたりの時間を計算しています。
maxFrameSkip は何フレーム分 update を実行したら描画を実行するかを決めています。
つまり「1秒毎に決められた回数のロジックを実行するよう試み」ているわけですね。
なのでこの場合だと 10回 ということになります。

ここ、だいぶ勘違いをしていました。
コメントで指摘してもらってだいぶクリアになった気がします。

ここについてはコメントを見てもらったほうがいいと思いますが、自分なりの解釈も書いておきます。

解釈

まず前提として、
描画処理は指定したFPS関係なく、関数が呼ばれた回数分「できるだけ」実行し、update 関数はFPSの指定通りの回数実行できるよう努力する
という見方をします。

さて、では問題をシンプルにするために while 文をまるまる取って考えてみましょう。
すると run が呼ばれた回数だけ draw が実行されるのは自明ですね。

ただこれではゲームループとしてアップデートしてほしい内容がなにも更新されなくなってしまいます。
理想として update がコスト0で終えられるなら、前述の通り run 実行回数分だけ draw も実行されます。
しかし現実はそううまくいかないのでここにそれなりのコストがかかります。

さて、そのコストがかかった分をどうするか、が while 文で行っている処理と見ることができます。

update に要した時間が 1フレーム分の時間 == skipTicks より小さい場合、次の while の評価は当然 ((Date.now() > nextGameTick) == false) になりループを抜けます。
この状態が維持され続ければ updatedraw は1対1で実行され続けますね。

ただもし、update の処理が重くなってしまった場合どうなるでしょうか。
結果として Date.now() > nextGameTicktrue になります。
(1フレーム分進めた時間よりも現在時刻のほうが先に行ってしまっている)

そうすると遅れた分を取り戻すためにループが開始されます。
ただ、update が毎回重くなってしまうと永久にループを抜けられなくなってしまうため、maxFrameSkip によってキャップを設け、その回数分実行したらループを抜けて一回描画を行う、という処理になります。

・・・ふぅ、この認識であってるかな( ;´Д)
要は「遅れた分を取り戻す処理が
while` の中身」ってことだと思いますw

17
15
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
15