有没有一种在C#中对System.Enum使用逻辑运算的好方法?

时间:2012-02-03 06:45:09

标签: c# enums

我正在玩一个小游戏来学习C#。作为其中的一部分,我将输入从设备映射到包含游戏内动作的枚举,从按钮字典,动作对定义。

例如,我有类似的东西:

[Flags]
enum Actions { None=0, MoveUp=1, MoveDown=2, MoveLeft=4, MoveRight=8 }

Actions currentActions;

private void SetActions()
{
 currentActions = Actions.None; 
 if (UpPressed)
     currentAction |= Actions.MoveUp;
 (etc)

}

public void Update()
{
 SetActions();
 if (currentActions & Actions.MoveUp) == Actions.MoveUp)
     MoveUp();
 (etc)
}

我根据输入设置动作,然后根据列表中的动作更新游戏的状态。

我想做的是,有一个新类,“ActionManager”,其中包含与动作相关的数据和方法;

public Enum currentActions;
public void SetActions();
public void UpdateActions();

和其他类,例如,对应于菜单的类,可以将它们自己的枚举添加到此全局枚举中,以便在负责处理输入的每个类内部定义每组可能的动作,而不是预定义在全球的枚举中。

但我不能这样做,因为我无法添加或删除枚举,我无法从System.Enum继承。我能想到的唯一方法是使用枚举列表:

// In class ActionManager
public List<Enum> allowedActions = new List<Enum>();
public List<Enum> currentActions = new List<Enum>();

public void SetActions(Enum action)
{
 currentActions.Clear();
 foreach (Enum e in allowedActions)
     if (IsKeyPressed(e))             
         currentActions.Add(e);
}

// In, say, GameMenu class
[Flags]
enum MenuActions { None=0, MenuUp = 1, ... }

private actionManager ActionManager = new ActionManager();

public void DefineActions()
{
 foreach (MenuActions m in Enum.GetValues(typeof(MenuActions)))
     actionManager.allowedActions.Add(m);
     //also define the key corresponding to the action 
     //here, from e.g., a config file
     //and put this into a Dictionary<buttons, actions>
}

public Update()
{
 actionManager.Update();

 if (actionManager.currentActions.Contains(MenuActions.MenuUp))
 (etc)
}

但这看起来很愚蠢,我用一个Enums列表取代了廉价的逻辑操作,这看起来很尴尬。它还迫使我使用.Contains等而不是算术,并使用值类型更有意义的引用类型(并且通用列表不应该暴露给外部)。

我意识到我也可以用int替换我的List,并将我所有其他类的枚举转换为int,这样我就可以或者一起行动,但是它没有枚举类型的安全性。

所以,我的问题是: 有没有办法用枚举做到这一点? 是否有一种更聪明的方法来做这种事情(无论是使用枚举还是其他方式)?

我这样做是为了学习这门语言,所以如果有更好的方法可以做这样的话,我会感激评论!

1 个答案:

答案 0 :(得分:3)

是;你可以使用位运算符:

Actions allowedActions = Actions.Up | Actions.Right;
allowedActions |= Actions.Down; // to show building at runtime
Actions currentActions = Actions.Right | Actions.Down; // union

然后使用各种& / | / ~来执行测试和更改:

var limitedToAllowed = currentActions & allowedActions; // intersect

// disallow "up" for some reason
allowedActions &= ~Actions.Up;

您可以通过以下方式测试重叠:

// test if **any** of the currentActions is in the allowedActions
bool anyAllowed = currentActions & allowedActions != 0;
// test if **all** of the currentActions are in the allowedActions
bool allAllowed = currentActions & allowedActions == currentActions;

关于“允许哪些值”的说明通常可以通过添加.All枚举(在您的情况下为15)或在运行时完成:

Actions actions = 0;
foreach(Actions action in Enum.GetValues(typeof(Actions))) {
    actions |= action;
}
// actions now has all the flags that are defined