JavaにおけるUpdate Methodパターン:体系的な更新によるゲームループ効率の向上
別名
- 更新メカニズム
Update Methodデザインパターンの目的
JavaのUpdate Methodパターンは、各オブジェクトに一度に1フレームの動作を処理させることで、独立したオブジェクトの集合をシミュレートします。
Update Methodパターンの詳細な説明と現実世界の例
現実世界の例
Update Methodデザインパターンの現実世界の例として、気象監視システムがあります。このシステムでは、複数の表示デバイス(モバイルアプリ、ウェブサイトウィジェット、壁掛けデジタルディスプレイなど)が現在の気象状況を表示する必要があります。これらのディスプレイは、様々なセンサー(温度、湿度、風速など)からデータを集める中央気象ステーションからの更新を購読しています。気象ステーションが新しいデータ検出すると、新しい情報をすべての購読している表示デバイスにプッシュする更新メソッドがトリガーされ、すべてが最新の気象状況を同時に表示するようにします。これにより、各デバイスが個別に更新を確認する必要なく、すべてのディスプレイが同期して更新されます。
簡単に言うと
Update Methodデザインパターンは、システムオブジェクトの動作を1フレームずつ処理します。
gameprogrammingpatterns.comによると
ゲームワールドはオブジェクトのコレクションを保持します。各オブジェクトは、オブジェクトの動作の1フレームをシミュレートするupdateメソッドを実装します。各フレームで、ゲームはコレクション内のすべてのオブジェクトを更新します。
JavaにおけるUpdate Methodパターンのプログラミング例
Update Methodデザインパターンは、各オブジェクトに一度に1フレームの動作を処理させることで、独立したゲームオブジェクトやアプリケーションオブジェクトのコレクションをシミュレートする振る舞いパターンです。このパターンは、ゲームワールドの各オブジェクトを1フレームごとに更新する必要があるゲーム開発で一般的に使用されます。
World
クラスはゲームワールドを表します。エンティティのリスト(List<Entity> entities
)と、ゲームが実行中かどうかを示すブール型のフラグ(isRunning
)を保持します。
public class World {
protected List<Entity> entities;
protected volatile boolean isRunning;
public World() {
entities = new ArrayList<>();
isRunning = false;
}
// Other properties and methods...
}
gameLoop
メソッドはメインゲームループです。ゲームが実行されている限り、ユーザー入力の処理、ゲーム状態の更新、次のフレームのレンダリングを継続的に行います。
private void gameLoop() {
while (isRunning) {
processInput();
update();
render();
}
}
processInput
メソッドはユーザー入力の処理をシミュレートします。ここでは、現実のゲーム状況をシミュレートするために、ランダムな時間遅延を導入するだけです。
private void processInput() {
try {
int lag = new SecureRandom().nextInt(200) + 50;
Thread.sleep(lag);
} catch (InterruptedException e) {
LOGGER.error(e.getMessage());
Thread.currentThread().interrupt();
}
}
update
メソッドは、Update Methodパターンが実装されている場所です。ゲームワールド内のすべてのエンティティを反復処理し、それらのupdate
メソッドを呼び出すことで、各エンティティが1フレームの動作を処理できるようにします。
private void update() {
for (var entity : entities) {
entity.update();
}
}
render
メソッドは、次のフレームのレンダリングを担当します。この例では、パターンとは関係がないため、何も行いません。
private void render() {
// Does Nothing
}
run
メソッドとstop
メソッドは、ゲームループの開始と停止に使用されます。
public void run() {
LOGGER.info("Start game.");
isRunning = true;
var thread = new Thread(this::gameLoop);
thread.start();
}
public void stop() {
LOGGER.info("Stop game.");
isRunning = false;
}
addEntity
メソッドは、ゲームワールドに新しいエンティティを追加するために使用されます。
public void addEntity(Entity entity) {
entities.add(entity);
}
App
クラスでは、World
クラスとそのメソッドを使用して、ゲームワールドを作成し、エンティティを追加し、ゲームループを開始する方法を示しています。
@Slf4j
public class App {
private static final int GAME_RUNNING_TIME = 2000;
public static void main(String[] args) {
try {
var world = new World();
var skeleton1 = new Skeleton(1, 10);
var skeleton2 = new Skeleton(2, 70);
var statue = new Statue(3, 20);
world.addEntity(skeleton1);
world.addEntity(skeleton2);
world.addEntity(statue);
world.run();
Thread.sleep(GAME_RUNNING_TIME);
world.stop();
} catch (InterruptedException e) {
LOGGER.error(e.getMessage());
}
}
}
コンソール出力
14:46:33.181 [main] INFO com.iluwatar.updatemethod.World -- Start game.
14:46:33.280 [Thread-0] INFO com.iluwatar.updatemethod.Skeleton -- Skeleton 1 is on position 11.
14:46:33.281 [Thread-0] INFO com.iluwatar.updatemethod.Skeleton -- Skeleton 2 is on position 71.
14:46:33.452 [Thread-0] INFO com.iluwatar.updatemethod.Skeleton -- Skeleton 1 is on position 12.
14:46:33.452 [Thread-0] INFO com.iluwatar.updatemethod.Skeleton -- Skeleton 2 is on position 72.
14:46:33.621 [Thread-0] INFO com.iluwatar.updatemethod.Skeleton -- Skeleton 1 is on position 13.
14:46:33.621 [Thread-0] INFO com.iluwatar.updatemethod.Skeleton -- Skeleton 2 is on position 73.
14:46:33.793 [Thread-0] INFO com.iluwatar.updatemethod.Skeleton -- Skeleton 1 is on position 14.
14:46:33.793 [Thread-0] INFO com.iluwatar.updatemethod.Skeleton -- Skeleton 2 is on position 74.
14:46:33.885 [Thread-0] INFO com.iluwatar.updatemethod.Skeleton -- Skeleton 1 is on position 15.
14:46:33.885 [Thread-0] INFO com.iluwatar.updatemethod.Skeleton -- Skeleton 2 is on position 75.
14:46:34.113 [Thread-0] INFO com.iluwatar.updatemethod.Skeleton -- Skeleton 1 is on position 16.
14:46:34.113 [Thread-0] INFO com.iluwatar.updatemethod.Skeleton -- Skeleton 2 is on position 76.
14:46:34.324 [Thread-0] INFO com.iluwatar.updatemethod.Skeleton -- Skeleton 1 is on position 17.
14:46:34.324 [Thread-0] INFO com.iluwatar.updatemethod.Skeleton -- Skeleton 2 is on position 77.
14:46:34.574 [Thread-0] INFO com.iluwatar.updatemethod.Skeleton -- Skeleton 1 is on position 18.
14:46:34.575 [Thread-0] INFO com.iluwatar.updatemethod.Skeleton -- Skeleton 2 is on position 78.
14:46:34.730 [Thread-0] INFO com.iluwatar.updatemethod.Skeleton -- Skeleton 1 is on position 19.
14:46:34.731 [Thread-0] INFO com.iluwatar.updatemethod.Skeleton -- Skeleton 2 is on position 79.
14:46:34.803 [Thread-0] INFO com.iluwatar.updatemethod.Skeleton -- Skeleton 1 is on position 20.
14:46:34.803 [Thread-0] INFO com.iluwatar.updatemethod.Skeleton -- Skeleton 2 is on position 80.
14:46:34.979 [Thread-0] INFO com.iluwatar.updatemethod.Skeleton -- Skeleton 1 is on position 21.
14:46:34.979 [Thread-0] INFO com.iluwatar.updatemethod.Skeleton -- Skeleton 2 is on position 81.
14:46:35.045 [Thread-0] INFO com.iluwatar.updatemethod.Skeleton -- Skeleton 1 is on position 22.
14:46:35.046 [Thread-0] INFO com.iluwatar.updatemethod.Skeleton -- Skeleton 2 is on position 82.
14:46:35.187 [main] INFO com.iluwatar.updatemethod.World -- Stop game.
14:46:35.288 [Thread-0] INFO com.iluwatar.updatemethod.Skeleton -- Skeleton 1 is on position 23.
14:46:35.289 [Thread-0] INFO com.iluwatar.updatemethod.Skeleton -- Skeleton 2 is on position 83.
これはUpdate Methodパターンの基本的な実装です。現実世界のアプリケーションでは、Entity
クラスにはさらにメソッドとプロパティがあり、update
メソッドにはエンティティの動作をシミュレートするためのより複雑なロジックが含まれる可能性があります。
JavaでUpdate Methodパターンを使用するケース
Update Methodは、以下の場合に有効です。
- 通常、手動での同期処理のオーバーヘッドなしに複数のオブジェクトを同期して更新する必要があるシナリオで適用され、上級Java開発者にとって最適な選択肢となります。
- 同時に実行する必要がある多くのオブジェクトまたはシステムを持つアプリケーション。
- 各オブジェクトの動作は、他のオブジェクトとはほとんど独立している。
- オブジェクトを時間経過とともにシミュレートする必要がある。
JavaにおけるUpdate Methodパターンの現実世界の応用例
- ワールドオブジェクトを1フレームごとに更新する必要があるリアルタイムゲームやデータ処理アプリケーション。
Update Methodパターンの利点とトレードオフ
利点
- 各エンティティは独自の動作をカプセル化します。
- エンティティの追加と削除が容易になります。
- メインループを簡潔に保ちます。
トレードオフ
- 毎フレーム制御を譲渡するため、複雑さが増します。
- 各フレーム後の更新を再開できるように、状態を保存する必要があります。
- エンティティは各フレームでシミュレートされますが、真に同時実行ではありません。
関連するJavaデザインパターン
- コンポーネント:ゲーム開発で、エンティティを様々なコンポーネントで構成し、それぞれが独自のupdateメソッドを持つことができるようにするために使用されることが多いです。
- ゲームループ:ゲームの状態を継続的に更新し、ゲームをレンダリングします。これには、様々なゲームオブジェクトのUpdate Methodが含まれる場合があります。