ゲームプログラミング備忘録

@startuml
' Enum for GameObjectState
enum GameObjectState {
    Active,
    Inactive,
    Destroyed
}

' Interface for GameObject
interface GameObject {
    + x: number
    + y: number
}

' Interface for StaticGameObject
interface StaticGameObject {
    + render(context: CanvasRenderingContext2D): void
}

' StaticGameObject inherits from GameObject
StaticGameObject --|> GameObject

' Interface for GameComponent
interface GameComponent {
    + owner: DynamicGameObject
    + setOwner(owner: DynamicGameObject): void
    + update(deltaTime: number): void
}

' Interface for DynamicGameObject
interface DynamicGameObject {
    + state: GameObjectState
    + components: GameComponent[]
    + setState(state: GameObjectState): void
    + getState(): GameObjectState
    + update(deltaTime: number): void
    + updateComponents(deltaTime: number): void
    + render(context: CanvasRenderingContext2D): void
    + processInput(input: InputSystem): void
    + addComponent(component: GameComponent): void
    + removeComponent(component: GameComponent): void
}

' DynamicGameObject inherits from GameObject
DynamicGameObject --|> GameObject
DynamicGameObject --> GameObjectState
DynamicGameObject --> GameComponent

' GameComponent references DynamicGameObject
GameComponent --> DynamicGameObject

' Interface for InputDevice
interface InputDevice {
    + updateState(): void
    + isKeyPressed(key: any): boolean
}

' Interface for InputSystem
interface InputSystem {
    // Properties and methods for InputSystem can be added here
}

' Interface for Scene
interface Scene {
    + game: Game
    + staticGameObjects: StaticGameObject[]
    + dynamicGameObjects: DynamicGameObject[]
    + addDynamicGameObject(gameObject: DynamicGameObject): void
    + addStaticGameObject(gameObject: StaticGameObject): void
    + removeDynamicGameObject(gameObject: DynamicGameObject): void
    + removeStaticGameObject(gameObject: StaticGameObject): void
    + update(deltaTime: number): void
    + render(context: CanvasRenderingContext2D): void
    + processInput(input: InputSystem): void
    + close(): void
}

Scene --> Game
Scene --> StaticGameObject
Scene --> DynamicGameObject
Scene --> InputSystem

' Interface for IGame (extracted from Game class)
interface IGame {
    + getInputSystem(): InputSystem
    + getCanvas(): HTMLCanvasElement
    + getContext(): CanvasRenderingContext2D
    + addScene(scene: Scene): void
    + removeScene(scene: Scene): void
    + changeScene(scene: Scene): void
    + startLoop(): void
    + stopLoop(): void
}

IGame --> InputSystem
IGame --> Scene

' Game class
class Game {
    + Game(canvas: HTMLCanvasElement)
    + startLoop(): void
    // Other public methods and properties
}

' Main class representing the entry point
class Main {
    + Main(): void
}

Main --> Game
@enduml

以上のPlantUMLを画像化するとこのようになる


UML図
import { Game } from "./Game.js";

// Main
(function () {
    const canvas = document.getElementById("canvas") as HTMLCanvasElement;
    const game = new Game(canvas);
    game.startLoop();
})();

エントリーポイントはこのような単純なループ開始コードで記述できる。

ゲームプログラミングのポイントを並べていく

ゲームループという1つの無限ループが実質的なmainとして機能する

ゲームループは以下の手順を無限に繰り返す。

  1. 入力を受取って他のオブジェクトに入力を渡す(渡されたオブジェクトが入力を処理して「ベクトルの方向」を決定する)

  2. 入力を渡して「ベクトルの方向」が変化したオブジェクトそれぞれのupdate(deltaTime: double)を呼び、経過時間に応じた変化を行わせる(オブジェクトのフィールドを更新させる)

  3. レンダリングを行う

ここで重要なのはupdate()をループの終わりからループ開始までの経過時間deltaTimeの関数としておくことである。経過時間の関数として記述することでフレームレートによらず画面を更新することが可能となる。

ゲームループはシーンを管理し、シーンが各ゲームオブジェクトを管理、更新を行う。

シーンはゲームループと同様のロジックをもち、ゲームループから呼ばれることで無限ループをつくる。

各ゲームオブジェクトはコンポーネントを追加、削除、更新する関数を基本とし、コンポーネントを通して状態を管理、更新する

コンポーネントは「ベクトルの方向」などを管理し、入力に応じて方向を更新し、経過時間に応じて状態を変化させることができるようにする。

ポイント: ニュートン物理と同様に初期条件と経過時間がわかれば状態が定まるという考え方を基本として構築していく。

初期条件を入力で決定し、経過時間と初期条件を使って状態が更新されるというロジックがすべての基礎となる。

この記事が気に入ったらサポートをしてみませんか?