146 lines
6.6 KiB
C#
146 lines
6.6 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.OpenGL;
|
|
using SlatedGameToolkit.Framework.Logging;
|
|
using System.Collections.Concurrent;
|
|
|
|
namespace SlatedGameToolkit.Framework.StateSystem
|
|
{
|
|
public sealed class StateManager {
|
|
public Thread thread;
|
|
public Color backgroundColour;
|
|
private IState currentState;
|
|
private IState nextState;
|
|
private ConcurrentDictionary<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 ConcurrentDictionary<string, IState>();
|
|
}
|
|
|
|
internal void Initialize(IState initialState) {
|
|
if (initialState == null) throw new ArgumentNullException("initialState");
|
|
Logger.Log("Initialized state manager with state: " + initialState.getName());
|
|
thread = Thread.CurrentThread;
|
|
AddState(initialState);
|
|
currentState = initialState;
|
|
currentState.Activate();
|
|
}
|
|
|
|
internal void Update(double timeStep) {
|
|
if (nextState != null) {
|
|
if (currentState.Deactivate() & nextState.Activate()) {
|
|
currentState = nextState;
|
|
nextState = null;
|
|
}
|
|
}
|
|
currentState.Update(timeStep);
|
|
}
|
|
|
|
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 initialize 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.");
|
|
Logger.Log("Adding state: " + state.getName(), LogLevel.DEBUG);
|
|
if (!this.states.TryAdd(state.getName(), state)) {
|
|
Logger.Log(string.Format("State with name \"{0}\" already exists in manager.", state.getName()), LogLevel.WARNING);
|
|
}
|
|
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];
|
|
Logger.Log("Removing state: " + name, LogLevel.DEBUG);
|
|
try {
|
|
state.Deinitialize();
|
|
Logger.Log("State deinitialized: " + name, LogLevel.DEBUG);
|
|
} catch (Exception e) {
|
|
Logger.Log(e.ToString(), LogLevel.WARNING);
|
|
Logger.Log("Failed to deinitialize state: " + state.getName(), LogLevel.WARNING);
|
|
}
|
|
IState removedState;
|
|
return states.Remove(name, out removedState);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Removes all the states in this state manager except for the current one.
|
|
/// Deinitializes the removed states.
|
|
/// </summary>
|
|
public void RemoveAllStates() {
|
|
foreach (String state in this.states.Keys)
|
|
{
|
|
RemoveState(state);
|
|
}
|
|
}
|
|
|
|
internal void Deinitialize() {
|
|
if (currentState == null) return;
|
|
currentState = null;
|
|
RemoveAllStates();
|
|
Logger.Log("Deinitializing state manager.");
|
|
}
|
|
}
|
|
} |