- Home /
Changing between states in state machine with a keypress
Hey I have made a state machine that is suppose to switch states with the press of the space key and prints which state it is in on the log file. It works as intended, but I was wondering if there was an easier way to do it, or if my way is good or bad with regards to memory consumption and other optimization practices. Also if anybody can show me how I would handle the key press in other file (such as a Main.cs file) then that would be great too. Thanks.
Just attach the C# code to anything and it should work.
using UnityEngine; using System.Collections;
public class abctest1 : MonoBehaviour {
public enum State{
Active,
Inactive,
Dead,
Complete,
}
public int stateCounter=0;
public State behaviorState;
IEnumerator Start () {
//behaviorState = abctest1.State.Active;
behaviorState = State.Active;
while(true){
switch(behaviorState){
case State.Active:
ActiveState();
break;
case State.Inactive :
InactiveState();
break;
case State.Dead :
DeadState();
break;
case State.Complete :
CompleteState();
break;
}
yield return 0;
}
}
public void ActiveState(){
Debug.Log("Active State");
if(stateCounter == 1)
behaviorState = State.Inactive;
}
public void InactiveState(){
Debug.Log("Inactive State");
if(stateCounter == 2)
behaviorState = State.Dead;
}
public void DeadState(){
Debug.Log("Dead State");
if(stateCounter == 3)
behaviorState = State.Complete;
}
public void CompleteState(){
Debug.Log("Complete State");
if(stateCounter == 4)
behaviorState = State.Active;
}
public void Update () {
if(Input.GetKeyDown("space"))
stateCounter = stateCounter + 1;
print(stateCounter);
if(stateCounter == 5)
stateCounter = 6 - stateCounter;
}
}
Answer by Berenger · Feb 08, 2012 at 03:23 PM
Well, that's the idea. What is going to change know is the nature of the event changing the state. From a space stroke to anything, life to low or player to far etc.
Another to do without the loop on the switch is, at least I think it's a good solution but I'm not that advanced so be carefull :p, to use object-oriented design. Each behavior is an implementation of an interface, and you can create an object of that implementation according to the event (if( state == death ) behavior = new Death(), etc).
Other advice, a good way to control performance is to not update the AI every frame. Nothing more simple in your case because everything is here already : replace yield return 0 by yield return WaitForSeconds( frequency );
Answer by Harry Buck · Feb 08, 2012 at 07:09 PM
@Berenger So with the new implementation of the interface, are you saying that I should make a new "Death" class and have the functionality for the Death in that class. If you could provide an example that would be great, I am more of a visual learner.
@Jessy I made it public because later on I want to be able to access this state machine in another file. I out the key press in the same class just for simplicity. Later on I would like to have it where the key press functionality is in another file but still gets the state machine from the file that the FSM is in.
Answer by Jessy · Feb 08, 2012 at 05:31 PM
I don't know anything about state machines. This is what came to mind.
#pragma warning disable 0649
using System;
using UnityEngine;
public class abctest1 : MonoBehaviour {
[Serializable] class State {
public Action action;
public State nextState;
public string announcement;
} [HideInInspector][SerializeField] State state;
[SerializeField] State active, inactive, dead, complete;
void Awake() {
// These next two blocks can't be serialized by the Editor.
active.nextState = inactive;
inactive.nextState = dead;
dead.nextState = complete;
complete.nextState = active;
// Put real stuff in the braces.
active.action = () => {};
inactive.action = () => {};
dead.action = () => {};
complete.action = () => {};
// This should be done in the Editor but dealing with Reset()
// is a pain and not directly relevant to the question.
state = active;
Debug.Log(active.announcement);
}
void Update() {
if(Input.GetKeyDown("space")) {
state = state.nextState;
Debug.Log(state.announcement);
}
state.action();
}
}