网游中,事件系统是一个不可或缺的模块。可以很方便的处理一些事件:比如杀怪,采集等。
同时也是降低模块之间耦合度的一个好办法。下面就来实现一个事件系统。
声明:很多人一看到事件系统,就联想到UI库中的事件驱动。我不得不告诉你,这是网游,不是UI。
本事件系统从设计上就是为网游服务器服务的,并不一定适合UI,网游的事件也并不复杂,也不需要上下层分发事件等。
一个事件,典型的表现就是:发生了某某事件,判断执行条件,如果满足,就执行某某行为。
在具体网游开发中,甚至会设计的更简单,发生了某某事件,执行某某函数。
1、事件区分同步还是异步。当然了,也可以将bSync换成一个整数,表示优先级。然后FireEvent的时候,按照事件的优先级来执行。
不过,我感觉这个用处不大,至少目前没看到。所以就只区分了同步还是异步
2、FireEvent最后,需要执行异步处理的时候,需要一个定时器,保证函数在下一个周期执行。我这里没有写出。因为定时器的代码还没整理好。
3、回调函数是可以包装一次的,这样的话,监听的时候就可以传入参数了。
4、之所以事件在初始化的时候,需要传入一个ID,目的是将事件分散开。如果事件系统全局只有一个,那么这个事件字典会异常的庞大。
有玩家的,有怪物的,查询起来会很耗时。所以,我希望的是,每个生物类中挂接一个事件系统。自己监听自己的事件。然后保持一个全局的事件系统,
当单个生物的事件无法实现时,就可以用全局事件来实现。
5、事件增删时,应该尽量在FireEvent之外执行,不要在事件触发的过程中进行增删事件。这个有待完善。
一个最简单的事件系统,就是这样了。
同时也是降低模块之间耦合度的一个好办法。下面就来实现一个事件系统。
声明:很多人一看到事件系统,就联想到UI库中的事件驱动。我不得不告诉你,这是网游,不是UI。
本事件系统从设计上就是为网游服务器服务的,并不一定适合UI,网游的事件也并不复杂,也不需要上下层分发事件等。
一个事件,典型的表现就是:发生了某某事件,判断执行条件,如果满足,就执行某某行为。
在具体网游开发中,甚至会设计的更简单,发生了某某事件,执行某某函数。
#目前支持的事件列表
g_EventList = ("获得物品",)
class CEventMgr:
def __init__(self, iID):
self.m_ID = iID
self.m_EventDict = {} #事件监听器管理
def AddEvent(self, sEventName, bSync, cbFunc):
"""
添加事件监听器
@param sEventName:string,事件名称
@param bSync:bool,是否同步处理
@param cbFunc:function,回调函数
"""
global g_EventList
if not sEventName in g_EventList:
raise "事件%s不支持,请检查" % sEventName
tInfo = (bSync, cbFunc)
tEventList = self.m_EventDict.get(sEventName, [])
if tInfo in tEventList:
raise "事件%s %s 重复注册,请检查" % (sEventName, tInfo)
tEventList.append(tInfo)
self.m_EventDict[sEventName] = tEventList
def RemoveEvent(self, sEventName, bSync, cbFunc):
"""
删除事件监听器
@param sEventName:string,事件名称
@param bSync:bool,是否同步处理
@param cbFunc:function,回调函数
"""
tInfo = (bSync, cbFunc)
if not sEventName in self.m_EventDict:
return
tEventList = self.m_EventDict[sEventName]
if not tInfo in tEventList:
return
tEventList.remove(tInfo)
self.m_EventDict[sEventName] = tEventList
def FireEvent(self, sEventName, *args):
"""
触发事件
@param sEventName:string,事件名称
@param args:tuple,事件参数
"""
tEventList = self.m_EventDict.get(sEventName, [])
if not tEventList:
return
for tEvent in tEventList:
bSync, cbFunc = tEvent
#过滤掉异步监听
if not bSync:
continue
cbFunc(*args)
#在下一个周期中执行异步监听的触发
#self.FireEventAsync(sEventName, *args)
def FireEventAsync(self, sEventName, *args):
tEventList = self.m_EventDict.get(sEventName, [])
if not tEventList:
return
for tEvent in tEventList:
bSync, cbFunc = tEvent
if bSync:
continue
cbFunc(*args)
够简单吧。
1、事件区分同步还是异步。当然了,也可以将bSync换成一个整数,表示优先级。然后FireEvent的时候,按照事件的优先级来执行。
不过,我感觉这个用处不大,至少目前没看到。所以就只区分了同步还是异步
2、FireEvent最后,需要执行异步处理的时候,需要一个定时器,保证函数在下一个周期执行。我这里没有写出。因为定时器的代码还没整理好。
3、回调函数是可以包装一次的,这样的话,监听的时候就可以传入参数了。
4、之所以事件在初始化的时候,需要传入一个ID,目的是将事件分散开。如果事件系统全局只有一个,那么这个事件字典会异常的庞大。
有玩家的,有怪物的,查询起来会很耗时。所以,我希望的是,每个生物类中挂接一个事件系统。自己监听自己的事件。然后保持一个全局的事件系统,
当单个生物的事件无法实现时,就可以用全局事件来实现。
5、事件增删时,应该尽量在FireEvent之外执行,不要在事件触发的过程中进行增删事件。这个有待完善。
一个最简单的事件系统,就是这样了。