You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Web-Dev-For-Beginners/translations/ja/6-space-game/1-introduction/README.md

30 KiB

宇宙ゲームを作ろう パート1: はじめに

journey
    title Your Game Development Journey
    section Foundation
      Learn game architecture: 3: Student
      Understand inheritance: 4: Student
      Explore composition: 4: Student
    section Communication
      Build pub/sub system: 4: Student
      Design event flow: 5: Student
      Connect components: 5: Student
    section Application
      Create game objects: 5: Student
      Implement patterns: 5: Student
      Plan game structure: 5: Student

ゲームプレイを示す宇宙ゲームのアニメーション

NASAのミッションコントロールが宇宙打ち上げ時に複数のシステムを調整するように、私たちはプログラムの異なる部分がシームレスに連携する方法を示す宇宙ゲームを作ります。実際に遊べるものを作りながら、どんなソフトウェアプロジェクトにも応用できる基本的なプログラミング概念を学びます。

コードを整理するための2つの基本的なアプローチ、継承とコンポジションを探ります。これらは単なる学術的な概念ではなく、ビデオゲームから銀行システムまでを支えるパターンです。また、宇宙船の通信ネットワークのように、依存関係を作らずに情報を共有できるpub/subという通信システムも実装します。

このシリーズの終わりまでに、ゲームやウェブアプリケーション、その他のソフトウェアシステムを開発する際にスケールアップや進化が可能なアプリケーションの作り方を理解できるようになります。

mindmap
  root((Game Architecture))
    Object Organization
      Inheritance
      Composition
      Class Hierarchies
      Behavior Mixing
    Communication Patterns
      Pub/Sub System
      Event Emitters
      Message Passing
      Loose Coupling
    Game Objects
      Properties (x, y)
      Behaviors (move, collide)
      Lifecycle Management
      State Management
    Design Patterns
      Factory Functions
      Observer Pattern
      Component System
      Event-Driven Architecture
    Scalability
      Modular Design
      Maintainable Code
      Testing Strategies
      Performance Optimization

講義前クイズ

講義前クイズ

ゲーム開発における継承とコンポジション

プロジェクトが複雑になるにつれて、コードの整理が重要になります。単純なスクリプトとして始まったものが、適切な構造がなければ維持が困難になることがあります。これは、アポロ計画が数千のコンポーネント間の慎重な調整を必要としたのと似ています。

コードを整理するための2つの基本的なアプローチ、継承とコンポジションを探ります。それぞれに独自の利点があり、両方を理解することで、状況に応じて適切なアプローチを選択できるようになります。これらの概念を宇宙ゲームを通じて示します。ヒーロー、敵、パワーアップ、その他のオブジェクトが効率的に相互作用する必要があります。

最も有名なプログラミング本の1つはデザインパターンに関するものです。

どんなゲームでも、ゲームオブジェクトがあります。これはゲームの世界を構成するインタラクティブな要素です。ヒーロー、敵、パワーアップ、視覚効果などがゲームオブジェクトです。それぞれが座標平面上の点をプロットするように、xyの値を使用して特定の画面座標に存在します。

見た目は異なりますが、これらのオブジェクトはしばしば基本的な動作を共有します:

  • どこかに存在する すべてのオブジェクトはxyの座標を持ち、ゲームが描画する場所を知る
  • 多くは移動できる ヒーローは走り、敵は追いかけ、弾丸は画面を横切る
  • 寿命がある 一部は永遠に存在し、他のもの(爆発など)は一時的に現れて消える
  • 何かに反応する 衝突が起きると、パワーアップが収集され、体力バーが更新される

パックマンのようなゲームを考えてみてください。このゲームで上記の4つのオブジェクトタイプを特定できますか

classDiagram
    class GameObject {
        +x: number
        +y: number
        +type: string
        +exists_somewhere()
    }
    
    class MovableObject {
        +moveTo(x, y)
        +can_move_around()
    }
    
    class TemporaryObject {
        +lifespan: number
        +has_lifespan()
    }
    
    class InteractiveObject {
        +onCollision()
        +reacts_to_stuff()
    }
    
    GameObject <|-- MovableObject
    GameObject <|-- TemporaryObject
    GameObject <|-- InteractiveObject
    
    MovableObject <|-- Hero
    MovableObject <|-- Enemy
    MovableObject <|-- Bullet
    
    TemporaryObject <|-- PowerUp
    TemporaryObject <|-- Explosion
    
    InteractiveObject <|-- Collectible
    InteractiveObject <|-- Obstacle

コードで動作を表現する

ゲームオブジェクトが共有する共通の動作を理解したところで、これらの動作をJavaScriptで実装する方法を探りましょう。オブジェクトの動作は、クラスや個々のオブジェクトに付属するメソッドを通じて表現できます。いくつかのアプローチがあります。

クラスベースのアプローチ

クラスと継承は、ゲームオブジェクトを整理するための構造化されたアプローチを提供します。カール・リンネによって開発された分類学的分類システムのように、共通のプロパティを含む基本クラスから始め、これらの基本を継承しながら特定の機能を追加する専門化されたクラスを作成します。

継承は重要な概念です。MDNの継承に関する記事でさらに学びましょう。

以下は、クラスと継承を使用してゲームオブジェクトを実装する方法です:

// Step 1: Create the base GameObject class
class GameObject {
  constructor(x, y, type) {
    this.x = x;
    this.y = y;
    this.type = type;
  }
}

これをステップごとに分解すると:

  • すべてのゲームオブジェクトが使用できる基本テンプレートを作成しています
  • コンストラクタはオブジェクトがどこにあるか(xy)とどのような種類のものかを保存します
  • これがすべてのゲームオブジェクトが基づく基盤になります
// Step 2: Add movement capability through inheritance
class Movable extends GameObject {
  constructor(x, y, type) {
    super(x, y, type); // Call parent constructor
  }

  // Add the ability to move to a new position
  moveTo(x, y) {
    this.x = x;
    this.y = y;
  }
}

上記では:

  • GameObjectクラスを拡張して移動機能を追加しました
  • super()を使用して親コンストラクタを呼び出し、継承されたプロパティを初期化しました
  • オブジェクトの位置を更新するmoveTo()メソッドを追加しました
// Step 3: Create specific game object types
class Hero extends Movable {
  constructor(x, y) {
    super(x, y, 'Hero'); // Set type automatically
  }
}

class Tree extends GameObject {
  constructor(x, y) {
    super(x, y, 'Tree'); // Trees don't need movement
  }
}

// Step 4: Use your game objects
const hero = new Hero(0, 0);
hero.moveTo(5, 5); // Hero can move!

const tree = new Tree(10, 15);
// tree.moveTo() would cause an error - trees can't move

これらの概念を理解することで:

  • 適切な動作を継承する専門化されたオブジェクトタイプを作成できます
  • 継承が選択的な機能の追加を可能にすることを示します
  • ヒーローは移動できるが木は静止していることを示します
  • クラス階層が不適切な動作を防ぐことを説明します

数分間、パックマンのヒーロー例えばインキー、ピンキー、ブリンキーを再構想し、それがJavaScriptでどのように記述されるか考えてみてください。

コンポジションアプローチ

コンポジションはモジュール設計の哲学に従い、エンジニアが交換可能なコンポーネントで宇宙船を設計する方法に似ています。親クラスから継承する代わりに、特定の動作を組み合わせて、必要な機能を正確に備えたオブジェクトを作成します。このアプローチは、堅固な階層的制約なしで柔軟性を提供します。

// Step 1: Create base behavior objects
const gameObject = {
  x: 0,
  y: 0,
  type: ''
};

const movable = {
  moveTo(x, y) {
    this.x = x;
    this.y = y;
  }
};

このコードが行うこと:

  • 位置とタイププロパティを持つ基本的なgameObject定義します
  • 移動機能を持つ別のmovable動作オブジェクトを作成します
  • 位置データと移動ロジックを独立して保持することで関心を分離します
// Step 2: Compose objects by combining behaviors
const movableObject = { ...gameObject, ...movable };

// Step 3: Create factory functions for different object types
function createHero(x, y) {
  return {
    ...movableObject,
    x,
    y,
    type: 'Hero'
  };
}

function createStatic(x, y, type) {
  return {
    ...gameObject,
    x,
    y,
    type
  };
}

上記では:

  • スプレッド構文を使用して基本オブジェクトプロパティと移動動作を組み合わせました
  • カスタマイズされたオブジェクトを返すファクトリ関数を作成しました
  • 堅固なクラス階層なしで柔軟なオブジェクト作成を可能にしました
  • 必要な動作だけを持つオブジェクトを許可しました
// Step 4: Create and use your composed objects
const hero = createHero(10, 10);
hero.moveTo(5, 5); // Works perfectly!

const tree = createStatic(0, 0, 'Tree');
// tree.moveTo() is undefined - no movement behavior was composed

覚えておくべき重要なポイント:

  • 継承するのではなく動作を混ぜ合わせてオブジェクトを構成します
  • 堅固な継承階層よりも柔軟性を提供します
  • 必要な機能だけを持つオブジェクトを許可します
  • クリーンなオブジェクトの組み合わせのために最新のJavaScriptスプレッド構文を使用します

**Which Pattern Should You Choose?**

**Which Pattern Should You Choose?**

```mermaid
quadrantChart
    title Code Organization Patterns
    x-axis Simple --> Complex
    y-axis Rigid --> Flexible
    quadrant-1 Advanced Composition
    quadrant-2 Hybrid Approaches
    quadrant-3 Basic Inheritance
    quadrant-4 Modern Composition
    
    Class Inheritance: [0.3, 0.2]
    Interface Implementation: [0.6, 0.4]
    Mixin Patterns: [0.7, 0.7]
    Pure Composition: [0.8, 0.9]
    Factory Functions: [0.5, 0.8]
    Prototype Chain: [0.4, 0.3]

💡 プロのヒント: 両方のパターンは現代のJavaScript開発で役立ちます。クラスは明確に定義された階層に適しており、コンポジションは最大限の柔軟性が必要な場合に輝きます。

各アプローチを使用するタイミング:

  • 継承を選択: 明確な「is-a」関係がある場合ヒーローは移動可能なオブジェクトである
  • コンポジションを選択: 「has-a」関係が必要な場合ヒーローは移動能力を持つ
  • チームの好みとプロジェクトの要件を考慮
  • 両方のアプローチを同じアプリケーションで混在させることを忘れない

🔄 教育的チェックイン

オブジェクト整理の理解: 通信パターンに進む前に、以下を確認してください:

  • 継承とコンポジションの違いを説明できる
  • クラスとファクトリ関数を使用するタイミングを特定できる
  • 継承におけるsuper()キーワードの動作を理解できる
  • ゲーム開発における各アプローチの利点を認識できる

簡単な自己テスト: 移動と飛行が可能な飛行する敵をどのように作成しますか?

  • 継承アプローチ: class FlyingEnemy extends Movable
  • コンポジションアプローチ: { ...movable, ...flyable, ...gameObject }

実世界の接続: これらのパターンは至る所で見られます:

  • Reactコンポーネント: Propsコンポジションvsクラス継承
  • ゲームエンジン: エンティティコンポーネントシステムはコンポジションを使用
  • モバイルアプリ: UIフレームワークはしばしば継承階層を使用

通信パターン: Pub/Subシステム

アプリケーションが複雑になるにつれて、コンポーネント間の通信を管理することが課題になります。パブリッシュ-サブスクライブパターンpub/subは、ラジオ放送の原理に似た方法でこの問題を解決します。1つの送信機が誰が聞いているかを知らずに複数の受信機に到達できます。

ヒーローがダメージを受けたときに何が起こるかを考えてみてください体力バーが更新され、効果音が再生され、視覚的なフィードバックが表示されます。ヒーローオブジェクトをこれらのシステムに直接結びつけるのではなく、pub/subを使用して「ダメージを受けた」というメッセージを送信します。反応する必要があるシステムは、このメッセージタイプを購読し、適切に反応します。

Pub/Subは「パブリッシュ-サブスクライブ」の略です

flowchart TD
    A[Hero Takes Damage] --> B[Publish: HERO_DAMAGED]
    B --> C[Event System]
    
    C --> D[Health Bar Subscriber]
    C --> E[Sound System Subscriber]
    C --> F[Visual Effects Subscriber]
    C --> G[Achievement System Subscriber]
    
    D --> H[Update Health Display]
    E --> I[Play Damage Sound]
    F --> J[Show Red Flash]
    G --> K[Check Survival Achievements]
    
    style A fill:#ffebee
    style B fill:#e1f5fe
    style C fill:#e8f5e8
    style H fill:#fff3e0
    style I fill:#fff3e0
    style J fill:#fff3e0
    style K fill:#fff3e0

Pub/Subアーキテクチャの理解

pub/subパターンは、アプリケーションの異なる部分を緩く結合し、直接依存せずに連携できるようにします。この分離により、コードがより保守可能でテスト可能で変更に柔軟になります。

pub/subの主要な要素

  • メッセージ 'PLAYER_SCORED'のような簡単なテキストラベルで、何が起こったかを説明(追加情報を含む場合も)
  • パブリッシャー 「何かが起こった!」と叫ぶオブジェクト
  • サブスクライバー 「そのイベントに関心がある」と言い、発生時に反応するオブジェクト
  • イベントシステム メッセージが正しいリスナーに届くようにする仲介者

イベントシステムの構築

これらの概念を示すシンプルで強力なイベントシステムを作りましょう:

// Step 1: Create the EventEmitter class
class EventEmitter {
  constructor() {
    this.listeners = {}; // Store all event listeners
  }
  
  // Register a listener for a specific message type
  on(message, listener) {
    if (!this.listeners[message]) {
      this.listeners[message] = [];
    }
    this.listeners[message].push(listener);
  }
  
  // Send a message to all registered listeners
  emit(message, payload = null) {
    if (this.listeners[message]) {
      this.listeners[message].forEach(listener => {
        listener(message, payload);
      });
    }
  }
}

ここで何が起こるかを分解すると:

  • シンプルなクラスを使用して中央のイベント管理システムを作成
  • メッセージタイプで整理されたオブジェクトにリスナーを保存
  • on()メソッドを使用して新しいリスナーを登録
  • emit()を使用して関心のあるすべてのリスナーにメッセージを送信
  • 関連情報を渡すためのオプションのデータペイロードをサポート

実践例: すべてをまとめる

さて、これを実際に見てみましょうpub/subのクリーンで柔軟な性質を示すシンプルな移動システムを構築します

// Step 1: Define your message types
const Messages = {
  HERO_MOVE_LEFT: 'HERO_MOVE_LEFT',
  HERO_MOVE_RIGHT: 'HERO_MOVE_RIGHT',
  ENEMY_SPOTTED: 'ENEMY_SPOTTED'
};

// Step 2: Create your event system and game objects
const eventEmitter = new EventEmitter();
const hero = createHero(0, 0);

このコードが行うこと:

  • メッセージ名のタイプミスを防ぐために定数オブジェクトを定義
  • すべての通信を処理するイベントエミッターインスタンスを作成
  • 初期位置にヒーローオブジェクトを初期化
// Step 3: Set up event listeners (subscribers)
eventEmitter.on(Messages.HERO_MOVE_LEFT, () => {
  hero.moveTo(hero.x - 5, hero.y);
  console.log(`Hero moved to position: ${hero.x}, ${hero.y}`);
});

eventEmitter.on(Messages.HERO_MOVE_RIGHT, () => {
  hero.moveTo(hero.x + 5, hero.y);
  console.log(`Hero moved to position: ${hero.x}, ${hero.y}`);
});

上記では:

  • 移動メッセージに反応するイベントリスナーを登録
  • 移動方向に基づいてヒーローの位置を更新
  • ヒーローの位置変更を追跡するためにコンソールログを追加
  • 入力処理から移動ロジックを分離
// Step 4: Connect keyboard input to events (publishers)
window.addEventListener('keydown', (event) => {
  switch(event.key) {
    case 'ArrowLeft':
      eventEmitter.emit(Messages.HERO_MOVE_LEFT);
      break;
    case 'ArrowRight':
      eventEmitter.emit(Messages.HERO_MOVE_RIGHT);
      break;
  }
});

これらの概念を理解することで:

  • キーボード入力をゲームイベントに直接結びつけることなく接続
  • 入力システムがゲームオブジェクトと間接的に通信できるようにする
  • 同じキーボードイベントに複数のシステムが反応できるようにする
  • キーバインドを変更したり新しい入力方法を追加するのが簡単になる
sequenceDiagram
    participant User
    participant Keyboard
    participant EventEmitter
    participant Hero
    participant SoundSystem
    participant Camera
    
    User->>Keyboard: Presses ArrowLeft
    Keyboard->>EventEmitter: emit('HERO_MOVE_LEFT')
    EventEmitter->>Hero: Move left 5 pixels
    EventEmitter->>SoundSystem: Play footstep sound
    EventEmitter->>Camera: Follow hero
    
    Hero->>Hero: Update position
    SoundSystem->>SoundSystem: Play audio
    Camera->>Camera: Adjust viewport

💡 プロのヒント: このパターンの美しさは柔軟性にあります!音響効果、画面の揺れ、またはパーティクル効果を簡単に追加できます。既存のキーボードや移動コードを変更する必要はありません。

このアプローチが好きになる理由:

  • 新しい機能の追加が非常に簡単 必要なイベントをリッスンするだけ
  • 同じイベントに複数のものが反応しても互いに干渉しない
  • 各部分が独立して動作するためテストが非常に簡単
  • 何かが壊れたとき、問題の場所がすぐにわかる

Pub/Subが効果的にスケールする理由

pub/subパターンは、アプリケーションが複雑になるにつれてシンプルさを維持します。多数の敵、動的なUI更新、または音響システムを管理する場合でも、このパターンはアーキテクチャの変更なしで拡張性を提供します。新しい機能は既存のイベントシステムに統合され、既存の機能に影響を与えません。

⚠️ よくある間違い: 初期段階で特定のメッセージタイプを作りすぎないでください。広いカテゴリから始め、ゲームのニーズが明確になるにつれてそれを洗練してください。

守るべきベストプラクティス:

  • 関連するメッセージを論理的なカテゴリにグループ化
  • 何が起こったかを明確に示す説明的な名前を使用
  • メッセージペイロードをシンプルで焦点を絞ったものに保つ
  • チームのコラボレーションのためにメッセージタイプを文書化

🔄 教育的チェックイン

イベント駆動型アーキテクチャの理解: システム全体の理解を確認してください:

  • pub/subパターンがコンポーネント間の緊密な結合を防ぐ方法
  • イベント駆動型アーキテクチャで新しい機能を追加するのがなぜ簡単なのか
  • EventEmitterが通信フローで ゲームアーキテクチャを向上させるために、Pub-Subパターンがどのように役立つかを考えましょう。どのコンポーネントがイベントを発行すべきか、システムがどのように応答すべきかを特定してください。ゲームコンセプトを設計し、そのコンポーネント間の通信パターンをマッピングしましょう。

講義後のクイズ

講義後のクイズ

復習と自己学習

Pub/Subについてさらに学ぶには、こちらを読んでください

次の5分間でできること

  • 任意のHTML5ゲームをオンラインで開き、DevToolsを使ってコードを確認する
  • 簡単なHTML5 Canvas要素を作成し、基本的な形を描画する
  • setIntervalを使って簡単なアニメーションループを作成してみる
  • Canvas APIのドキュメントを調べて描画メソッドを試してみる

🎯 この1時間で達成できること

  • 講義後のクイズを完了し、ゲーム開発の概念を理解する
  • HTML、CSS、JavaScriptファイルを使ってゲームプロジェクトの構造を設定する
  • 継続的に更新と描画を行う基本的なゲームループを作成する
  • Canvas上に最初のゲームスプライトを描画する
  • 画像や音声の基本的なアセット読み込みを実装する

📅 1週間でのゲーム作成

  • 計画したすべての機能を備えた完全なスペースゲームを完成させる
  • 洗練されたグラフィック、効果音、滑らかなアニメーションを追加する
  • ゲームの状態(スタート画面、ゲームプレイ、ゲームオーバー)を実装する
  • スコアリングシステムとプレイヤーの進捗追跡を作成する
  • ゲームをレスポンシブにし、デバイス間でアクセス可能にする
  • ゲームをオンラインで共有し、プレイヤーからフィードバックを得る

🌟 1か月でのゲーム開発

  • 異なるジャンルやメカニクスを探求する複数のゲームを作成する
  • PhaserやThree.jsのようなゲーム開発フレームワークを学ぶ
  • オープンソースのゲーム開発プロジェクトに貢献する
  • 高度なゲームプログラミングパターンと最適化を習得する
  • ゲーム開発スキルを示すポートフォリオを作成する
  • ゲーム開発やインタラクティブメディアに興味を持つ人々を指導する

🎯 ゲーム開発マスタリータイムライン

timeline
    title Game Architecture Learning Progression
    
    section Object Patterns (20 minutes)
        Code Organization: Class inheritance
                         : Composition patterns
                         : Factory functions
                         : Behavior mixing
        
    section Communication Systems (25 minutes)
        Event Architecture: Pub/Sub implementation
                          : Message design
                          : Event emitters
                          : Loose coupling
        
    section Game Object Design (30 minutes)
        Entity Systems: Property management
                      : Behavior composition
                      : State handling
                      : Lifecycle management
        
    section Architecture Patterns (35 minutes)
        System Design: Component systems
                     : Observer pattern
                     : Command pattern
                     : State machines
        
    section Advanced Concepts (45 minutes)
        Scalable Architecture: Performance optimization
                             : Memory management
                             : Modular design
                             : Testing strategies
        
    section Game Engine Concepts (1 week)
        Professional Development: Scene graphs
                                 : Asset management
                                 : Rendering pipelines
                                 : Physics integration
        
    section Framework Mastery (2 weeks)
        Modern Game Development: React game patterns
                               : Canvas optimization
                               : WebGL basics
                               : PWA games
        
    section Industry Practices (1 month)
        Professional Skills: Team collaboration
                           : Code reviews
                           : Game design patterns
                           : Performance profiling

🛠️ ゲームアーキテクチャツールキットのまとめ

このレッスンを完了した後、以下を習得しました:

  • デザインパターンの習得:継承とコンポジションのトレードオフの理解
  • イベント駆動型アーキテクチャスケーラブルな通信のためのPub/Subの実装
  • オブジェクト指向設計:クラス階層と振る舞いのコンポジション
  • モダンJavaScriptファクトリ関数、スプレッド構文、ES6+パターン
  • スケーラブルなアーキテクチャ:疎結合とモジュール設計の原則
  • ゲーム開発の基礎:エンティティシステムとコンポーネントパターン
  • プロフェッショナルパターン:コード組織の業界標準アプローチ

実世界での応用:これらのパターンは以下に直接適用できます:

  • フロントエンドフレームワークReact/Vueのコンポーネントアーキテクチャと状態管理
  • バックエンドサービス:マイクロサービス通信とイベント駆動型システム
  • モバイル開発iOS/Androidアプリのアーキテクチャと通知システム
  • ゲームエンジンUnity、Unreal、ウェブベースのゲーム開発
  • エンタープライズソフトウェア:イベントソーシングと分散システム設計
  • API設計RESTfulサービスとリアルタイム通信

習得したプロフェッショナルスキル:以下が可能になります:

  • 設計:実証済みのパターンを使用してスケーラブルなソフトウェアアーキテクチャを設計する
  • 実装:複雑なインタラクションを処理するイベント駆動型システムを実装する
  • 選択:異なるシナリオに適したコード組織戦略を選択する
  • デバッグ:疎結合システムを効果的に維持・修正する
  • コミュニケーション:業界標準の用語を使用して技術的な決定を伝える

次のステップ:これらのパターンを実際のゲームに実装し、高度なゲーム開発トピックを探求するか、これらのアーキテクチャ概念をウェブアプリケーションに適用する準備が整いました!

🌟 達成解除:シンプルなゲームから複雑なエンタープライズシステムまでを支える基本的なソフトウェアアーキテクチャパターンを習得しました!

課題

ゲームをモックアップする


免責事項:
この文書はAI翻訳サービスCo-op Translatorを使用して翻訳されています。正確性を追求しておりますが、自動翻訳には誤りや不正確な部分が含まれる可能性があります。元の言語で記載された文書を正式な情報源としてご参照ください。重要な情報については、専門の人間による翻訳を推奨します。この翻訳の使用に起因する誤解や誤認について、当方は一切の責任を負いません。