《游戏编程模式》(3)

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掉开火状态,状态机自动返回开火前的状态。

posted on 2017-01-06 16:26  pandawuwyj  阅读(272)  评论(0编辑  收藏  举报

导航