I’ve been struggling to figure out an elegant solution to this problem, which is how to handle switching a controller’s state between ‘no-control’ and ‘full-control’, in an RPG-styled game. My problem is, there are many factors which can switch the controller state, and I want to avoid conflicting code.
This is my current solution below, although I’m not totally satisfied with it:
Some examples of when the controller will be turned off (in my game):
- Transitioning between scenes
- Playing animations
- Interacting with an NPCs
Each of these scenarios can turn the controller on / off, yet they all happen independently.
An example of how these may conflict with each other, goes:
-Player begins a room transition (controller turns off), but then a separate animation plays and finishes before the room has fully transitioned. After the animation has complete, it would make a call to the controller to return to ‘full-control’.
Really, there should only be one entity at a time, which dictates the state of the controller.
Currently, I’m using a state-machine in a ControllerManager
class. I’m also using an interface called IStateCaller
, which stores an IStateCaller
variable in ControllerManager
, which is now the ‘registered called’.
Then, IStateCaller
is applied to any object that is intended to switch the state of the controller. Whenever that object has completed it’s function, it then checks ControllerManager
if this object is the ‘registered-caller’, and if it is, then it switches the controller’s state.
An example for transitioning between room, we go through a door script.
A snippet:…
public class ControllerManager : Monobehaviour
{
private ControllerManagerState state;
private IStateCaller caller;
private FullControl_CMState fullControl_S;
private NoControl_CMState noControl_S;
private Pause_CMState pause_S;
public void RegisterCaller(IStateCaller registerCaller)
{
if (caller != null) return;
caller = registerCaller;
}
public void State(IStateCaller registeredCaller, ControllerManagerOptions nextState)
{
if (FailedToMatchCaller(registeredCaller)) return;
state.LoadNextState(nextState);
}
}
public class DoorOpen : Monobehaviour, IStateCaller
{
public void OpenDoor()
{
// Here's where we set the StateCaller:
ControllerManager.Instance.RegisterCaller(this);
ControllerManager.Instance.State(this, ControllerManagerOptions.noControl);
ControllerManager.Instance.PlayerAnim(AnimRegistery.openDoor, doorAngle);
}
}
If anyone knows a better solution please let me know!