25 KiB
建立太空遊戲第一部分:介紹
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 的任務控制在太空發射期間協調多個系統一樣,我們將建立一個太空遊戲,展示程式的不同部分如何無縫協作。在創建一個實際可以玩的遊戲的同時,您將學習適用於任何軟體專案的基本程式設計概念。
我們將探討組織程式碼的兩種基本方法:繼承和組合。這些不僅僅是學術概念——它們是從電子遊戲到銀行系統的所有事物的運作模式。我們還將實現一個名為 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
課前測驗
繼承與組合在遊戲開發中的應用
隨著專案的複雜性增加,程式碼的組織變得至關重要。最初的簡單腳本如果沒有適當的結構,可能會變得難以維護——就像阿波羅任務需要仔細協調數千個組件一樣。
我們將探討組織程式碼的兩種基本方法:繼承和組合。每種方法都有其獨特的優勢,了解這兩者有助於您在不同情況下選擇合適的方法。我們將通過我們的太空遊戲演示這些概念,其中英雄、敵人、增強道具和其他物件必須高效地互動。
✅ 最著名的程式設計書籍之一與設計模式有關。
在任何遊戲中,您都會有「遊戲物件」——填充遊戲世界的互動元素。英雄、敵人、增強道具和視覺效果都是遊戲物件。每個物件都使用 x 和 y 值存在於特定的螢幕座標上,類似於在坐標平面上繪製點。
儘管它們在視覺上有所不同,但這些物件通常共享基本行為:
- 它們存在於某處——每個物件都有 x 和 y 座標,因此遊戲知道在哪裡繪製它
- 許多物件可以移動——英雄奔跑,敵人追逐,子彈在螢幕上飛行
- 它們有壽命——有些物件會永遠存在,其他物件(如爆炸)會短暫出現然後消失
- 它們會對事物做出反應——當物件碰撞時,增強道具被收集,生命條更新
✅ 想想像吃豆人這樣的遊戲。您能否在這個遊戲中識別出上述四種物件類型?
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;
}
}
讓我們一步步分解:
- 我們正在創建每個遊戲物件都可以使用的基本模板
- 建構函數保存物件的位置(
x,y)以及物件的類型 - 這成為所有遊戲物件構建的基礎
// 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
理解這些概念:
- 創建繼承適當行為的專門物件類型
- 展示了繼承如何允許選擇性地包含功能
- 顯示英雄可以移動,而樹木保持靜止
- 說明類層次結構如何防止不適當的操作
✅ 花幾分鐘重新構想吃豆人中的英雄(例如 Inky、Pinky 或 Blinky),並思考如何用 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 開發中都有其位置。類適用於明確定義的層次結構,而組合在需要最大靈活性時表現出色。
以下是使用每種方法的情況:
- 選擇繼承,當您有明確的「是某物」關係時(例如,英雄 是 可移動物件)
- 選擇組合,當您需要「擁有某物」關係時(例如,英雄 擁有 移動能力)
- 考慮您的團隊偏好和專案需求
- 記住您可以在同一應用程式中混合使用這兩種方法
🔄 教學檢查
物件組織理解:在進入通信模式之前,確保您能夠:
- ✅ 解釋繼承和組合的區別
- ✅ 確定何時使用類與工廠函數
- ✅ 理解
super()關鍵字在繼承中的作用 - ✅ 認識每種方法在遊戲開發中的優勢
快速自測:如何創建一個既能移動又能飛行的飛行敵人?
- 繼承方式:
class FlyingEnemy extends Movable - 組合方式:
{ ...movable, ...flyable, ...gameObject }
現實世界的聯繫:這些模式無處不在:
- React 元件:屬性(組合)與類繼承
- 遊戲引擎:實體-組件系統使用組合
- 移動應用:UI 框架通常使用繼承層次結構
通信模式:Pub/Sub 系統
隨著應用程式變得複雜,管理組件之間的通信變得具有挑戰性。發布-訂閱模式(pub/sub)使用類似於廣播的原則解決了這個問題——一個發射器可以在不知道誰在聽的情況下到達多個接收器。
想像一下當英雄受到傷害時會發生什麼:生命條更新、音效播放、視覺反饋出現。與其將英雄物件直接與這些系統耦合,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 處理以下遊戲場景?
- 敵人死亡:更新分數、播放音效、生成增強道具、從螢幕移除
- 關卡完成:停止音樂、顯示 UI、保存進度、加載下一關
- 收集增強道具:增強能力、更新 UI、播放效果、啟動計時器
專業聯繫:此模式出現在:
- 前端框架:React/Vue 的事件系統
- 後端服務:微服務通信
- 遊戲引擎:Unity 的事件系統
- 移動開發:iOS/Android 的通知系統
GitHub Copilot Agent 挑戰 🚀
使用 Agent 模式完成以下挑戰:
描述: 使用繼承和 Pub/Sub 模式創建一個簡單的遊戲物件系統。您將實現一個基本遊戲,其中不同的物件可以通過事件進行通信,而不直接了解彼此。
提示: 使用以下要求創建一個 JavaScript 遊戲系統:1)創建一個具有 x、y 座標和類型屬性的基礎 GameObject 類。2)創建一個 Hero 類,擴展 GameObject 並可以移動。3)創建一個 Enemy 類,擴展 GameObject 並可以追逐英雄。4)實現一個 EventEmitter 類,用於 Pub/Sub 模式。5)設置事件監聽器,當英雄移動時,附近的敵人接收到 'HERO_MOVED' 事件並更新其位置以追逐英雄。包括 console.log 語句以顯示物件之間的通信。
了解更多關於 agent 模式 的資訊。
🚀 挑戰
考慮如何使用發布-訂閱模式來提升遊戲架構。識別哪些元件應該發出事件,以及系統應如何響應。設計一個遊戲概念並繪製其元件之間的通信模式。
課後測驗
回顧與自學
了解更多有關發布/訂閱模式的資訊,請閱讀相關內容。
⚡ 接下來的5分鐘內可以做的事情
- 打開任何線上HTML5遊戲,使用開發者工具檢查其代碼
- 創建一個簡單的HTML5 Canvas元素並繪製基本形狀
- 嘗試使用
setInterval創建一個簡單的動畫循環 - 探索Canvas API文檔並嘗試一個繪圖方法
🎯 一小時內可以完成的目標
- 完成課後測驗並理解遊戲開發概念
- 使用HTML、CSS和JavaScript文件設置遊戲項目結構
- 創建一個基本的遊戲循環,持續更新和渲染
- 在Canvas上繪製你的第一個遊戲精靈
- 實現基本的資產加載功能,包括圖片和聲音
📅 一週內的遊戲創作計劃
- 完成具有所有計劃功能的完整太空遊戲
- 添加精美的圖形、音效和流暢的動畫
- 實現遊戲狀態(開始畫面、遊戲過程、遊戲結束)
- 創建計分系統和玩家進度追蹤功能
- 使遊戲在各種設備上都能響應並易於訪問
- 將你的遊戲分享至線上並收集玩家的反饋
🌟 一個月的遊戲開發計劃
- 創建多款遊戲,探索不同的類型和機制
- 學習一個遊戲開發框架,例如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
🛠️ 遊戲架構工具包摘要
完成本課程後,你現在擁有:
- 設計模式精通:理解繼承與組合的權衡
- 事件驅動架構:發布/訂閱實現可擴展的通信
- 面向對象設計:類層次結構和行為組合
- 現代JavaScript:工廠函數、展開語法和ES6+模式
- 可擴展架構:鬆耦合和模塊化設計原則
- 遊戲開發基礎:實體系統和組件模式
- 專業模式:符合行業標準的代碼組織方法
實際應用:這些模式直接適用於:
- 前端框架:React/Vue的組件架構和狀態管理
- 後端服務:微服務通信和事件驅動系統
- 移動開發:iOS/Android應用架構和通知系統
- 遊戲引擎:Unity、Unreal和基於網頁的遊戲開發
- 企業軟件:事件溯源和分佈式系統設計
- API設計:RESTful服務和實時通信
專業技能獲得:你現在可以:
- 設計使用經驗證模式的可擴展軟件架構
- 實現處理複雜交互的事件驅動系統
- 選擇適合不同場景的代碼組織策略
- 調試並有效維護鬆耦合系統
- 溝通使用行業標準術語進行技術決策
下一步:你已準備好在真實遊戲中實施這些模式,探索高級遊戲開發主題,或將這些架構概念應用於網頁應用程序!
🌟 成就解鎖:你已掌握從簡單遊戲到複雜企業系統的基礎軟件架構模式!
作業
免責聲明:
本文件已使用 AI 翻譯服務 Co-op Translator 進行翻譯。儘管我們努力確保翻譯的準確性,但請注意,自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵信息,建議使用專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或誤釋不承擔責任。
