Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/310.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在枚举中显式定义标志组合_C#_Enums_State_Flags_State Machine - Fatal编程技术网

C# 在枚举中显式定义标志组合

C# 在枚举中显式定义标志组合,c#,enums,state,flags,state-machine,C#,Enums,State,Flags,State Machine,我正在考虑实现一个定义游戏对象状态的枚举,我想知道我是否可以在枚举的定义中直接使用标志,而不是将对象的状态定义为一组标志,而不是为状态机中使用的状态定义一个简单的、预定义的全局名称 例如,假设有5种状态:预激活(创建但未启动;即未来浪潮中的敌人)、激活(当前正在使用;即屏幕上的敌人攻击你)、暂停(不再激活,但可能重新激活;即如果玩家使用时间冻结能力,则为敌人)、停用(已完成使用但仍在游戏世界中的对象;即死亡后留下身体的敌人,如《末日1&2》),以及ToRemove(预定从游戏中移除的对象;即清除

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

例如,假设有5种状态:预激活(创建但未启动;即未来浪潮中的敌人)、激活(当前正在使用;即屏幕上的敌人攻击你)、暂停(不再激活,但可能重新激活;即如果玩家使用时间冻结能力,则为敌人)、停用(已完成使用但仍在游戏世界中的对象;即死亡后留下身体的敌人,如《末日1&2》),以及ToRemove(预定从游戏中移除的对象;即清除一个关卡并移动到下一关卡后的敌人)

我想做的是定义枚举,使状态保留所有适用的标志;例如,停用的敌人: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
}
据我所知,这应该是正确的,但我有几个主要问题:

  • 这可能会带来什么问题
  • 这是坏习惯吗
  • 这是坏习惯吗?如果是;
    • 有什么问题吗
    • B.我应该怎么做呢?我只想让对象的状态成为这些标志的集合,但我想要一个特定状态的简写枚举,因为这允许特定实例的复杂性和需要时的简单性。有没有更可接受的方法来实现这一点

  • 很抱歉,如果这是一次重复或我违反了其他一些规则,但我今天刚刚创建了一个帐户;这是我的第一篇文章。另外,我不确定在搜索时你会如何称呼它,我也没有从这里或谷歌得到任何类似的点击。

    如果没有更多的上下文,很难真正知道,但您可能希望查看状态模式以获得更可扩展的信息和OO的做事方式

    它的工作方式是使游戏对象成为一个空壳,实现抽象游戏状态类所具有的相同接口。游戏对象将调用状态来执行接口指定的操作,而状态有一个对其包含的游戏对象的引用。当状态更改时,状态实例会告诉游戏对象

    例如,假设您的游戏对象有一个只包含一个方法“Attack”的接口。抽象状态类有两个具体的子类,Alive和Dead。Alive和Dead都实现了攻击。当有东西攻击您的游戏对象object.Attack();时,该对象内部只调用state.Attack()。活动状态将决定攻击是否成功,并执行parent.state=new DeadState();。再次调用攻击时,DeadState不执行任何操作

    这样你就避免了枚举、开关、IFS、一切,你只需添加游戏,而不需要进一步编程。你的“被激活”检查也将是一个接口方法。

    你是否考虑使用了?


    可以这样做。这正是标志枚举的要点。如果
    枚举
    要用作标志,请使用
    [flags]
    属性对其进行标记

    我建议将现有的标志与按位or(
    |
    )组合,这样可读性更强,也更不容易出错

    [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”后缀。

    只需将
    [flags]
    属性添加到枚举中,您就完成了,一点问题也没有。此外,您还可以使用
    (1)我在考虑使用This看起来非常混乱,我肯定认为这是一种不好的做法。为什么要将标志和状态混合在同一类型中?这很可能是不可读的,并且很难维护相关的源代码。当然,对于最后的值,最好使用除位移位以外的任何其他方法,但同样,这是对它的评论我更喜欢代码读取的方法。此外,使用混合标志和值只是偏好的问题,有人会告诉你这是一种不好的做法,其他人则是一种常见用法(每个状态机每个示例),所以它不太适合s.O.我只是从来没有见过这样做,在任何地方都找不到,所以我不确定这是否被普遍认为是不好的做法,或者是不常见的做法。我会再看看,但从我所看到的,我认为我通常的FSM创建方法对我来说更有效。我通常有一个列出了一些简单的状态;根据它是什么,这些方法的行为会略有不同(但不是完全不同)。此外,对象管理器和其他对象可以检查状态并从中做出决策(例如,我在Bullet类中使用了ToRemove状态,因此BulletManager知道将其从树中删除)。此外,我想知道这样使用枚举是否被认为是一种良好的做法,因为我计划在其他应用程序中使用它,如果是的话。是的,开关和if-else链通常是缺乏OO的标志。@JMor在您的情况下,应该有一些东西负责检测冲突。乍一看,我很想介绍PhysicEngine策略然后我会查看Rx中的反应性碰撞流,使所有对象成为潜在的订阅对象,并简单地调用所有参与对象上的碰撞。如果这导致移除,那么,为什么不呢。Ricochet()等等?@JMor使用世界这样的概念来描述世界的行为,而不是BulletManager。让Bullet对世界作出“反应”。所以,如果发生碰撞,让世界告诉Bullet发生了什么,让Bullet决定接下来会发生什么。如果Bullet需要世界的帮助来决定是。跳弹还是。移除,然后从世界到Bullet公开支持方法。Re广告设计模式GoF@JMorBulletManager是有问题的,因为它既避免将行为绑定到对象(封装),又向外界大量泄漏细节,
    
    [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
    }