2012-02-03 117 views
1

我正在通过编写一个小游戏来学习C#。作为其中的一部分,我将来自设备的输入映射到包含游戏中操作的枚举,该操作由按钮,操作对的字典定义。有没有一种在C#中使用System.Enum的逻辑操作的好方法?

例如,我有这样的事情,示意:

[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) 
} 

但这似乎愚蠢的,我把它换成廉价的逻辑运算与枚举的列表,这似乎很尴尬。它也迫使我使用.Contains等,而不是算术,并使用引用类型,其中值类型更有意义(并且通用列表不应该暴露在外面)。

我知道我还可以用一个int代替我的名单,并投我的所有其他类的枚举到整数这样我就可以和动作组合,但是这并没有枚举类型安全。

所以,我的问题是: 有没有办法用枚举来做到这一点? 有没有更智能的方式来做这种事情(通常是枚举或其他方式)?

我这样做是为了学习语言,所以如果有更好的方法来做这样的事情,我将不胜感激!

回答

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)或者在IME:

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

是的,我知道我能做到位操作,但没有用它,在这里我想怎么办内的所有可能的行动,一个全球性的枚举,我不能做到这一点是有一个插件类级别的枚举到ActionManager类中 - ActionManager类将不会提前知道这些操作。 – JMP 2012-02-03 06:57:46

+0

@JMP你能澄清你的意思吗?当你使用'List '时,我看不出有什么不同......如果你的意思是“我想要所有枚举”,那么很简单 - 我将编辑... – 2012-02-03 07:30:41

相关问题