固定ステップと可変ステップ
固定ステップ
デフォルトでは、固定ステップと呼ばれる一定の間隔でゲームのデータを更新する状態に設定されています。前述したように、ゲーム時間の 1 秒間に約 60 回 Update() メソッドが呼び出されてデータを更新します。こうすることで、実行するコンピュータのパフォーマンスに影響されることなく、一定の速度でゲームを進行させることができます。
この固定ステップによる Update() メソッドの呼び出しは、Game クラスの TargetElapsedTime プロパティの影響を受けます。
public TimeSpan TargetElapsedTime { get; set; }
このプロパティは、固定ステップで Update() メソッドを呼び出す時間間隔を表す TimeSpan を提供します。このプロパティに、任意の TimeSpan を設定することで、Update() メソッドの呼び出し間隔を変更できます。ゲーム更新の粒度を上げたい場合は、デフォルトよりも短い間隔に設定します。逆に、粒度を下げたい場合は、長い間隔に設定します。
using System; using System.Diagnostics; using Microsoft.Xna.Framework; public class TestGame : Game { public static void Main(string[] args) { using (Game game = new TestGame()) game.Run(); } public Test() { TargetElapsedTime = new TimeSpan(0, 0, 0, 0, 100); } private double t; private int? latestUpdatePerSec; private int currentUpdatePerSec; protected override void Update(GameTime gameTime) { currentUpdatePerSec++; t += gameTime.ElapsedGameTime.TotalMilliseconds; Window.Title = (latestUpdatePerSec == null ? "計測中..." : latestUpdatePerSec + "/s") + ", ElapsedGameTime=" + gameTime.ElapsedGameTime; if (t >= 1000) { latestUpdatePerSec = currentUpdatePerSec; currentUpdatePerSec = 0; t = 0; Debug.WriteLine("Update per sec=" + latestUpdatePerSec); } base.Update(gameTime); } }
コード1は、コンストラクタで TargetElapsedTime プロパティの値を変更し、100 ミリ秒間隔で Update() メソッドを呼び出すように設定しています。この設定が正しく機能していれば、1 秒間に 10 回 Update() メソッドが呼び出されることになります。実行結果のように、1 秒間の間に Update() メソッドが実行された回数と、最後の Update() メソッドの呼び出しからの経過時間を表示します。Update() メソッドが 100 ミリ秒間隔で呼び出され、1 秒間の間に 10 回実行されていることが確認できます。
1 秒間の間に呼び出された Update() メソッドの回数を数えるために、Update() メソッドが呼び出されるたびに currentUpdatePerSec フィールドの値をインクリメントしています。この値は、1 秒が経過した時点で初期化する必要があるので ElapsedGameTime プロパティから得られる前回の Update() メソッドからの経過時間をミリ秒単位で t フィールドに加算します。t フィールドが 1000 を超えた時点で 1 秒経過したと判断し、currentUpdatePerSec フィールドの値を latestUpdatePerSec フィールドに代入します。この latestUpdatePerSec フィールドの値が、最も新しい 1 秒間で Update() メソッドが呼び出された回数を表します。その後、currentUpdatePerSec フィールドと t フィールドを 0 に初期化しています。
可変ステップ
可能な限り Update() メソッドを呼び出し続けることを可変ステップと呼びます。可変ステップは、TargetElapsedTime プロパティの設定を無視して、可能な限り連続で Update() メソッドを呼び出し続けます。設定を可変ステップに変更するには IsFixedTimeStep プロパティを使います。
public bool IsFixedTimeStep { get; set; }
このプロパティの値が true の場合は固定ステップ、そうでなければ可変ステップを表します。デフォルトでは固定ステップに設定されています。可変ステップに変更するには、このプロパティに false を設定します。
using System.Diagnostics; using Microsoft.Xna.Framework; public class TestGame : Game { public static void Main(string[] args) { using (Game game = new TestGame()) game.Run(); } public Test() { IsFixedTimeStep = false; } private double t; private int? latestUpdatePerSec; private int currentUpdatePerSec; protected override void Update(GameTime gameTime) { currentUpdatePerSec++; t += gameTime.ElapsedGameTime.TotalMilliseconds; Window.Title = (latestUpdatePerSec == null ? "計測中..." : latestUpdatePerSec + "/s") + ", ElapsedGameTime=" + gameTime.ElapsedGameTime; if (t >= 1000) { latestUpdatePerSec = currentUpdatePerSec; currentUpdatePerSec = 0; t = 0; Debug.WriteLine("Update per sec=" + latestUpdatePerSec); } base.Update(gameTime); } }
コード2は、コンストラクタで IsFixedTimeStep プロパティを false に設定しています。そのため、このゲームのデータ更新は可変ステップです。実行環境が許す限りの速度で、連続して Update() メソッドを呼び出し続けます。Update() メソッドの内容は、コード1と変わりません。1 秒間に更新された回数をカウントし、タイトルバーに表示しています。実行結果をみると、Update() メソッドの呼び出し間隔が固定されていないことを確認できます。