|
using UnityEngine; |
|
|
|
public class MinimumFsmBasedAiController : MonoBehaviour |
|
{ |
|
public enum EState : byte |
|
{ |
|
START = 0, |
|
PATROL, |
|
INVESTIGATE, |
|
ATTACK, |
|
TAKE_COVER, |
|
DEAD, |
|
} |
|
|
|
void FixedUpdate () |
|
{ |
|
OnStateTick(_state, Time.fixedTime - _stateChangeTime); |
|
} |
|
|
|
#if UNITY_EDITOR |
|
void OnDrawGizmos () |
|
{ |
|
if( Application.isPlaying ) UnityEditor.Handles.Label(transform.position, $"[{_state}]"); |
|
} |
|
#endif |
|
|
|
/// <summary>Good place to change animations, moving speed or play sounds etc.</summary> |
|
void OnStateEnter ( EState state ) |
|
{ |
|
// state starts: |
|
if( state==EState.START ) |
|
{ |
|
|
|
} |
|
else if( state==EState.PATROL ) |
|
{ |
|
|
|
} |
|
else if( state==EState.INVESTIGATE ) |
|
{ |
|
|
|
} |
|
else if( state==EState.ATTACK ) |
|
{ |
|
|
|
} |
|
else if( state==EState.TAKE_COVER ) |
|
{ |
|
|
|
} |
|
else if( state==EState.DEAD ) |
|
{ |
|
|
|
} |
|
else throw new System.NotImplementedException($"{state} not implemented"); |
|
} |
|
|
|
/// <summary>Good place to change states - always using ChangeState(_)!.</summary> |
|
void OnStateTick ( EState state , float duration ) |
|
{ |
|
// state update: |
|
if( state==EState.START ) |
|
{ |
|
ChangeState(EState.PATROL); |
|
} |
|
else if( state==EState.PATROL ) |
|
{ |
|
|
|
} |
|
else if( state==EState.INVESTIGATE ) |
|
{ |
|
|
|
} |
|
else if( state==EState.ATTACK ) |
|
{ |
|
|
|
} |
|
else if( state==EState.TAKE_COVER ) |
|
{ |
|
|
|
} |
|
else if( state==EState.DEAD ) |
|
{ |
|
|
|
} |
|
else throw new System.NotImplementedException($"{state} not implemented"); |
|
} |
|
|
|
/// <summary>Good place to reset values</summary> |
|
void OnStateExit ( EState state ) |
|
{ |
|
// state ends: |
|
if( state==EState.START ) |
|
{ |
|
|
|
} |
|
else if( state==EState.PATROL ) |
|
{ |
|
|
|
} |
|
else if( state==EState.INVESTIGATE ) |
|
{ |
|
|
|
} |
|
else if( state==EState.ATTACK ) |
|
{ |
|
|
|
} |
|
else if( state==EState.TAKE_COVER ) |
|
{ |
|
|
|
} |
|
else if( state==EState.DEAD ) |
|
{ |
|
|
|
} |
|
else throw new System.NotImplementedException($"{state} not implemented"); |
|
} |
|
|
|
#region INTERNALS (DO NOT CHANGE) |
|
|
|
EState _state = EState.START; |
|
float _stateChangeTime; |
|
|
|
/// <summary>Call this to change state.</summary> |
|
/// <remarks>Do not modify value _state outside this.</summaremarksry> |
|
void ChangeState ( EState nextState ) |
|
{ |
|
if( nextState==_state) |
|
{ |
|
// do NOT comment this out, rethink the call logic to fix the damn warning |
|
Debug.LogError($"{nameof(ChangeState)} fails as {nextState} is a current state already."); |
|
return; |
|
} |
|
|
|
OnStateExit(_state); |
|
_state = nextState; |
|
_stateChangeTime = Time.time; |
|
OnStateEnter(_state); |
|
} |
|
|
|
#endregion |
|
|
|
} |