2012-02-03 4 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などを使用し、値の型がより意味のある参照型を使用するようにします(そして、汎用リストは外部に公開されるべきではありません)。

Listをintに置き換えて、他のすべてのクラスの列挙型をintにキャストして、一緒にやりこなすこともできるが、列挙型の型の安全性はない。

私の質問は次のとおりです。 enumでこれを行う方法はありますか? 一般的に(enumや他の方法で)このようなことを行うよりスマートな方法はありますか?

私は言語を学ぶためにこれをやっているので、このようなことをするより良い方法があればコメントをいただきたいと思います!

答えて

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)を追加するか、またはrunt 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

+0

@JMPあなたは何を意味するのかを明確にすることができますか?'List 'を使っているときにどう違うのかは分かりません。単に "すべての列挙型が欲しい"という意味なら、簡単です - 私は編集します... –

関連する問題