在枚举中明确定义标志组合

Explicitly defining flag combinations in an enum

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

例如,假设有 5 种状态:PreActivation(已创建但未开始;即未来 wave 中的敌人)、Active(当前正在使用;即屏幕上的敌人正在攻击您)、Paused(不再活跃,但可能会重新激活;即如果玩家使用时间冻结能力,则为敌人),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. 这是不好的做法吗?而且,如果是的话;
    • 一个。怎么了?
    • 乙。我应该怎么做?我只想让对象的状态成为这些标志的集合,但我想要一个针对特定状态的 shorthand 枚举,因为这允许特定实例的复杂性和需要时的简单性。有没有更容易接受的方法来实现这个?

抱歉,如果这是重复或我违反了其他规则,但我今天刚创建了一个帐户;这是我的第一个 post。另外,我不确定你在搜索时会怎么称呼它,而且我没有从这里或 Google.

得到任何类似的匹配。

如果没有更多的上下文,很难真正知道,但您可能希望研究状态模式以获得更可扩展和面向对象的做事方式。

它的工作方式是将游戏对象设为空 shell,实现与抽象游戏状态 class 相同的接口。游戏对象将调用状态来执行接口指定的操作,而状态具有对其包含的游戏对象的引用。当状态改变时,状态实例告诉游戏对象。

例如,假设您的游戏对象有一个只有一个方法的接口,"Attack"。抽象状态 class 有两个具体的子 class 实体,Alive 和 Dead。 Alive 和 Dead 都实现了 Attack。当有东西攻击你的游戏对象时,object.Attack(); ,对象内部只调用 state.Attack()。 Alive 状态将决定攻击是否成功并执行 parent.State=new DeadState();。当再次调用 attack 时,DeadState 什么都不做。

这样您就可以避免枚举、开关、ifs 等所有内容,您只需添加游戏状态而无需进一步编程。您的 "been activated" 检查也将是一种接口方法。

您考虑过使用 [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;

你可以这样做。这是标志枚举的重点。如果 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
}

我还为各州添加了一个 "State" 后缀,以更好地将它们与旗帜区分开来。或者反过来,为标志添加 "Flags" 后缀。