《游戲編程模式》(3)

来源:http://www.cnblogs.com/pandawuwyj/archive/2017/01/06/6256800.html
-Advertisement-
Play Games

Chatper 5 原型模式 核心思想是一個對象可以生成與自身相似的其他對象。 基類Monster,有一個抽象方法clone: 1 class Monster 2 { 3 public: 4 5 virtual ~Monster() {} 6 virtual Monster* clone() = 0 ...


Chatper 5 原型模式

核心思想是一個對象可以生成與自身相似的其他對象。

 

基類Monster,有一個抽象方法clone:

1 class Monster
2 {
3 public:
4 
5   virtual ~Monster() {}
6   virtual Monster* clone() = 0;
7 
8   // Other stuff...
9 };

 

子類的clone實現:

 1 class Ghost : public Monster {
 2 public:
 3 
 4   Ghost(int health, int speed)
 5   : health_(health),
 6     speed_(speed)
 7   {} 
 8 
 9   virtual Monster* clone()
10   {
11     return new Ghost(health_, speed_);
12   }
13 
14 private:
15   int health_;
16   int speed_;
17 };

 

通用的Spawner類:

 1 class Spawner
 2 {
 3 
 4 public:
 5   Spawner(Monster* prototype)
 6   : prototype_(prototype)
 7   {}
 8 
 9   Monster* spawnMonster()
10   {
11     return prototype_->clone();
12   }
13 
14 private:
15   Monster* prototype_;
16 };

 

這樣用:

1 Monster* ghostPrototype = new Ghost(15, 3);
2 Spawner* ghostSpawner = new Spawner(ghostPrototype);
3 Monster* newGhost = Spawner->spawnMonster();

 

生成器函數和孵化函數指針:

 1 Monster* spawnGhost()
 2 {
 3   return new Ghost();
 4 }
 5 typedef Monster* (*SpawnCallback)();
 6 
 7 class Spawner
 8 {
 9 public:
10   Spawner(SpawnCallback spawn)
11   : spawn_(spawn)
12   {}
13 
14   Monster* spawnMonster()
15   {
16     return spawn_();
17   }
18 
19 private:
20   SpawnCallback spawn_;
21 
22 };

 

這樣用:

1 Spawner* ghostSpawner = new Spawner(spawnGhost);
2 Monster* newGhost = ghostSpawner->spawnMonster();

 

Chatper 6 單例模式

確保一個類只有一個實例,併為其提供一個全局訪問入口。

 

 1 class FileSystem
 2 {
 3 public:
 4   static FileSystem& instance()
 5   {
 6     static FileSystem *instance = new FileSystem();
 7     return *instance;
 8   } 
 9 
10 private:
11   FileSystem() {}
12 
13 };
  1. 延遲初始化
  2. C++11保證局部靜態變數的初始化只進行一次
  3. 多線程安全
  4. 私有構造函數

 

繼承單例(多平臺):

 1 class FileSystem
 2 {
 3 public:
 4 
 5   static FileSystem& instance();
 6  
 7   virtual ~FileSystem() {}
 8 
 9   virtual char* readFile(char* path) = 0;
10   virtual void  writeFile(char* path, char* contents) = 0;
11  
12 protected:
13   FileSystem() {}
14 
15 };
16 
17 class PS3FileSystem : public FileSystem
18 {
19 
20 public:
21   virtual char* readFile(char* path)
22   {
23     // Use Sony file IO API...
24   }
25 
26   virtual void writeFile(char* path, char* contents)
27   {
28     // Use sony file IO API...
29   }
30 };
31 
32 class WiiFileSystem : public FileSystem
33 {
34 
35 public:
36   virtual char* readFile(char* path)
37   {
38     // Use Nintendo file IO API...
39   }
40 
41   virtual void writeFile(char* path, char* contents)
42   {
43     // Use Nintendo file IO API...
44   }
45 
46 };

 

Instance的編譯跳轉實現:

 1 FileSystem& FileSystem::instance()
 2 {
 3 
 4 #if PLATFORM == PLAYSTATION3
 5     static FileSystem *instance = new PS3FileSystem();
 6 #elif PLATFORM == WII
 7     static FileSystem *instance = new WiiFileSystem();
 8 #endif 
 9 
10   return *instance;
11 }

 

單例的缺陷:

  1. 全局變數,單例就是一個全局狀態,只是被封裝到了類中;
  2. 延遲初始化可能導致掉幀和卡頓,可能導致記憶體佈局碎片化。 

通過將全局對象類包裝在現有類里來減少全局對象數量:

 1 class Game
 2 {
 3 
 4 public:
 5   static Game& instance() { return instance_; }
 6  
 7   // Functions to set log_, et. al. ...
 8  
 9   Log& getLog() { return *log_; }
10 
11   FileSystem&  getFileSystem()  { return *fileSystem_; }
12 
13   AudioPlayer& getAudioPlayer() { return *audioPlayer_; }
14  
15 private:
16   static Game instance_; 
17   Log *log_;
18   FileSystem  *fileSystem_;
19   AudioPlayer *audioPlayer_;
20 
21 };
22 
23 Game::instance().getAudioPlayer().play(VERY_LOUD_BANG);

 

Chatper 7 狀態模式

允許一個對象在其內部狀態改變時改變自身的行為,對象看起來好像是在修改自身類。

複雜的分支和可變的狀態是兩種最容易出錯的代碼。

狀態、輸入和轉換:

1.  擁有一組數目較小的狀態,可以在這組狀態之間切換;

2.  同一時刻只能處於一種狀態;

3.  響應用戶輸入和游戲事件

 

定義一個介面,enter函數定義一些進入狀態時的處理,exit函數定義一些狀態改變前的處理:

 1 class HeroineState
 2 {
 3 
 4 public:
 5   virtual ~HeroineState() {}
 6   virtual void handleInput(Heroine& heroine, Input input) {}
 7   virtual void update(Heroine& heroine) {} 
 8 
 9   virtual void enter(Heroine& heroine) {}
10   virtual void exit(Heroine& heroine) {}
11 
12 };

 

每一個狀態都繼承這個狀態介面:

 1 class DuckingState : public HeroineState
 2 {
 3 
 4 public:
 5   DuckingState()
 6   : chargeTime_(0)
 7   {}
 8 
 9   virtual void handleInput(Heroine& heroine, Input input) {
10     if (input == RELEASE_DOWN)
11     {
12       // Change to standing state...
13       heroine.setGraphics(IMAGE_STAND);
14     }
15   }
16 
17   virtual void update(Heroine& heroine) {
18     chargeTime_++;
19     if (chargeTime_ > MAX_CHARGE)
20     {
21       heroine.superBomb();
22     }
23   } 
24 
25 private:
26   int chargeTime_;
27 
28 };

 

主角類中有一個指針指向當前狀態:

 1 class Heroine
 2 {
 3 
 4 public:
 5   virtual void handleInput(Input input)
 6   {
 7     state_->handleInput(*this, input);
 8   }
 9  
10   virtual void update()
11   {
12     state_->update(*this);
13   }
14 
15   // Other methods...
16 
17 private:
18   HeroineState* state_;
19 
20 };

 

靜態狀態(省CPU省記憶體):

 1 class HeroineState
 2 {
 3 
 4 public:
 5   static StandingState standing;
 6   static DuckingState ducking;
 7   static JumpingState jumping;
 8   static DivingState diving; 
 9 
10   // Other code...
11 };
12 
13 if (input == PRESS_B)
14 {
15   heroine.state_ = &HeroineState::jumping;
16   heroine.setGraphics(IMAGE_JUMP);
17 }

 

實例化狀態(handleInput方法返回後刪除原狀態):

 1 void Heroine::handleInput(Input input)
 2 {
 3   HeroineState* state = state_->handleInput(*this, input);
 4   if (state != NULL)
 5   {
 6     delete state_;
 7     state_ = state;
 8 
 9     // Call the enter action on the new state.
10     state_->enter(*this); 
11   }
12 }
13 
14 HeroineState* StandingState::handleInput(
15   Heroine& heroine, Input input)
16 {
17   if (input == PRESS_DOWN)
18   {
19     // Other code...
20     return new DuckingState();
21   }
22 
23   // Stay in this state.
24   return NULL;
25 }

 

併發狀態機(當兩種狀態沒什麼關係時):

 1 class Heroine
 2 {
 3 
 4   // Other code...
 5  
 6 private:
 7   HeroineState* state_;
 8   HeroineState* equipment_;
 9 
10 };
11 
12 void Heroine::handleInput(Input input)
13 {
14   state_->handleInput(*this, input);
15   equipment_->handleInput(*this, input);
16 }

如果兩種狀態有一些聯繫(不能太多),需要對某些狀態處理進行干預,可以做一些簡單的if判斷並特殊處理下。

 

層次狀態機:

一個狀態有父狀態,如果子狀態不處理就交給他的父狀態處理。用來處理可能包含的大量相似狀態。

 1 class OnGroundState : public HeroineState
 2 {
 3 
 4 public:
 5   virtual void handleInput(Heroine& heroine, Input input)
 6   {
 7     if (input == PRESS_B)
 8     {
 9       // Jump...
10     }
11     else if (input == PRESS_DOWN)
12     {
13       // Duck...
14     }
15   }
16 };
17 
18 class DuckingState : public OnGroundState
19 {
20 
21 public:
22   virtual void handleInput(Heroine& heroine, Input input)
23   {
24     if (input == RELEASE_DOWN)
25     {
26       // Stand up...
27     }
28     else
29     {
30       // Didn't handle input, so walk up hierarchy.
31       OnGroundState::handleInput(heroine, input);
32     }
33   }
34 };

 

下推自動機:

 

 

開火時push Firing,結束後pop掉開火狀態,狀態機自動返回開火前的狀態。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 大圖輪播 > 1 2 ... ...
  • 這篇文章主要講解Java在創建對象的時候,初始化的順序。主要從以下幾個例子中講解: 繼承關係中初始化順序 初始化塊與構造器的順序 已經載入過的類的初始化順序 載入父類,會不會載入子類 創建子類對象會不會創建父類對象 例子1——繼承關係中初始化順序 先看簡單的情況,看下麵的例子: 其執行的結果如下: ...
  • YII 2.x 模板文件的 beginBlock、beginContent、beginCache ...
  • 1 #include 2 #include 3 #include 4 struct student //定義結構體 5 { 6 char name[7]; //姓名 7 int number; //號碼 8 }student,student1; 9 void menu() //顯示欄 10 { 11... ...
  • 一.圖片驗證碼概述:很多網站都有該實現作用:為了提高系統的安全性有了驗證碼,我們就可以要求用戶在輸入用戶名,密碼等信息後,同時輸入圖片上的文字,用戶提交後,系統會首先從session中提取剛剛生成的驗證碼,並和用戶輸入的驗證碼進行比較,如果比較相等,表示用戶是從登錄界面登錄過來的,否則,表示用戶是非 ...
  • 在Spring+Struts+Hibernate中,有時需要使用到Spring上下文。項目啟動時,會自動根據applicationContext配置文件初始化上下文,可以使用ApplicationContextAware介面去獲得Spring上下文。創建以下的類: 在applicationConte ...
  • 大家好,今天我們學習了Java如何連接資料庫。之前學過.net語言的資料庫操作,感覺就是一通百通,大同小異。 JDBC是Java資料庫連接技術的簡稱,提供連接各種常用資料庫的能力。 JDBC API (主要功能:與資料庫建立連接、執行語句、處理結果): 提供者:Sun公司 內容:供程式員調用的介面與 ...
  • 首先為什麼要自己編寫Dockerfile來構建 nginx、php、mariadb這三個鏡像呢?一是希望更深入瞭解Dockerfile的使用,也就能初步瞭解docker鏡像是如何被構建的;二是希望將來可以定製自己的images,特別是能針對不同的系統環境與目標需求適當對鏡像進行調整改進。在編輯Doc... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...