145 lines
6.3 KiB
C#

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<string, IState> states;
/// <summary>
/// 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.
/// </summary>
/// <param name="initialState">The name of the initial state.</param>
/// <param name="states">The initial set of game states to be added.</param>
internal StateManager() {
backgroundColour = Color.Orange;
this.states = new Dictionary<string, IState>();
}
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();
}
/// <summary>
/// Begins a state change. The current stage will be notified, and so will the state that is being changed to.
/// </summary>
/// <param name="name">The name of the state that we are turning to.</param>
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.");
}
/// <summary>
/// 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.
/// </summary>
/// <param name="states">The states to add.</param>
/// <returns>True if all the states were unique, and false if there were repetitions determined by name.</returns>
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;
}
/// <summary>
/// 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.
/// </summary>
/// <param name="state">The state to be added to this manager.</param>
/// <returns>False if a state of this name has already been registered.</returns>
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;
}
/// <summary>
/// Removes the state given the name of the state.
/// If the state doesn't exist, nothing happens.
/// Will call dispose on the state.
/// </summary>
/// <param name="name">The name of the state.</param>
/// <returns>False if the state is being used, or the state doesn't exist.</returns>
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);
}
/// <summary>
/// Removes all the states in this state manager except for the current one.
/// Disposes of the removed states.
/// </summary>
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();
}
}
}