使用枚举错误的方法?

时间:2014-11-17 21:54:48

标签: c++ enums

我正在为游戏制作一个事件系统。我最初的解决方法是让一组监听器存储在一个地图中,其中一个字符串作为键(事件名称)和触发事件时的回调。这很好(在我看来,还没有进行过实际的测试),但没过多久就发现了一些缺陷。

  1. 速度 - 我希望这是一款中型游戏。这意味着100名“听众”在等待不同的事件。调用事件后,搜索必须遍历每个侦听器字符串名称才能找到匹配项。将尽可能快地发送和处理大量事件,以避免在每个帧中一直占用。
  2. 命名 - “ Shoot_arrow_player ”,“ Shoot_arrow_ai ”,“ Shoot_arrow_player3 ”。这不是一个非常简单的系统,必须记住每个事件名称,并且可能很容易打字错误并进行烦人的调试。
  3. 然后我想到了一个奇怪的(在我心中)解决方案。使用枚举来分类和加快性能。

    别担心我遇到了我的问题。

    这是我设置枚举列表的方式:

    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;
    

    然后,您可以使用比搜索单个事件更小的可能性列表来搜索事件。唯一的缺点(我能想到的)是我将为每个类别进行的硬编码量。

    现在,我的问题是,这是否是使用枚举的正确方法。我知道编译器不应该抛出任何错误,但是如果我要发布这个,那我就会徘徊认为编程不好。我试图避免尽可能不具有建设性,但由于这将是一个关键系统,我需要确保它不是一件坏事。

2 个答案:

答案 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
    };
};

然后你的整个策略就是敬酒。你的代码不应该那么容易破解。