设计精度的游戏趋向于事件驱动。即当一个事件发生了(发生了武器,扳动了手柄,一个犯错的警告等等), 事件被广播给游戏中有关的对象。这样它们可以恰当地做出反应。这些事件一般是以一个数据包的形式送出, 数据包包括关于事件的消息比如什么事件发送了它,什么对象应该对它做出反应,实际的事件是什么, 一个时间戳等等。
事件驱动结构被普遍选取的原因是因为它们是高效率的,没有事件处理,对象不得不持续地检测游戏世界来看是否有一个特定的行为已经发生了。 使用事件处理,对象
可以简单地继续它们自己的的工作,直到有一个事件消息广播给它们。
首先看下消息格式
struct Telegram
{
// 消息发送者,这里对应cocos2dx node中的Tag
int Sender;
// 消息接受者,同样对应cocos2dx node中的Tag
int Receiver;
// 消息类型
int Msg;
// 消息延迟时间
double DispatchTime;
// 额外信息块,用于传递额外信息
void* ExtraInfo;
Telegram():DispatchTime(-1),
Sender(-1),
Receiver(-1),
Msg(-1)
{}
Telegram(double time,
int sender,
int receiver,
int msg,
void* info = NULL): DispatchTime(time),
Sender(sender),
Receiver(receiver),
Msg(msg),
ExtraInfo(info)
{}
};
代码已经做了注释。
接下来看发送类
class MessageDispatcher
{
private:
// 使用标准容器set来存储消息队列
std::set<Telegram> PriorityQ;
std::set<Telegram> PriorityQ;
// 实现消息派送
void Discharge(BaseGameEntity* pReceiver, const Telegram& msg);
MessageDispatcher(){}
// 单例需要拷贝构造私有
MessageDispatcher(const MessageDispatcher&);
MessageDispatcher& operator=(const MessageDispatcher&);
public:
static MessageDispatcher* Instance();
// 发送一条消息
void DispatchMsg(double delay,
int sender,
int receiver,
int msg,
void* ExtraInfo);
// 消息驱动,需要在主循环中不断更新
void DispatchDelayedMessages();
};
void Discharge(BaseGameEntity* pReceiver, const Telegram& msg);
MessageDispatcher(){}
// 单例需要拷贝构造私有
MessageDispatcher(const MessageDispatcher&);
MessageDispatcher& operator=(const MessageDispatcher&);
public:
static MessageDispatcher* Instance();
// 发送一条消息
void DispatchMsg(double delay,
int sender,
int receiver,
int msg,
void* ExtraInfo);
// 消息驱动,需要在主循环中不断更新
void DispatchDelayedMessages();
};
可以看到, 消息派送就是维持了一个消息队列,根据消息设定的延迟时间(如果为0代表消息需要立即发送), 来不断派送信息。
我们知道,消息本身是不知道如何处理接受到信息的,为了能够处理消息【在cocos2dx 中】,我定义了一BaseGameEntity类
class BaseGameEntity: public cocos2d