Chatper 2 命令模式
命令是一个具象化(实例化)的方法调用。
A command is a reified method call.
定义一个基类,命令的控制对象由参数传入:
1 class Command2 {3 public:4 virtual ~Command() {}5 virtual void execute(GameActor& actor) = 0;6 };
为不同的游戏命令创建子类:
1 class JumpCommand : public Command2 {3 public:4 virtual void execute(GameActor& actor)5 {6 actor.jump();7 }8 };
在输入处理中,为每个按钮存储一个指针,绑定一个命令,且可以灵活替换新的命令:
1 class InputHandler 2 { 3 public: 4 void handleInput(); 5 6 // Methods to bind commands... 7 8 private: 9 Command* buttonX_;10 Command* buttonY_;11 Command* buttonA_;12 Command* buttonB_;13 };
现在,输入处理返回一个命令指针:
1 Command* InputHandler::handleInput() 2 { 3 if (isPressed(BUTTON_X)) return buttonX_; 4 if (isPressed(BUTTON_Y)) return buttonY_; 5 if (isPressed(BUTTON_A)) return buttonA_; 6 if (isPressed(BUTTON_B)) return buttonB_; 7 8 // Nothing pressed, so do nothing. 9 return NULL;10 }
接收命令并让角色执行:
1 Command* command = inputHandler.handleInput();2 if (command)3 {4 command->execute(actor);5 }
对游戏中的AI对象也可以简单地提供命令对象以供执行。
空对象模式:在这里可以提供一个什么都不做的命令。
撤销和重做:
execute中记录上一次的位置:
1 class Command 2 { 3 public: 4 virtual ~Command() {} 5 virtual void execute() = 0; 6 virtual void undo() = 0; 7 }; 8 class MoveUnitCommand : public Command 9 {10 public:11 MoveUnitCommand(Unit* unit, int x, int y)12 : unit_(unit),13 xBefore_(0),14 yBefore_(0),15 x_(x),16 y_(y)17 {}18 19 virtual void execute()20 {21 // Remember the unit's position before the move22 // so we can restore it.23 xBefore_ = unit_->x();24 yBefore_ = unit_->y();25 26 unit_->moveTo(x_, y_);27 }28 29 virtual void undo()30 {31 unit_->moveTo(xBefore_, yBefore_);32 }33 34 private:35 Unit* unit_;36 int xBefore_, yBefore_;37 int x_, y_;38 };
多次撤销可以维护一个命令列表和对当前命令的一个引用。
Chapter 3 享元模式
将数据对象切分成两种类型:
- 不属于单一实例对象并能被所有对象共享的数据;
- 对每个对象都是唯一的数据。
地形类:
1 class Terrain 2 { 3 public: 4 Terrain(int movementCost, 5 bool isWater, 6 Texture texture) 7 : movementCost_(movementCost), 8 isWater_(isWater), 9 texture_(texture)10 {}11 12 int getMovementCost() const { return movementCost_; }13 bool isWater() const { return isWater_; }14 const Texture& getTexture() const { return texture_; }15 16 private:17 int movementCost_;18 bool isWater_;19 Texture texture_;20 };
使用指向地形对象的网格指针,相同地形的瓦片指向同一地形实例:
1 class World 2 { 3 public: 4 World() 5 : grassTerrain_(1, false, GRASS_TEXTURE), 6 hillTerrain_(3, false, HILL_TEXTURE), 7 riverTerrain_(2, true, RIVER_TEXTURE) 8 {} 9 10 private:11 Terrain grassTerrain_;12 Terrain hillTerrain_;13 Terrain riverTerrain_;14 15 Terrain* tiles_[WIDTH][HEIGHT];16 // Other stuff...17 };
使用这些地形实例来绘制地面:
1 void World::generateTerrain() 2 { 3 // Fill the ground with grass. 4 for (int x = 0; x < WIDTH; x++) 5 { 6 for (int y = 0; y < HEIGHT; y++) 7 { 8 // Sprinkle some hills. 9 if (random(10) == 0)10 {11 tiles_[x][y] = &hillTerrain_;12 }13 else14 {15 tiles_[x][y] = &grassTerrain_;16 }17 }18 }19 20 // Lay a river.21 int x = random(WIDTH);22 for (int y = 0; y < HEIGHT; y++) {23 tiles_[x][y] = &riverTerrain_;24 }25 }
获得(x,y)下的地形及属性:
1 const Terrain& World::getTile(int x, int y) const2 {3 return *tiles_[x][y];4 }5 int cost = world.getTile(2, 3).getMovementCost();
Chatper 4 观察者模式
观察者模式非常适合于一些不相关模块之间的通信(成就系统,新手引导)。
观察者:
1 class Observer 2 { 3 public: 4 virtual ~Observer() {} 5 virtual void onNotify(const Entity& entity, Event event) = 0; 6 }; 7 class Achievements : public Observer 8 { 9 public:10 virtual void onNotify(const Entity& entity, Event event)11 {12 switch (event)13 {14 case EVENT_ENTITY_FELL:15 if (entity.isHero() && heroIsOnBridge_)16 {17 unlock(ACHIEVEMENT_FELL_OFF_BRIDGE);18 }19 break;20 21 // Handle other events, and update heroIsOnBridge_...22 }23 }24 25 private:26 void unlock(Achievement achievement)27 {28 // Unlock if not already unlocked...29 }30 31 bool heroIsOnBridge_;32 };
被观察者:
1 class Subject 2 { 3 private: 4 Observer* observers_[MAX_OBSERVERS]; 5 int numObservers_; 6 }; 7 class Subject 8 { 9 public:10 void addObserver(Observer* observer)11 {12 // Add to array...13 }14 15 void removeObserver(Observer* observer)16 {17 // Remove from array...18 }19 20 // Other stuff...21 };22 class Subject23 {24 protected:25 void notify(const Entity& entity, Event event)26 {27 for (int i = 0; i < numObservers_; i++)28 {29 observers_[i]->onNotify(entity, event);30 }31 }32 33 // Other stuff...34 };
单链表写法(避免造成动态内存分配):
1 class Subject 2 { 3 Subject() 4 : head_(NULL) 5 {} 6 7 // Methods... 8 private: 9 Observer* head_;10 };11 class Observer12 {13 friend class Subject;14 15 public:16 Observer()17 : next_(NULL)18 {}19 20 // Other stuff...21 private:22 Observer* next_;23 };24 void Subject::addObserver(Observer* observer)25 {26 observer->next_ = head_;27 head_ = observer;28 }29 void Subject::removeObserver(Observer* observer)30 {31 if (head_ == observer)32 {33 head_ = observer->next_;34 observer->next_ = NULL;35 return;36 }37 38 Observer* current = head_;39 while (current != NULL)40 {41 if (current->next_ == observer)42 {43 current->next_ = observer->next_;44 observer->next_ = NULL;45 return;46 }47 48 current = current->next_;49 }50 }51 void Subject::notify(const Entity& entity, Event event)52 {53 Observer* observer = head_;54 while (observer != NULL)55 {56 observer->onNotify(entity, event);57 observer = observer->next_;58 }59 }
C#:event关键字,观察者成为一个代理。
原标题:《游戏编程模式》(2)
关键词: