2012-05-28 87 views
1

首先,我將說明我使用的單身人士實際上並不會在整個應用程序生命週期中。這更多的是封裝用戶所發生的事情的一種方式。單身人士和繼承C#

我有幾個GameState,例如InGame或MainMenu,這些函數調用非常相似,所以我想用inheritence來停止複製/粘貼。下面的代碼就是我所擁有的,但它並不像我打算的那樣工作。那就是:

BaseState.cs

abstract class BaseState 
{ 
    protected static BaseState mHandle = null; 

    protected static BaseState Handle 
    { 
     get 
     { 
      return mHandle; 
     } 
     set 
     { 
      mHandle = value; 
     } 
    } 

    public static GameState UpdateState(GameTime gameTime) 
    { 
     GameState g = GameState.MainMenu; 

     try 
     { 
      Handle.Update(gameTime); 
     } 
     catch (Exception e) 
     { 

     } 

     return g; 
    } 

    public static void DrawState(GameTime gameTime, SpriteBatch spriteBatch) 
    { 
     Handle.Draw(gameTime, spriteBatch); 
    } 

    public static void Release() 
    { 
     mHandle = null; 
    } 

    protected abstract GameState Update(GameTime gameTime); 
    protected abstract void Draw(GameTime gameTime, SpriteBatch spriteBatch); 
} 

InGame.cs

class InGame : BaseState 
{ 
    private InGame() 
    { 

    } 

    protected static new BaseState Handle 
    { 
     get 
     { 
      if (mHandle == null) 
      { 
       mHandle = new InGame(); 
      } 

      return mHandle; 
     } 
     set 
     { 
      mHandle = value; 
     } 
    } 

    protected override GameState Update(GameTime gameTime) 
    { 
     return GameState.Quit; 
    } 

    protected override void Draw(GameTime gameTime, SpriteBatch spriteBatch) 
    { 

    } 
} 

你也許可以告訴我希望能夠使用的InGamegetsetBaseState如此我可以簡單地調用Handle.Update(),不管是從InGame還是Menu中調用它,或者不管它會知道使用哪個代碼。

顯然我需要刷新我的面向對象技能。但是,如果任何人都可以提出一種方法來讓它做我想做的事,或者提出一種不同的方式去實現它,我將不勝感激。謝謝。

+0

哪裏是遊戲狀態定義?你必須做一個虛擬函數才能夠從基類中調用它,但觸發派生類行爲(多態)。所以你的setter/getter應該是虛擬的。另外,InGame.Update只是返回GameState.Quit,是否有意? –

+0

GameState是一個簡單的枚舉。 是的,它現在故意返回GameState.Quit 它們不能是虛擬的,因爲它們是靜態的,我認爲它們是相互對立的?它至少給編譯錯誤;我嘗試了'new'關鍵字,因爲它好像是我想要的,並且它被編譯。沒有做我期望的。 – Luke

+0

我不認爲你需要一個單例,但簡單而簡單的多態。一個單例意味着只有一個類型的實例可以在任何時候存在,但在你的情況下,我相信多個狀態可以共存。考慮一下,當你從遊戲狀態轉到菜單狀態並返回時,你不會期望你的遊戲實例被破壞,但是你必須使用一個單例。 –

回答

3

什麼你正在努力實現並不需要一個單身,見下圖:

public abstract class BaseState 
{ 
    public GameState UpdateState(GameTime gameTime) 
    { 
     GameState g = GameState.MainMenu; 

     try 
     { 
      g = Update(gameTime); // Update returns a new state 
     } 
     catch (Exception e) 
     { 

     } 

     return g; 
    } 

    protected abstract GameState Update(GameTime gameTime); 
    protected abstract void Draw(GameTime gameTime, SpriteBatch spriteBatch); 
} 

public class InGame : BaseState 
{ 
    public InGame() 
    { 

    } 

    protected override GameState Update(GameTime gameTime) 
    { 
     return GameState.Quit; 
    } 

    protected override void Draw(GameTime gameTime, SpriteBatch spriteBatch) 
    { 
     // Draw game 
    } 
} 

public class InMenu : BaseState 
{ 
    public InMenu() 
    { 

    } 

    protected override GameState Update(GameTime gameTime) 
    { 
     return GameState.Pause; 
    } 

    protected override void Draw(GameTime gameTime, SpriteBatch spriteBatch) 
    { 
     // Draw menu 
    } 
} 

public void Foo() 
{ 
    List<BaseState> states = new List<BaseState>(); 
    states.Add(new InGame()); 
    states.Add(new InMenu()); 

    // Calls InGame.Update(...) 
    states[0].UpdateState(...); 

    // Calls InMenu.Update(...) 
    states[1].UpdateState(...); 
} 
+0

是的,這和我原來的一樣,但是這意味着當你在遊戲中時,你並不需要內存中的主菜單,那麼在整個遊戲中每個狀態都是持久的。靜態函數的想法是自動分配和釋放資源類型,或者至少隱藏它。我將它移入主Game1文件並使用普通的舊多態。 – Luke

+1

如果菜單佔用大量內存,請添加一個「ReleaseContent」方法,在該方法中放棄可以快速從磁盤重新加載的所有內存不足變量。 –

2

那麼,你不能重載靜態成員,所以我認爲你的方法是錯誤的。你最好使用工廠或管理員類(如果需要,可以使用單例訪問當前實例),從而使您可以訪問當前的遊戲狀態。

public class GameStateManager 
{ 
    private static GameStateManager _instance = new GameStateManager(); 

    public static GameStateManager Instance { get { return _instance; } } 

    public BaseState Current { get; private set; } 

    public GameStateManager() 
    { 
     Current = new InGame(); 
    } 

    public void ChangeState(GameState state, GameTime gameTime) 
    { 
     // change your current state here, I'm not really sure about your logic here 
     Current.UpdateState(gameTime); 

     switch(state) 
     { 
      case GameState.Menu: 
       Current = new MainMenu(); 
      // etc. 
      default: 
       throw new NotImplementedException(string.Formatted("The state {0} is not implemented.", state)); 
     } 
    } 
} 

您可以使用GameStateManager.Instance訪問單身人士。

+1

這個想法非常好。不過,我認爲在這種情況下存在一個小問題:例如,從遊戲狀態進入暫停狀態,將取消分配先前的狀態。這當然不是你期望的!也許可以引入狀態堆棧? 另外,他的派生類Update方法返回一個新的GameState,所以它會是state = Current.UpdateState(gameTime);並將GameState參數放到ChangeState方法中。 –

+0

這些都是好點。我認爲堆棧是一種合理的方法,因此您可以添加並刪除一個狀態(例如您的暫停示例,在InGame狀態之上推入暫停狀態以在遊戲狀態中繪製暫停狀態,以及然後在玩家取消暫停時將其刪除)。在這種情況下,似乎應該將一個上下文或狀態參數傳遞給'UpdateState'方法,以便狀態可以進行通信(例如,暫停狀態將要通知InGame狀態它應該暫停動畫)。 – HackedByChinese