using System; using System.Collections.Generic; using System.Drawing; using System.Threading; using SlatedGameToolkit.Framework.Graphics.Window; using SlatedGameToolkit.Framework.StateSystem.States; using SlatedGameToolkit.Framework.Utilities; using SlatedGameToolkit.Framework.Graphics; using SlatedGameToolkit.Framework.Graphics.OpenGL; namespace SlatedGameToolkit.Framework.StateSystem { public sealed class StateManager : IDisposable { public Thread thread; public Color backgroundColour; private IState currentState; private IState nextState; private Dictionary states; /// /// Instantiates a game state manager with an initial state, and a set of states to be added at the start. /// States can later be added or removed. /// None of the parameters can be null, and the initial state must exist in initial set of states. /// /// The name of the initial state. /// The initial set of game states to be added. internal StateManager() { backgroundColour = Color.Orange; this.states = new Dictionary(); } internal void Initialize(IState initialState) { if (initialState == null) throw new ArgumentNullException("initialState"); thread = Thread.CurrentThread; currentState = initialState; addState(initialState); } internal void update(double delta) { if (nextState != null) { if (currentState.Deactivate() & nextState.Activate()) { currentState = nextState; nextState = null; } } currentState.Update(delta); } internal void render(double delta) { WindowContext windowContext = WindowContextsManager.CurrentWindowContext; windowContext.Context.ClearColor(backgroundColour.RedAsFloat(), backgroundColour.GreenAsFloat(), backgroundColour.BlueAsFloat(), 1f); windowContext.Context.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); currentState.Render(delta); windowContext.SwapBuffer(); } /// /// Begins a state change. The current stage will be notified, and so will the state that is being changed to. /// /// The name of the state that we are turning to. public void changeState(string name) { if (thread != Thread.CurrentThread) throw new ThreadStateException("State cannot be changed from a different thread."); if (!states.TryGetValue(name, out nextState)) throw new ArgumentException("The requested state to change to does not exist in this manager."); } /// /// Adds the given states to this manager under each of their own respective names. /// Initializes all the states. /// If there are two states of the same name, the first state in the array is added and the second is discarded. /// The discarded state will not be initialized and dispose will not be called on it. /// /// The states to add. /// True if all the states were unique, and false if there were repetitions determined by name. public bool addStates(IState[] states) { if (states == null || states.Length == 0) throw new ArgumentException("The array of states cannot be null, and cannot be of size 0"); bool unique = true; foreach (IState state in states) { unique = unique && addState(state); } return unique; } /// /// Adds the given state to this manager under it's own name. /// Initializes the state as well. /// Will not iniitialize the state if this method returns false. /// /// The state to be added to this manager. /// False if a state of this name has already been registered. public bool addState(IState state) { if (thread != Thread.CurrentThread) throw new ThreadStateException("Cannot add a state from a different thread."); try { GameEngine.Logger.Debug("Adding state: " + state.getName()); this.states.Add(state.getName(), state); } catch (ArgumentException) { return false; } state.Initialize(this); return true; } /// /// Removes the state given the name of the state. /// If the state doesn't exist, nothing happens. /// Will call dispose on the state. /// /// The name of the state. /// False if the state is being used, or the state doesn't exist. public bool removeState(string name) { if (thread != Thread.CurrentThread) throw new ThreadStateException("Cannot remove a state from a different thread."); if (states[name] == currentState) return false; IState state = states[name]; GameEngine.Logger.Debug("Removing state: " + name); try { state.Deinitialize(); } catch (Exception e) { GameEngine.Logger.Error(e.ToString()); GameEngine.Logger.Error("Failed to deinitialize state: " + state.getName()); } return states.Remove(name); } /// /// Removes all the states in this state manager except for the current one. /// Disposes of the removed states. /// public void removeAllStates() { GameEngine.Logger.Debug("Beginning to remove all states..."); foreach (String state in this.states.Keys) { removeState(state); } GameEngine.Logger.Debug("Completed removing all states..."); } public void Dispose() { if (currentState == null) return; currentState = null; removeAllStates(); } } }