2017-06-05 75 views
2

我正在爲Xamarin中的android遊戲工作,但我有兩個特別的部分是極端乾的(不要重複自己)。如何檢查沒有多個if語句的條件?

第一部分是當我想要改變音軌(audioplay)或背景,其中我有三個不同音高的基於水平的相同音軌,而背景畫布交替出現的背景也相同。

對於這些方法的條件是基於等於水平播放器處於一個整數水平。

實施例代碼

private void SetBackgrounds() 
{ 
    if (level == 5) 
    { 
     gameAreaCanvas.SetBackgroundResource(Resource.Drawable.LevelUpOneBackground); 

    } 
    else if (level == 10) 
    { 
     gameAreaCanvas.SetBackgroundResource(Resource.Drawable.LevelUpTwoBackground); 

    } 
    else if (level == 15) 
    { 
     gameAreaCanvas.SetBackgroundResource(Resource.Drawable.LevelUpThreeBackground); 

    } 
} 

這同樣適用於所述代碼的不同部分,其中很多是基於在一個整數值,這是水平。玩家每次將級別整數增量提高1,然後該活動具有檢查整數級別的方法。代碼正在工作,但顯然效率很低,因爲有很多重複的代碼和一個小的調整。

例如水平看起來是這樣的。

 if(level == 1) { 

      levelDisplay.Text = "LEVEL 1"; 
      timer = new Timer(); 
      timer.Interval = 2000; /// DIFFERENT 
      timer.Enabled = true; 
      timer.Elapsed += Level1; /// DIFFERENT 
      timer.Start(); 
     } 
     ///LEVEL 2 
     if (level == 2) 
     { 
      levelDisplay.Text = "LEVEL 2"; 
      timer = new Timer(); 
      timer.Interval = 2000; /// DIFFERENT 
      timer.Enabled = true; 
      timer.Elapsed += Level2; /// DIFFERENT 
      timer.Start(); 
     } 

有沒有辦法讓這段代碼少幹?輸入讚賞。

+1

有關使用開關的情況下怎麼辦? –

+1

僅供參考,設置'timer.Enabled = true;'與'timer.Start();'相同。請參閱:[Timer.Enabled屬性文檔](https://msdn.microsoft.com/en-us/library/system.timers.timer.enabled(v = vs.110).aspx) –

+0

@RufusL不知道那個,謝謝。 – Eli

回答

1

您是否在尋找一個字典

//TODO: please, check dictionary's value type 
private static Dictionary<int, Resource.Drawable> s_Backgrounds = 
    new Dictionary<int, Resource.Drawable>() { 
    {5, Resource.Drawable.LevelUpOneBackground}, 
    {10, Resource.Drawable.LevelUpTwoBackground}, 
    {15, Resource.Drawable.LevelUpThreeBackground}, 
}; 

... 

private void SetBackgrounds() { 
    gameAreaCanvas.SetBackgroundResource(s_Backgrounds[level]); 
} 

編輯:用level同樣的想法;唯一的區別是你有對應於每個鍵的三個值。最簡單的辦法是將這些值整理成Tuple(一定製類將是一個更好的選擇,不過):

// I've used Tuple<string, int, int> to store three values 
// you may want to change it to a custom class 
private static Dictionary<int, Tuple<string, int, int>> s_Levels = 
    new Dictionary<int, Tuple<string, int, int>>() { 
    {1, new Tuple<string, int, int>("LEVEL 1", 2000, Level1)}, 
    {2, new Tuple<string, int, int>("LEVEL 2", 2000, Level2)}, 
}; 

... 

levelDisplay.Text = s_Levels[level].Item1; 
timer = new Timer(); 
timer.Interval = s_Levels[level].Item2; /// DIFFERENT 
timer.Enabled = true; 
timer.Elapsed += s_Levels[level].Item3; /// DIFFERENT 
imer.Start(); 
+0

這是一個有趣的解決方案!編輯:你是否對這些關卡有任何建議,或者切換案例是唯一的選擇? – Eli

+0

@Eli:在Tuple <>'的幫助下(自定義類將是更好的解決方案,但是)您可以創建多個(在您的情況下爲三個)值的字典。看我的編輯。 –

+0

我喜歡第一個解決方案,但你有點失去了我的元組......也許我需要更多地關注它。 – Eli

0

他們被稱爲switch語句,它們是這樣的:

switch(level) 
{ 
    case 1: 
    doLevel1(); 
    break; 
    case 2: 
    doLevel2(); 
    break; 
} 

更多信息可以在這裏找到:Switch Statement Tutorial

+0

這是我一直在尋找的解決方案,但代碼量似乎並未減少。我有時達到25個級別,是寫25個開關盒的唯一解決方案嗎? – Eli

+0

在你的情況下,最好的解決方案是switch語句,即使你必須寫25個開關情況。 – fn5341

+0

@ fn5341我認爲在這種情況下,最好的解決方案是使用Map(C#中的字典)。沒有switch語句,乾淨而強大。 – BackSlash

2

第一部分可如下濃縮:

canvas.SetBackgroundResource(level == 5? Resource.Drawable.LevelUpOneBackground : 
           level = 10? Resource.Drawable.LevelUpTwoBackground : 
              Resource.Drawable.LevelUpThreeBackground); 

或者,更好的是,創建一個字典,映射級別的數字到背景,所以你可以有這個:

gameAreaCanvas.SetBackgroundResource(resourcesFromLevels[level]); 

簡化sec ond部分有點涉及。

在這樣的情況下,一個可行的方案是繼承。

你做一個新的抽象class Level來代表你的遊戲水平,你創建該類的每個特定級別的子類。所以,你會有class Level1: Level,class Level2: Level等等。基類有一個Setup()方法,它通過調用自身的可重寫對象來工作,並且每個可重寫對象都有一個默認實現,但Level的後裔可以提供它們自己的實現。

此外,並非所有事情都必須由overridables處理。 Level類可以接受一些構造函數參數,例如關卡名稱,然後每個後代都可以向基類提供正確的關卡名稱。因此,它應該是這樣的:

class Level 
{ 
    readonly string levelName; 

    Level(String levelName) 
    { 
     this.levelName = levelName; 
    } 

    void Setup() 
    { 
     levelDisplay.Text = levelName; 
     SetupTimer(); 
    } 

    virtual void SetupTimer() 
    { 
     //Default implementation 
    } 
} 

class Level1: Level 
{ 
    Level1() : Level("LEVEL 1") 
    { 
    } 

    override void SetupTimer() 
    { 
     //Level1 implementation 
    } 
} 
+0

有趣的解決方案。試圖找出解決方案來整合計時器與此解決方案。 – Eli

0

我會讓你的「水平」更面向對象:

public LevelObject 
{ 
    public BackgroundResource BackgroundResource { get; set; } 
    public string Text { get; set; } 
    public double TimeInterval { get; set; } 
    public double ElapsedInterval { get; set; } 

    // constructors, methods, etc... 
} 

這樣,您就可以初始化「級別」的集合,像List<LevelObject>,然後根據您目前level,設置任何必要的屬性:

int level = // current level 
List<LevelObject> levelObjectList = 
    new List<LevelObject> 
    { 
     new LevelObject("LEVEL 1", 2000, Level1), 
     new LevelObject("LEVEL 2", 2000, Level2), 
     // etc... 
    } 
LevelObject levelObject = levelObjectList[level]; 

Ë xamples:

private void SetBackgrounds(LevelObject levelObject) 
{ 
    if (levelObject.BackgroundResource != null) 
    { 
     gameAreaCanvas.SetBackgroundResource(levelObject.BackgroundResource); 
    } 
} 

levelDisplay.Text = levelObject.Text; 
timer = new Timer(); 
timer.Interval = levelObject.TimeInterval; 
timer.Enabled = true; 
timer.Elapsed += levelObject.ElapsedInterval; 
timer.Start(); 
0

我會走這條路:

首先,你需要一種枚舉的

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Reflection; 

namespace ConsoleApp1 
{ 
    public class MyEnumeration 
    { 
     #region Private Fields 

     private readonly string _displayName; 
     private readonly int _value; 
     private readonly int _interval; 
     private readonly Action _action; 

     #endregion Private Fields 

     #region Protected Constructors 

     protected MyEnumeration() 
     { 
     } 

     protected MyEnumeration(int value, string displayName, int interval, Action action) 
     { 
      _value = value; 
      _displayName = displayName; 
      _interval = interval; 
      _action = action; 
     } 

     #endregion Protected Constructors 

     #region Public Properties 

     public string DisplayName 
     { 
      get { return _displayName; } 
     } 

     public int Value 
     { 
      get { return _value; } 
     } 

     public int Interval 
     { 
      get { return _interval; } 
     } 

     public Action Action 
     { 
      get { return _action; } 
     } 

     #endregion Public Properties 

     #region Public Methods 

     public static int AbsoluteDifference(MyEnumeration firstValue, MyEnumeration secondValue) 
     { 
      var absoluteDifference = Math.Abs(firstValue.Value - secondValue.Value); 
      return absoluteDifference; 
     } 

     public static T FromDisplayName<T>(string displayName) where T : MyEnumeration, new() 
     { 
      var matchingItem = parse<T, string>(displayName, "display name", item => item.DisplayName == displayName); 
      return matchingItem; 
     } 

     public static T FromValue<T>(int value) where T : MyEnumeration, new() 
     { 
      var matchingItem = parse<T, int>(value, "value", item => item.Value == value); 
      return matchingItem; 
     } 

     public static IEnumerable<T> GetAll<T>() where T : MyEnumeration, new() 
     { 
      var type = typeof(T); 
      var fields = type.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly); 

      foreach (var info in fields) 
      { 
       var instance = new T(); 
       var locatedValue = info.GetValue(instance) as T; 

       if (locatedValue != null) 
       { 
        yield return locatedValue; 
       } 
      } 
     } 

     public int CompareTo(object other) 
     { 
      return Value.CompareTo(((MyEnumeration)other).Value); 
     } 

     public override bool Equals(object obj) 
     { 
      var otherValue = obj as MyEnumeration; 

      if (otherValue == null) 
      { 
       return false; 
      } 

      var typeMatches = GetType().Equals(obj.GetType()); 
      var valueMatches = _value.Equals(otherValue.Value); 

      return typeMatches && valueMatches; 
     } 

     public override int GetHashCode() 
     { 
      return _value.GetHashCode(); 
     } 

     public override string ToString() 
     { 
      return DisplayName; 
     } 

     #endregion Public Methods 

     #region Private Methods 

     private static T parse<T, K>(K value, string description, Func<T, bool> predicate) where T : MyEnumeration, new() 
     { 
      var matchingItem = GetAll<T>().FirstOrDefault(predicate); 

      if (matchingItem == null) 
      { 
       var message = string.Format("'{0}' is not a valid {1} in {2}", value, description, typeof(T)); 
       throw new ApplicationException(message); 
      } 

      return matchingItem; 
     } 

     #endregion Private Methods 
    } 

}

然後你可以創建您自己的枚舉類似於:

using System; 

namespace ConsoleApp1 
{ 
    internal class LevelEnum : MyEnumeration 
    { 
     public static readonly LevelEnum Level1 = new LevelEnum(1, "Level 1", 2000, Program.Level1); 
     public static readonly LevelEnum Level2 = new LevelEnum(2, "Level 2", 3000, Program.Level2); 
     public static readonly LevelEnum Level3 = new LevelEnum(3, "Level 3", 4000, Program.Level3); 
     public static readonly LevelEnum Level4 = new LevelEnum(4, "Level 4", 5000, Program.Level4); 
     public static readonly LevelEnum Level5 = new LevelEnum(5, "Level 5", 6000, Program.Level5); 
     public static readonly LevelEnum Level6 = new LevelEnum(6, "Level 6", 7000, Program.Level6); 
     public static readonly LevelEnum Level7 = new LevelEnum(7, "Level 7", 8000, Program.Level7); 
     public static readonly LevelEnum Level8 = new LevelEnum(8, "Level 8", 9000, Program.Level8); 

     public LevelEnum() 
     { 
     } 

     protected LevelEnum(int value, string displayName, int interval, Action action) : base(value, displayName, interval, action) 
     { 
     } 
    } 
} 

,你可以用它喜歡:

private static void Main(string[] args) 
{ 
    int level = 5; 
    LevelEnum levelEnum = MyEnumeration.FromValue<LevelEnum>(level); 

    levelDisplay.Text = levelEnum.DisplayName; 
    timer = new Timer(); 
    timer.Interval = levelEnum.Interval; 
    timer.Enabled = true; 
    timer.Elapsed += levelEnum.Action; 
    timer.Start(); 
} 

internal static void Level1() 
{ 
    // Action for Level 1 
} 

internal static void Level2() 
{ 
    // Action for Level 2 
} 

internal static void Level3() 
{ 
    // Action for Level 3 
}