在枚举

时间:2018-05-20 20:02:11

标签: c# enums state flags state-machine

我正在考虑实现一个定义游戏对象状态的枚举,我想知道我是否可以在枚举的定义中直接使用标志,而不是将对象的状态定义为标志的集合,不容易,状态机中使用的状态的预定义全局名称。

例如,假设有5种状态:PreActivation(创建但未启动;即未来波中的敌人),活动(当前正在使用;即屏幕上的敌人,攻击你),暂停(不再活跃的,但可能会重新激活;即如果玩家使用时间冻结的力量,则为敌人),DeActivated(已完成使用但仍在游戏世界中的物体;即死亡后身体遗留的敌人,如在毁灭战士1& 2)和ToRemove(一个用于从游戏中移除的物体;即在你清除一个等级并移动到下一个等级后的敌人)。

我想要做的是定义枚举,以便状态包含所有适用的标志;例如,DeActivated敌人:1。先前已被激活,2。目前尚未激活。我目前的想法是做这样的事情:

public enum ObjectState
{
    // The first section are the flags
    BeenActivated   = 0b0000001, // Previously activated
    CurrentlyActive = 0b0000010, // Currently activated
    IsSuspended     = 0b0000100, // It may be reactivated
    ShouldRemove    = 0b0001000, // It should be removed
    // These are the states
    PreActivation   = 0b0000100, // Mot currently active, nor has it ever been active, but it will get activated
    Active          = 0b0000011, // Currently active,     and it's been active
    Paused          = 0b0000101, // Not currently active, but it's been active before
    DeActivated     = 0b0000001, // Not currently active, but it's been active before, and it shouldn't get reactivated, but don't remove yet
    ToRemove        = 0b0001001  // Not currently active, but it's been active before, and it shouldn't get reactivated, it should be removed
}

据我所知,这应该可以正常工作,但我有几个主要问题:

  1. 这可能有什么问题吗?
  2. 这是不好的做法吗?
  3. 这是不好的做法吗?而且,如果是的话;
    • 甲。怎么了?
    • B中。我该怎么做呢?我只是让对象的状态成为这些标志的集合,但我想要一个特定状态的简写枚举,因为这允许特定实例的复杂性和需要时的简单性。是否有更可接受的方法来实现这一目标?
  4. 很抱歉,如果这是重复,或者我违反了其他规则,但我今天刚创建了一个帐户;这是我的第一篇文章。另外,我不确定在搜索时你会怎么称呼它,而且我没有从这里或谷歌获得任何类似的点击。

3 个答案:

答案 0 :(得分:13)

你可以这样做。它是旗帜枚举的重点。如果enum旨在用作标记,请使用[Flags]属性标记它。

我建议将现有标志与按位或(|)组合起来。它更具可读性且不易出错。

[Flags]
public enum ObjectState
{
    // Flags
    BeenActivated   = 0b0000001, // Previously activated
    CurrentlyActive = 0b0000010, // Currently activated
    IsSuspended     = 0b0000100, // It may be reactivated
    ShouldRemove    = 0b0001000, // It should be removed

    // States as combination of flags.
    PreActivationState   = IsSuspended,                     // Mot currently active, nor has it ever been active, but it will get activated
    ActiveState          = BeenActivated | CurrentlyActive, // Currently active,     and it's been active
    PausedState          = BeenActivated | IsSuspended,     // Not currently active, but it's been active before
    DeActivatedState     = BeenActivated,                   // Not currently active, but it's been active before, and it shouldn't get reactivated, but don't remove yet
    ToRemoveState        = BeenActivated | ShouldRemove     // Not currently active, but it's been active before, and it shouldn't get reactivated, it should be removed
}

我还添加了一个"州"州的后缀,以更好地区分它们与旗帜。或转过身来添加一个" Flags"而不是标志的后缀。

答案 1 :(得分:4)

您考虑使用[Flags]-enum吗?

[Flags]
public enum ObjectState
{
    BeenActivated   = 1, // Previously activated
    CurrentlyActive = 2, // Currently activated
    IsSuspended     = 4, // It may be reactivated
    ShouldRemove    = 8, // It should be removed
}

// Currently active, and it's been active
var active = ObjectState.BeenActivated | ObjectState.CurrentlyActive;

答案 2 :(得分:1)

如果没有更多的上下文,很难真正知道,但是您可能希望查看State Pattern以获得更具扩展性和OO的处理方式。

它的工作方式是让你的游戏对象成为一个空shell,实现抽象Game State类所做的相同界面。游戏对象将调用状态来执行接口指定的操作,而状态具有对其包含的游戏对象的引用。当状态改变时,状态实例告诉游戏对象。

因此,举例来说,让我们说你的游戏对象只有一个方法的接口,"攻击"。抽象状态类有两个具体的子类,Alive和Dead。 Alive and Dead也实施了Attack。当某些东西攻击你的游戏对象时,object.Attack(); ,对象内部只调用state.Attack()。 Alive状态将决定攻击是否成功并执行parent.State = new DeadState();.当再次调用攻击时,DeadState什么都不做。

这样你可以避免使用枚举,开关,ifs,所有内容,只需添加游戏状态而无需进一步编程。你的被激活了#34; check也是一种接口方法。