C# 引擎脚本和类结构
我已经开始用C#/XNA编写2d JRPG引擎,我对类结构和游戏事件有一些疑问 在“game maker”类型的环境中,您有一个基于用户输入运行事件等的游戏脚本。这通常不是面向对象的,也没有对类等的引用 现在在我自己的引擎中,编码游戏事件的最佳方式是什么 假设您在屏幕上与NPC交互,那么在OO语言中如何处理该事件?我假设在character类中有一个事件,并且我假设该事件将被分配到加载地图的部分中,但是该事件将链接到哪里?哪个类将包含事件逻辑 编辑:我应该注意到,我不想把它变成一个完全可定制的引擎,供其他人使用,因此一个完整的脚本语言实现并不是我真正想要的C# 引擎脚本和类结构,c#,xna,C#,Xna,我已经开始用C#/XNA编写2d JRPG引擎,我对类结构和游戏事件有一些疑问 在“game maker”类型的环境中,您有一个基于用户输入运行事件等的游戏脚本。这通常不是面向对象的,也没有对类等的引用 现在在我自己的引擎中,编码游戏事件的最佳方式是什么 假设您在屏幕上与NPC交互,那么在OO语言中如何处理该事件?我假设在character类中有一个事件,并且我假设该事件将被分配到加载地图的部分中,但是该事件将链接到哪里?哪个类将包含事件逻辑 编辑:我应该注意到,我不想把它变成一个完全可定制的引
class Character {
...
public delegate void InteractionEventHandler(object sender, EventArgs e);
...
public event InteractionEventHandler Interact;
...
}
class Map {
public Map(){
...
//add a new character to the NPC collection
newchar.Interact += ???
...
}
}
目前我的类结构相当简单,因为我需要在进一步研究之前解决这个问题,但它看起来是这样的
Main类包含Map类的一个实例
Map类通过内容管道加载xml格式的地图
映射实例包含对映射中包含的所有对象和NPC的引用
Map类创建这些对象的新实例,这些实例都继承自Drawable类,该类包含将对象绘制到屏幕所需的基本方法和属性。这些实例都添加到Map类中的集合中
Character类是从Drawable类继承的类之一,将包含Interact事件
正如我所说的,该项目是基于固定时间步长的XNA框架的,因此引擎在主类中运行Update和Draw方法
update方法包含处理播放器输入的逻辑。因此,玩家可以移动到地图上的NPC并按下“交互”按钮。逻辑检查玩家面前的NPC并触发其交互事件。。。那么会发生什么呢?事件不应该附加任何逻辑;它们仅仅是一条信息,一种告诉感兴趣的组件发生了什么的技术,但如何处理事件是所述组件(又名监听器)的责任。在您的情况下,这就是您的NPC 但我不理解你关于“事件不是OO”的论点,是什么让你相信的?什么是不能面向对象的事件
现在如何处理事件和整个过程,我没有C语言的经验,但是我已经完成了C++的部分,这是我反复使用的一种方法,它对我的需求来说是足够灵活的:
我有一个事件元类,每个特定的事件都可以从中派生子类(即UI事件、NPC事件等)。还有一个EventManager,它创建和销毁所有事件(“发射器”,即需要触发事件的组件,将调用实例(即GameObjects)的管理器),最重要的是,它具有处理队列 发射器对象将把事件“挂钩”到队列,EventManager将把它们分派给“侦听器”。现在,侦听器对事件感兴趣,因此可以将自己注册到某些事件或其类型。一旦管理器将事件分派给这些侦听器,就由它们从那时起执行与该事件相关的逻辑 最终,拥有一个事件元类(我必须从中保持子类化)的设计对我来说不是很灵活,这是一项乏味的工作,因此我采用了另一种方法,可以将属性任意附加到事件对象,处理组件必须知道如何处理它。当然,这对性能有影响,但它对我来说是必要的,因为我触发和处理Lua中的事件逻辑,而不是C++。 如果你正在制作一个RPG游戏,事件和脚本几乎是游戏的主要部分,在开始编写代码之前,你需要对这两个方面进行清晰的设计。我建议先阅读关于事件处理的文章 最后,我不确定它是否会对您有所帮助,但我曾经在用C++/Lua制作网络游戏时发布过一次关于事件的帖子,考虑到网络游戏的性质,设计可能比您需要的更复杂,但您还是可以查看它 更新:我将向您展示一个如何使用我的系统的示例,但我必须首先明确:您使用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;
}
//单例
类事件管理器{
公众:
事件*createvt();
无效订阅(事件*,侦听器*);
无效挂钩(事件*);
无效更新();
}
类侦听器{
//告诉evt经理我们要收听这些事件
无效寄存器(事件*somevettype,处理程序*myMethod);
//将事件添加到队列(由EventManager调用)
无效排队(事件*somevt);
//处理队列中的事件
无效过程();
受保护的:
//调用每个订阅的处理程序来处理事件
//处理程序只是绑定到事件的函子
//调用“register()时”
无效派送(事件*);
map myHandlers;//一个事件可以有多个处理程序(方法)
}
类游戏对象:公共侦听器{
}
NPC类:公共游戏对象{
受保护的:
无效步行(NPCEvent_步行*evt);
无效谈话(NPCEvent_talk*evt);
}
//在你要触发事件的任何地方,我猜是在鼠标点击这里
void InputManager::mouseClicked(MouseEvent*evt){
//我们希望全国人大采取行动
NPCEvent_Walk*evtWalk=EventManager->createvt();
evtWalk->setX(…);
evtWalk->setY(…);
//说
NPCEvent_Talk*evtTalk=Ev