我正在为游戏制作一个事件系统。我最初的解决方法是让一组监听器存储在一个地图中,其中一个字符串作为键(事件名称)和触发事件时的回调。这很好(在我看来,还没有进行过实际的测试),但没过多久就发现了一些缺陷。
然后我想到了一个奇怪的(在我心中)解决方案。使用枚举来分类和加快性能。
别担心我遇到了我的问题。
这是我设置枚举列表的方式:
struct Events
{
enum class Player {
Start = 1,
Shoot_arrow,
Reloading_bow,
Draw_Bow,
End
};
enum class Enemy {
Start = (int)Player::End+1,
Check_for_object,
Object_spotted,
Attacking_object,
End
};
enum class Car {
Start = (int)Enemy::End+1,
Starting_engine,
Out_of_gas,
Car_started,
End
};
};
使用此系统,如果我对事件进行“分类”,我可以使用更快的方式搜索事件。我正在考虑做一些事情,比如有一个地图,其中键是类别(每个类别的起始int),数据是另一个地图,在该映射中键是事件(int),数据是回调。通过这种方式,我可以快速找到该类别,然后搜索更少。这将是一个可以返回类别的单个函数:
if (event > Event::Enemy)
return Event::Bear::Start;
else if (event < Event::Enemy)
return Event::Player::Start;
else
return Event::Enemy::Start;
然后,您可以使用比搜索单个事件更小的可能性列表来搜索事件。唯一的缺点(我能想到的)是我将为每个类别进行的硬编码量。
现在,我的问题是,这是否是使用枚举的正确方法。我知道编译器不应该抛出任何错误,但是如果我要发布这个,那我就会徘徊认为编程不好。我试图避免尽可能不具有建设性,但由于这将是一个关键系统,我需要确保它不是一件坏事。
答案 0 :(得分:3)
我建议您在事件结构中发送信息,而不是在枚举名称中。
enum Player {/*...*/};
enum Action {Shoot, /*...*/};
enum Weapon {Bow_Arrow, /*...*/};
struct Event
{
Player receiving_player;
Action event_action;
Weapon event_weapon;
};
//...
Event e = {Enemy1, Shoot, Bow_Arrow};
Send_Events(e);
可以扩展此技术,例如拥有父事件或其他事件(例如移动)。
这里的概念是将信息放入变量而不是标识符名称。
编辑1:玩家接收敌人。
让我们在活动中添加另一个字段:
struct Event
{
Player sending_player;
Player receiving_player;
Action event_action;
Weapon event_weapon;
};
活动创建者将填写以下字段:
Event e = {Enemy1, Player2, Shoot, Bow_Arrow);
以上事件描述了Enemy1
Player2
从弓箭射箭的动作。
接下来要有一个事件处理程序将事件发送给零个或多个侦听器:
struct Event_Listener
{
virtual void receive_event(const Event& e) = 0;
};
typedef std::vector<Event_Listener *> Event_Listener_Container;
//...
Event_Listener_Container listeners;
Event_Listener_Container::iterator iter;
for (iter = listeners.begin();
iter != listeners.end();
++iter)
{
(*iter)->receive_event(e);
}
请记住,Listeners,Subscribers和Publishers有各种各样的实现。查看这些设计模式。
答案 1 :(得分:1)
恕我直言,你建议使用枚举闻到高天堂,这取决于我所谓的coding by coincidence
。它会很脆弱,一旦打破真的很难调试。
例如,假设我编写一个合理的(从语言的角度来看)更改为您的枚举:
struct Events
{
enum class Player {
Start = 1,
Shoot_arrow,
Reloading_bow,
Draw_Bow,
End = 0
};
enum class Enemy {
Start = (int)Player::End+1,
Check_for_object,
Object_spotted,
Attacking_object,
End
};
enum class Car {
Start = (int)Enemy::End+1,
Starting_engine,
Out_of_gas,
Car_started,
End
};
};
然后你的整个策略就是敬酒。你的代码不应该那么容易破解。