Last active
December 10, 2015 09:30
-
-
Save Sose/128da4d033cffc8df3d8 to your computer and use it in GitHub Desktop.
Unity C# FSM
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System.Collections; | |
public class AttackState : State | |
{ | |
private float attackTimer; | |
private float attackDuration = 0.5f; | |
public override void OnEnter() | |
{ | |
((TestEnemy)owner).animator.SetTrigger("Attack"); | |
((TestEnemy)owner).animator.SetBool("isMoving", false); | |
attackTimer = 0f; | |
} | |
public override void Update() | |
{ | |
attackTimer += Time.deltaTime; | |
} | |
public bool IsFinished() | |
{ | |
return (attackTimer > attackDuration); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System.Collections; | |
public class FollowState : State | |
{ | |
public override void OnEnter() | |
{ | |
((TestEnemy)owner).animator.SetBool("isMoving", true); | |
} | |
public override void Update() | |
{ | |
var player = ((TestEnemy)owner).player; | |
var self = owner.transform; | |
var rigidBody = ((TestEnemy)owner).rigidBody; | |
var speed = ((TestEnemy)owner).speed; | |
//math from Unity TopDown Video tutorial | |
float z = Mathf.Atan2(player.transform.position.y - self.position.y, | |
player.transform.position.x - self.position.x) | |
* Mathf.Rad2Deg - 90; | |
owner.transform.eulerAngles = new Vector3(0, 0, z); | |
rigidBody.AddForce(self.up * speed); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System.Collections; | |
using System; | |
public class IdleState : State | |
{ | |
public override void OnEnter() | |
{ | |
((TestEnemy)owner).animator.SetBool("isMoving", false); | |
} | |
public override void Update() | |
{ | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System.Collections; | |
using System; | |
using System.Collections.Generic; | |
public abstract class State | |
{ | |
protected MonoBehaviour owner; | |
protected StateMachine stateMachine; | |
protected Dictionary<Func<bool>, State> transitions; | |
public State() | |
{ | |
this.transitions = new Dictionary<Func<bool>, State>(); | |
} | |
public void Initialize(MonoBehaviour owner, StateMachine stateMachine) | |
{ | |
this.owner = owner; | |
this.stateMachine = stateMachine; | |
} | |
public virtual void Update() | |
{ | |
} | |
public virtual void OnEnter() | |
{ | |
} | |
public virtual void OnExit() | |
{ | |
} | |
public void AddTransition(State newState, Func<bool> cond) | |
{ | |
transitions.Add(cond, newState); | |
} | |
public void CheckTransitions() | |
{ | |
foreach (KeyValuePair<Func<bool>, State> kvp in transitions) | |
{ | |
Func<bool> cond = kvp.Key; | |
State state = kvp.Value; | |
if (cond()) | |
{ | |
stateMachine.State = state; | |
break; | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System.Collections; | |
public class StateMachine | |
{ | |
public MonoBehaviour owner; | |
private State currentState; | |
public State State | |
{ | |
get | |
{ | |
return currentState; | |
} | |
set | |
{ | |
if (currentState != null) | |
{ | |
currentState.OnExit(); | |
} | |
currentState = value; | |
currentState.Initialize(owner, this); | |
currentState.OnEnter(); | |
} | |
} | |
public StateMachine(MonoBehaviour owner) | |
{ | |
this.owner = owner; | |
} | |
public void Update() | |
{ | |
currentState.CheckTransitions(); | |
currentState.Update(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System.Collections; | |
[RequireComponent(typeof(Rigidbody2D), typeof(Animator))] | |
public class TestEnemy : MonoBehaviour | |
{ | |
public float alertRange = 10f; | |
public float speed = 5f; | |
public Transform player; | |
[HideInInspector] | |
public Rigidbody2D rigidBody; | |
[HideInInspector] | |
public Animator animator; | |
private StateMachine FSM; | |
private IdleState idleState; | |
private FollowState followState; | |
private AttackState attackState; | |
void Awake() | |
{ | |
if (player == null) | |
player = GameObject.FindGameObjectWithTag("Player").transform; | |
rigidBody = GetComponent<Rigidbody2D>(); | |
animator = GetComponent<Animator>(); | |
} | |
void Start() | |
{ | |
idleState = new IdleState(); | |
followState = new FollowState(); | |
attackState = new AttackState(); | |
idleState.AddTransition(followState, playerIsNear); | |
followState.AddTransition(idleState, () => !playerIsNear()); | |
followState.AddTransition(attackState, shouldAttack); | |
attackState.AddTransition(followState, attackState.IsFinished); | |
FSM = new StateMachine(this); | |
FSM.State = idleState; | |
} | |
void Update() | |
{ | |
FSM.Update(); | |
} | |
bool shouldAttack() | |
{ | |
var distanceSqr = (player.transform.position - transform.position).sqrMagnitude; | |
return distanceSqr < 3f * 3f; | |
} | |
bool playerIsNear() | |
{ | |
var distanceSqr = (player.transform.position - transform.position).sqrMagnitude; | |
return (distanceSqr < alertRange * alertRange); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment