游戏设计模式 - 观察者模式

给出一个例子:

  小球砸在地面,达成一个成就“蛋疼”。砸在地面,听起来是需要物理引擎参与吧,但我们总不能在物理引擎计算各种力学公式的时候强行插入一个unlockEggPain()方法吧,观察者模式就出来有话说了。

def undateEntity(entity):
    entity.accelerate(GRAVITY)
    entity.update()
    if entity.IsOnSurface():
        notify(entity, EVENT_ON_FACE)

  这里,我们实现了某个东西砸在地上了,感兴趣的人自行关注。

  成就系统就可以注册自己进去,收到信息后检查是否和自己相关,有则进行运算,否则抛弃。这样成就系统和物理系统没进行耦合,任何一方的存亡也没另一边的关系。

 

如何实现:

  定义观察者

 

class ObSever:
    def onNotify(entity, event):
        pass

  继承obsever即可成为观察者,就是那么简单。

class Achievents(Obsever):
    def onNotify(entity, event):
        if event == EVENT_ON_FACE:
             self.Unlock(ACHIEVENT_EGG_PAIN)
        elif xxx:
            pass

此外,还得定义被观察的对象,称为客体

class Subject:
    def __init__(self):
        self.m_ObList = []
    
    def addObsever(obObj):
        self.m_ObList.append(obObj)
    
    def removeObsever(obObj):
        pass
    
    def notify(entity, event):
        for obObj in self.m_ObList:
            obObj.onNotify(entity, event)

通过注册本身进去,就可关注此类事件的发生。

使用列表存储观察者可避免观察者发生竞争,后续还有各种存储的方式,选择符合情况的即可。

物理引擎在合适的时机出发onNotify就可以通知观察者。

 

注意:

  1.观察者们在触发事件后会等待通知方法返回后才会执行其他工作,如果此方法内含有需要耗时很大的内容,容易导致ui卡死,所以通知方法应该尽快返回控制权,如需要进行此类工作,可开线程和工作队列完成

  2.如果观察者要获取客体的锁,容易导致游戏死锁,最好使用事件队列来做异步通信

  3.客体和观察者进行销毁时,都要向对方发送通知,例如c++如果观察者被注销却没告知客体,客体会向一片莫名的内存发起通告,就原地爆炸了。客体销毁也要通知下观察者。

  4.注册观察者最好是注册方法,而不是注册观察者实例本身,最好是使用弱引用,以免引发不必要的回收问题。拥有闭包能力的语言非常适合做此类工作,例如py,lua

posted on 2017-06-09 14:14  usp10  阅读(457)  评论(2编辑  收藏  举报

导航