2012-05-28 4 views
1

Сначала я просто заявляю, что я использую одиночные игры, которые на самом деле не будут существовать на протяжении всего срока службы приложения. Это больше способ инкапсулировать то, что происходит от пользователя.Singleton & Inheritance C#

У меня есть несколько GameStates, например InGame или MainMenu, и у них есть довольно похожие вызовы функций, поэтому я решил использовать наследование для остановки копирования/вставки. Следующий код - это то, что у меня есть, но он не работает, как я предполагаю. Вот оно:

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) 
    { 

    } 
} 

Вы, наверное, можно сказать, что я хочу, чтобы иметь возможность использовать get и set из InGame в BaseState так Я могу просто вызвать Handle.Update(), и независимо от того, вызвал ли я его из InGame или Menu или что бы он знал, какой код использовать.

Очевидно, мне нужно освежить свои навыки OO. Но если кто-нибудь может предложить способ заставить это делать то, что я хотел бы, или предложить другой способ этого, я был бы благодарен. Благодарю.

+0

Где GameState определяется? И вы должны сделать функцию виртуальной, чтобы иметь возможность называть ее из базового класса, но запускать поведение производного класса (полиморфизм). Поэтому ваш сеттер/получатель должен быть виртуальным. Кроме того, 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

Ну, вы не можете переопределить статические элементы, поэтому я думаю, что ваш подход здесь неправильный. Вам лучше использовать фабричный или менеджерский класс (который мог бы использовать singleton для доступа к текущему экземпляру, если вам нужно), который даст вам доступ к текущему состоянию игры.

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

Вы можете получить доступ к Singleton, используя GameStateManager.Instance.

+1

Идея очень хорошая. Однако я думаю, что в этом случае есть небольшая проблема: переход из состояния игры в состояние паузы, например, отменяет предыдущее состояние. Это, конечно, не то, что вы ожидаете! Может быть, может быть введен стек состояния? Кроме того, метод его производного класса Update возвращает новый GameState, так что это будет state = Current.UpdateState (gameTime); и отбросить параметр GameState к методу ChangeState. –

+0

Это хорошие моменты. Я думаю, что стек является разумным подходом, поэтому вы можете добавить и удалить состояние (например, пример паузы, где у вас есть состояние Pause, нажатое вверху состояния InGame, чтобы нарисовать состояние паузы по состоянию в игре, и затем удалите его, когда проигрыватель отключится).В этом случае представляется, что аргумент контекста или состояния должен быть передан в метод «UpdateState», поэтому состояния могут связываться (например, состояние «Пауза» будет хотеть сообщать в состояние «InGame», что оно должно приостанавливать анимацию). – HackedByChinese