事件不应附加任何逻辑;它们只是一条消息,一种告诉感兴趣的组件发生了什么的技术,但如何处理该事件是所述组件(也称为监听器)的责任。在你的情况下,那是你的 NPC。
但我不明白你关于“事件不是 OO”的论点,是什么让你相信?不能面向对象的事件是怎么回事?
现在关于如何处理事件和整个过程,我没有使用 C# 的经验,但我已经在 C++ 中完成了我的分享,这是我反复使用的一种方法,它足够灵活,可以满足我的需求:
我有一个事件元类,每个特定事件都可以从它子类化(即,UI 事件、NPC 事件等)。还有一个 EventManager 可以创建和销毁所有事件(“发射器”,需要触发事件的组件,会为实例调用管理器,即 GameObjects),最重要的是,它具有处理队列。
Emitter 对象会将事件“挂钩”到队列中,EventManager 会将它们分派给“Listeners”。现在,监听器对事件感兴趣,因此可以将自己注册到某些事件或其类型。一旦管理器将事件分派给这些侦听器,就由他们来执行与该事件相关的逻辑。
最终,拥有一个我必须从中继承子类的事件元类的设计对我来说不是很灵活,而且这是一项乏味的工作,所以我采用了另一种方法,我可以将属性任意附加到事件对象,并且处理组件必须知道如何处理它。这当然会影响性能,但对我来说这是必要的,因为我在 Lua 而不是 C++ 中触发和处理事件逻辑。
如果您正在制作一款 RPG 游戏,那么事件和脚本几乎是您游戏的主体,在开始编写代码之前,您确实需要对这两个方面进行简洁的设计。我建议先阅读Gamedev.net 上的事件处理文章。
最后,我不确定它是否对您有帮助,但我曾在使用 C++/Lua 制作网络游戏时发布过一次有关事件的信息,考虑到网络的性质,设计可能比您需要的更复杂游戏,但无论如何你都可以查看here。
更新:我将向您展示如何使用我的系统的示例,但我必须首先明确:您使用 C# 和 XNA 是有原因的,而我不能误认为 XNA 提供的正是您所需要的,因此我建议不要使用我的事件管理系统或任何人的事件管理系统,因为我的事件管理系统与 C++ 及其模板机制紧密耦合,可能对您没有用处。该框架应该可以满足您的需求,因此请先检查一下。
// singleton
class EventManager {
public:
Event* createEvt<EventType*>();
void subscribe(Event*, Listener*);
void hook(Event*);
void update();
}
class Listener {
// tells evt manager we want to listen to these events
void register(Event* someEvtType, Handler* myMethod);
// adds event to the queue (called by the EventManager)
void enqueue(Event* someEvt);
// processes events in the queue
void process();
protected:
// calls every subscribed handler to process the event
// a handler is only a functor that is bound to an event
// when calling "register()"
void dispatch(Event*);
map<Event*, list<Handler*>> myHandlers; // an event could have multiple handlers (methods)
}
class GameObject : public Listener {
}
class NPC : public GameObject {
protected:
void walkTo(NPCEvent_Walk* evt);
void talk(NPCEvent_Talk* evt);
}
// inside wherever you're gonna trigger the event, i presumed on mouseclick here
void InputManager::mouseClicked(MouseEvent* evt) {
// we want the NPC to move
NPCEvent_Walk* evtWalk = EventManager->createEvt<NPCEvent_Walk>();
evtWalk->setX(...);
evtWalk->setY(...);
// and talk
NPCEvent_Talk* evtTalk = EventManager->createEvt<NPCEvent_Talk>();
evtTalk->setText(...);
// when the master queue is empty, these events will be
// dispatched to their registered Listeners which will
// process them on their own terms
EventManager->hook(evtWalk);
EventManager->hook(evtTalk);
}
// as an NPC, i'd like to be notified of NPCEvents
NPC::NPC() {
register(NPCEvent_Walk*, &NPC::walkTo);
register(NPCEvent_Talk*, &NPC::talk);
}
void NPC::walkTo(NPCEvent_Walk*) {
// move it
// ...
// are we done?
// return true;
// if we need more updates, return false and we will be called again
// return false;
}
void NPC::talk(NPCEvent_Talk*) {
// update UI components or whatever
// ...
return true;
}
显然,此代码将无法工作,因为它缺少所有实现细节,甚至在语法上也不正确,但它应该给你一个想法。但是,正如我上面所说,如果您使用 XNA,则不需要这样做。