目標
前回はこちら(https://qiita.com/kazuya976/items/ba1527780cb24edca71f)
JavaScriptでとりあえずゲームを作成し、Gitに共有させることを目的としております。
今日はどんなゲームを、どのように作るかを具体的に考えようと思います。
なお、前回の記事ではNode.jsをインストールさせましたが、作っていくのはブラウザゲームであり、Node.jsはいりませんでした。どんまい( ´∀` )
その代わり、Live Serverをインストールさせて[Alt+L,Alt+O]というショートカットを使って実行させようと思います。
ゲーム企画
・とりあえず動けばいいからブラウザゲームでよい
・なるべく簡単なやつ
・(できれば)再利用できるように部品いろいろ作って、他のゲーム作りにも使える基盤をつくりたい
ゲームアーキテクチャ
調べていると、MVCのようなもの(アーキテクチャというらしい)がゲーム作りにもあるみたい。
簡単に言うと、全体の構造や設計の骨組みを意味するもので、ゲームアーキテクチャはゲームの開発におけるシステム全体の設計手法らしい。
何をつくるにおいても、型が大事だと私は思っているのでゲームアーキテクチャについてここにまとめつつ、どのような手順でゲームを作成していくかを考える。
★コンポーネントベースのアーキテクチャ(ECS)
チャットGPTに聞いたところ一番おすすめらしい。
ゲーム内のエンティティをコンポーネントして分割し、必要なシステムを追加していくような仕組みらしい。感覚的にはオブジェクト指向に近いのかな?
★MVCパターン
モデル→ゲームの状態
ビュー→画面の表示
コントローラー→ユーザー入力
仕事は今MVVCみたいな感じでやっているからとてもイメージはしやすい。コードを整理しやすいのが利点。
状態遷移パターン(State Pattern)
プレイヤーやゲーム全体が異なる状態(メニュー、ゲーム画面など)をもつ。これを管理するために状態遷移を使うと、状態ごとのふるまいを綺麗に管理できる。
シンプルなフロー管理と状態の追加のしやすさが利点。
結論
ECSを強くお勧めされているからそれを使いたい。
だけど、コンポーネントベースのアーキテクチャというのがピンとこないので調べる
コンポーネントベースのアーキテクチャとは何ですか?
コンポーネントをレゴブロックにたとえろ。とのこと。オブジェクト指向と何が違うのかさっぱりわからんがレゴという部品を作って、それを組み合わせて作るっていう解釈。
(オブジェクト指向も部品をオブジェクト、というものにたとえて、モノを組み合わせて作るんだよね....うーん?)
コンポーネントはライブラリに保存され、開発者によって組み立てられて作られるらしい。
どうやって、何から作ろう?
ゲームアーキテクチャって何ぞや、って話は何となく理解した。では実際に明日から何をつくろうっていうのまで考えるのが今日の目的(脱線しまくるのは気にしない)
とりあえず、ECSで作るのが目的なんだけど。まじで触ったことのない分野?というかイメージがつきづらくて若干難しい。
以下はチャットGPTにスタート画面とゲーム画面を書いてって頼んだ時の一部
class Position {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
// Spriteコンポーネント(画像を持つ)
class Sprite {
constructor(image) {
this.image = image;
}
}
// Textコンポーネント(テキストを持つ)
class Text {
constructor(content) {
this.content = content;
}
}
// Stateコンポーネント(ゲームの状態を管理)
class State {
constructor(state) {
this.state = state; // 'start', 'game', 'gameOver' など
}
}
// Inputコンポーネント(ユーザー入力)
class Input {
constructor(type) {
this.type = type; // 'click', 'key' など
}
}
これだけ見ると、コンポーネント、というよりはクラスをたくさん書いているようにしか見えない。
次にエンティティの定義
class StartScreenEntity {
constructor() {
this.components = new Map();
this.components.set('position', new Position(100, 100));
this.components.set('sprite', new Sprite('start_button.png')); // ボタンの画像
this.components.set('text', new Text('Start Game'));
this.components.set('state', new State('start')); // 現在はスタート画面
}
}
// ゲーム画面のエンティティ
class GameScreenEntity {
constructor() {
this.components = new Map();
this.components.set('position', new Position(0, 0));
this.components.set('sprite', new Sprite('player.png')); // プレイヤーの画像
this.components.set('state', new State('game')); // ゲーム進行中
}
}
ふむふむ。わかるけど分からん。エンティティっていう一つの塊をつくって、それを扱えばそれなりの動作をするってイメージかな?
チャットGPTさんは優秀すぎるのでシステムも同時にサンプルを見せてくれました。
render(entities) {
entities.forEach(entity => {
const position = entity.components.get('position');
const sprite = entity.components.get('sprite');
const text = entity.components.get('text');
if (sprite) {
// 描画処理(例: canvas APIやDOM操作)
console.log(`Rendering sprite at (${position.x}, ${position.y})`);
}
if (text) {
console.log(`Rendering text: ${text.content}`);
}
});
}
}
class InputSystem {
handleInput(entities, input) {
// 入力処理(クリックやキー入力を処理)
entities.forEach(entity => {
const state = entity.components.get('state');
if (state.state === 'start' && input.type === 'click') {
state.state = 'game'; // スタートボタンがクリックされたらゲームを開始
console.log('Game Started');
}
});
}
}
RenderingSystemが画面に描画するシステムで、InputSystemがユーザーの入力を処理するシステムらしい。
んー、正直なじみがなさすぎてコードがうまく頭に入らない。複数のクラスをたくさん用意して、それをシステムとして作っている感じか...
これを0から考えるのはめちゃくちゃ大変だけど、チャットGPTさんってすごいね。
うん。よくわからんけど、このコードをコピペして動かしてみようって思う。
実践
とりあえず、調べて出てきたやつを使って作ってみる。
ついでに、ファイル構成も調べたら下記がでてきたのでとりあえずこれをつくる
まとめ:ファイル構成
Position.js — 位置に関連するコンポーネント
Sprite.js — スプライト(画像)に関連するコンポーネント
Text.js — テキストに関連するコンポーネント
State.js — ゲームの状態を管理するコンポーネント
Input.js — 入力に関連するコンポーネント
Entity.js — エンティティ管理クラス
StartScreenEntity.js — スタート画面のエンティティ
GameScreenEntity.js — ゲーム画面のエンティティ
RenderingSystem.js — 画面描画システム
InputSystem.js — 入力処理システム
StateSystem.js — 状態管理システム
Game.js — ゲームロジック実行ファイル
まとめ
今日は、コンポーネントとどんなファイル構成にするか、までを何となくつかんだ。
これを使って、イメージをつかんだらAIに頼らずに0から作れるようにはしたい。