Skip to content

Instantly share code, notes, and snippets.

@Sose
Last active December 10, 2015 09:30
Show Gist options
  • Save Sose/128da4d033cffc8df3d8 to your computer and use it in GitHub Desktop.
Save Sose/128da4d033cffc8df3d8 to your computer and use it in GitHub Desktop.
Unity C# FSM
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);
}
}
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);
}
}
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()
{
}
}
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;
}
}
}
}
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();
}
}
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