What I am trying to do is choose different function to call based on specific input. I know this seems trivia, however, as I am implementing new states throughout the whole project, what is a good practice so that I can easily expand the functionality without messing things up?
For example, currently there are 2 states for my project: Idle, MakeFist, each associated with a bool flag. I have a script called CursorBehaviour.cs that defines all the flags and functions associated.
In ‘Idle’ state, the cursor can be used to select and click certain objects.
In ‘MakeFist’ state, the cursor can change the camera’s viewing angle
If I am to making a 3rd state called ‘FingerSpread’, I will need to modify this script, add in a new flag, and check one more condition , and add new functions… This script will quickly go crazy and I am sure there is a better way to handle this.
Should I have a different script to handle all the state flags, and another script for functions? What would it look like?
Another question is what would be a good way to record all the states? With all the flags I have, only one of them shall be true.
I would create a script that is a CursorStateHandler:
using UnityEngine;
using System.Collections;
public class CursorStateHandler : MonoBehaviour {
int currentState;
public void SetState(int state)
{
currentState = state;
}
public int GetState()
{
return currentState;
}
}
Then other scripts and buttons ,etc would access this object like so:
OnMouseClick()
{
switch (cursorStateHandler.GetState())
{
case STATE_NORMAL:
// do whatever nomral click action is
break;
case STATE_FIST:
// Do some fist action;
break;
default:
// don't do anyting these other states are non clickable states
break;
}
}
ButtonClickHandler()
{
cursorStateHandler.SetState(STATE_FIST);
}
This way any Object A can handle clicks without caring who set the cursor or why. And its easily extendable. If you add a new state Object A’s MouseClick handler will just treat it as a non-click state unless you to add the code in.
The CursorHandler script is basically just a variable at this point, but it allows you to extend it later without breaking your code. Here is an idea you might do.
using UnityEngine;
using System.Collections.Generic;
public class CursorStateHandler : MonoBehaviour {
public struct StateData
{
int state; // which state this state data goes with;
bool ClickableState;
var SomeOtherstuff;
}
List<StateData> stateData = new List<StateData>();
int currentState;
void Awake()
{
InitStateData();
}
public InitStateData()
{
// Code here that reads from a file
// or Some Constants variable you setup somehwere else
// to initalize all the StateData that goes with each State.
}
public void SetState(int state)
{
currentState = state;
}
public int GetState()
{
return currentState;
}
public StateData GetStateData()
{
return FindData(currentState);
}
StateData FindData(int state)
{
foreach (StateData data in stateData)
if (data.state == currentState)
return data;
}
}
and Change the MousClick code to :
OnMouseClick()
{
StateData data = cursorStateHandler.GetStateData();
if (data.Clickable)
{
// Do normal mouse click stuff
// Now any extra states you add
// can be clicked by settting clickable in the data
// and this code won't have to be changed when you add new states
}
}
You could always choose to go hog wild with a Strategy Pattern. Sort of like this:
public interface CursorBehaviourStrategy {
OnMouseClick();
}
public class IdleCursorBehaviourStrategy : CursorBehaviourStrategy {
OnMouseClick() {
// Do something idle
}
}
public class MakeFistCursorBehaviourStrategy : CursorBehaviourStrategy {
OnMouseClick() {
// Do something makefisty
}
}
public class FingerSpreadCursorBehaviourStrategy : CursorBehaviourStrategy {
OnMouseClick() {
// Do something fingerspready
}
}
public class CursorStateHandler : MonoBehaviour {
CursorState state; // CursorState is an enum, or something
CursorBehaviourStrategy cursorStrategy;
void ChangeState(CursorState state) {
this.state = state;
switch (state) {
case CursorState.Idle:
cursorStrategy = new IdleCursorBehaviourStrategy();
break;
case CursorState.MakeFist:
cursorStrategy = new MakeFistCursorBehaviourStrategy();
break;
case CursorState.FingerSpread:
cursorStrategy = new FingerSpreadCursorBehaviourStrategy();
break;
}
}
void OnMouseClick() {
cursorStrategy.OnMouseClick();
}
}
It may be overkill in your current situation, but if you’re going to add more functionality to the different behaviours, or you just like bloated code, this could be worth considering.