游戏中的观察者模式

“在对象间定义一种一对多的依赖关系,以便当某对象的状态改变时,与它存在依赖关系的所有对象都能收到通知并自动进行更新。”

经典的就是解锁成就

void Physics::updateEntity(Entity& entity) 
{
 bool wasOnSurface = entity.isOnSurface();
 entity.accelerate(GRAVITY);
 entity.update();
 if (wasOnSurface && !entity.isOnSurface())
 {
  notify(entity, EVENT_START_FALL);
 }
}

利用事件类型,通知到观察者。多个地方写通知事件就好了,不用没出都直接调用或硬编码一些内容。

观察者

接收事件的对象

class Observer
{
public: 
 virtual ~Observer() {}
 virtual void onNotify(const Entity& entity,   
                 Event event) = 0; 
};

class Achievements : public Observer
{
public:
 virtual void onNotify(const Entity& entity,
              Event event)
 {
  switch (event)
  {
  case EVENT_ENTITY_FELL:
   if (entity.isHero() && heroIsOnBridge_)
   {
    unlock(ACHIEVEMENT_FELL_OFF_BRIDGE);
   }
   break;

   //Handle other events...


   // Update heroIsOnBridge_...


  }
 }

private:
 void unlock(Achievement achievement)
 {
  // Unlock if not already unlocked...


 }

 bool heroIsOnBridge_;
};

被观察者

发出事件的对象

class Subject
{
private: 
 Observer* observers_[MAX_OBSERVERS]; 
 int numObservers_;
};

class Subject
{
public:
 void addObserver(Observer* observer)
 {
    //Add to array...
 }

 void removeObserver(Observer* observer)
 {
   //Remove from array..
 }

   //Other stuff...

};

被观察者发出事件通知观察者

class Subject
{
protected:
 void notify(const Entity& entity, Event event)
 {
  for (int i = 0; i < numObservers_; i++)
  {
   observers_[i]->onNotify(entity, event);
  }
 }
 // Other stuff...


};

链式观察者

上面Subject里用指针数组来保存观察者,还可以用链表

class Subject
{
 Subject()
 : head_(NULL)
 {}

 // Methods...


private:
 Observer* head_;
};
class Observer
{
 friend class Subject;

public:
 Observer()
 : next_(NULL)
 {}

 // Other stuff...


private:
 Observer* next_;
};

具体链表插入删除省略,遍历链表。

还可以用双向链表。

链表节点池

考虑到这一般都是极致优化才要做的,节点对象预分配,用对象池可以达到对象复用,加快内存分配和回收。