IStateを継承したクラスで、ゴーストの状態の遷移と、そのときの行動を処理します。Dictionary<State, IState>とenum Stateで各stateを登録・参照し、Mover、Animatorで移動、アニメーションを行います。
移動に関しては下記を参照してください。
nullsuke.com
アニメーションに関しては下記を参照してください。
nullsuke.com
public interface IState
{
event EventHandler OnTouch;
IState Excute();
IState Frighten(float span);
IState Calm();
IState Eaten();
void Warp(Vector2 pos, float span);
void Animate();
}
public enum State { Wait, Init, Scatter, Chase, Scare, Return, Dead };
public class Wait : IState
{
public event EventHandler OnTouch;
private readonly Dictionary<State, IState> states;
private readonly Queue<Vector2> waypoints;
private readonly Mover mover;
private readonly Animator animator;
private readonly float span;
private float limitTime;
public Wait(Mover mover, Dictionary<State, IState> states,
Animator animator, Queue<Vector2> waypoints, float span)
{
this.mover = mover;
this.states = states;
this.animator = animator;
this.waypoints = waypoints;
this.span = span;
mover.SetWaypoints(waypoints);
states.Add(State.Wait, this);
}
public IState Excute()
{
if (limitTime < Time.fixedTime)
{
var next = states[State.Init] as Init;
next.SetState();
return next;
}
mover.MoveToWaypoints(true);
return this;
}
public void SetState()
{
limitTime = Time.fixedTime + span;
mover.SetWaypoints(waypoints);
}
public IState Frighten(float scareSpan)
{
var next = states[State.Scare] as Scare;
next.SetState(this, scareSpan);
return next;
}
public IState Calm()
{
return this;
}
public IState Eaten()
{
OnTouch(this, EventArgs.Empty);
return this;
}
public void Warp(Vector2 pos, float warpSpan)
{
throw new System.NotImplementedException();
}
public void Animate()
{
animator.SetFloat("DirX", mover.Direction.x);
animator.SetFloat("DirY", mover.Direction.y);
}
}
public class Init : IState
{
public event EventHandler OnTouch;
private readonly Dictionary<State, IState> states;
private readonly Queue<Vector2> waypoints;
private readonly Mover mover;
private readonly Animator animator;
public Init(Mover mover, Dictionary<State, IState> states,
Animator animator, Queue<Vector2> waypoints)
{
this.mover = mover;
this.states = states;
this.animator = animator;
this.waypoints = waypoints;
states.Add(State.Init, this);
}
public IState Excute()
{
IState next = this;
mover.MoveToWaypointsThen(() =>
{
var scatter = states[State.Scatter] as Scatter;
scatter.SetState();
next = scatter;
});
return next;
}
public void SetState()
{
mover.SetWaypoints(waypoints);
}
public IState Frighten(float scareSpan)
{
var next = states[State.Scare] as Scare;
next.SetState(this, scareSpan);
return next;
}
public IState Calm()
{
return this;
}
public IState Eaten()
{
OnTouch(this, EventArgs.Empty);
return this;
}
public void Warp(Vector2 pos, float warpSpan)
{
throw new System.NotImplementedException();
}
public void Animate()
{
animator.SetFloat("DirX", mover.Direction.x);
animator.SetFloat("DirY", mover.Direction.y);
}
}
public class Scatter : IState
{
public event EventHandler OnTouch;
private readonly Dictionary<State, IState> states;
private readonly Queue<Vector2> waypoints;
private readonly Mover mover;
private readonly Animator animator;
private readonly float span;
private float limitTime;
public Scatter(Mover mover, Dictionary<State, IState> states,
Animator animator, Queue<Vector2> waypoints, float span)
{
this.mover = mover;
this.states = states;
this.animator = animator;
this.waypoints = waypoints;
this.span = span;
states.Add(State.Scatter, this);
}
public IState Excute()
{
if (limitTime < Time.fixedTime)
{
var next = states[State.Chase] as Chase;
next.SetState();
return next;
}
mover.MoveToWaypoints(true);
return this;
}
public void SetState()
{
limitTime = Time.fixedTime + span;
mover.SetWaypoints(waypoints);
}
public IState Frighten(float scareSpan)
{
var next = states[State.Scare] as Scare;
next.SetState(this, scareSpan);
return next;
}
public IState Calm()
{
return this;
}
public IState Eaten()
{
OnTouch(this, EventArgs.Empty);
return this;
}
public void Warp(Vector2 pos, float warpSpan)
{
throw new System.NotImplementedException();
}
public void Animate()
{
animator.SetFloat("DirX", mover.Direction.x);
animator.SetFloat("DirY", mover.Direction.y);
}
}
public class Chase : IState
{
public event EventHandler OnTouch;
private readonly Dictionary<State, IState> states;
private readonly Mover mover;
private readonly Animator animator;
private readonly float span;
private readonly SpriteRenderer sprite;
private bool warped;
private float leftSpan;
private float limitTime;
private float warpEndTime;
public Chase(Mover mover, Dictionary<State, IState> states,
Animator animator, SpriteRenderer sprite, float span)
{
this.mover = mover;
this.states = states;
this.animator = animator;
this.sprite = sprite;
this.span = span;
states.Add(State.Chase, this);
}
public IState Excute()
{
if (!warped)
{
if (limitTime < Time.fixedTime)
{
leftSpan = 0;
var next = states[State.Return] as Return;
next.SetState();
return next;
}
else
{
mover.MoveToWaypoints(State.Chase);
return this;
}
}
else
{
if (warpEndTime < Time.fixedTime)
{
sprite.enabled = true;
warped = false;
limitTime = leftSpan + Time.fixedTime;
}
return this;
}
}
public void SetState()
{
limitTime = Time.fixedTime + span;
}
public IState Frighten(float scareSpan)
{
limitTime += scareSpan;
var next = states[State.Scare] as Scare;
next.SetState(this, scareSpan);
return next;
}
public IState Calm()
{
return this;
}
public IState Eaten()
{
OnTouch(this, EventArgs.Empty);
return this;
}
public void Warp(Vector2 pos, float warpSpan)
{
sprite.enabled = false;
leftSpan = Mathf.Max(limitTime - Time.fixedTime, 0);
warpEndTime = Time.fixedTime + warpSpan;
warped = true;
mover.Warp(pos);
}
public void Animate()
{
animator.SetFloat("DirX", mover.Direction.x);
animator.SetFloat("DirY", mover.Direction.y);
}
}
public class Scare : IState
{
public event EventHandler OnTouch;
private readonly Dictionary<State, IState> states;
private readonly Mover mover;
private readonly Animator animator;
private readonly float defaultSpeed;
private readonly SpriteRenderer sprite;
private IState preState;
private bool warped;
private float limitTime;
private float warpEndTime;
public Scare(Mover mover, Dictionary<State, IState> states,
Animator animator, SpriteRenderer sprite)
{
this.mover = mover;
this.states = states;
this.animator = animator;
this.sprite = sprite;
defaultSpeed = mover.Speed;
states.Add(State.Scare, this);
}
public IState Excute()
{
IState state = this;
if (!warped)
{
if (preState is Wait || preState is Init ||
preState is Scatter)
{
preState = preState.Excute();
}
else
{
mover.MoveToWaypoints(State.Scare);
}
}
else
{
if (warpEndTime < Time.fixedTime)
{
sprite.enabled = true;
warped = false;
}
}
return state;
}
public void SetState(IState preState, float span)
{
this.preState = preState;
limitTime = Time.fixedTime + span;
mover.Speed = defaultSpeed * 0.8f;
animator.SetBool("IsScare", true);
}
public IState Frighten(float span)
{
limitTime = Time.fixedTime + span;
return this;
}
public IState Calm()
{
mover.Speed = defaultSpeed;
sprite.enabled = true;
warped = false;
animator.SetBool("IsScare", false);
animator.SetBool("IsCalmSoon", false);
return preState;
}
public IState Eaten()
{
OnTouch(this, EventArgs.Empty);
var next = states[State.Dead] as Dead;
next.SetState();
return next;
}
public void Warp(Vector2 pos, float warpSpan)
{
sprite.enabled = false;
warpEndTime = Time.fixedTime + warpSpan;
warped = true;
mover.Warp(pos);
}
public void Animate()
{
if (limitTime - Time.fixedTime < 3)
{
animator.SetBool("IsCalmSoon", true);
}
else
{
animator.SetBool("IsCalmSoon", false);
}
}
}
public class Dead : IState
{
public event EventHandler OnTouch;
private readonly Dictionary<State, IState> states;
private readonly Mover mover;
private readonly Animator animator;
private readonly Queue<Vector2> nestWaypoints;
private readonly SoundManager soundManager;
private readonly float defaultSpeed;
private bool isArriveNearNest;
public Dead(Mover mover, Dictionary<State, IState> states,
Animator animator, Queue<Vector2> nestWaypoints)
{
this.mover = mover;
this.states = states;
this.animator = animator;
this.nestWaypoints = nestWaypoints;
defaultSpeed = mover.Speed;
states.Add(State.Dead, this);
soundManager = SoundManager.Instance;
}
public IState Excute()
{
IState next = this;
if (!isArriveNearNest)
{
mover.MoveToWaypointsThen(nestWaypoints.Peek(),
() => isArriveNearNest = true);
}
else
{
mover.MoveToWaypointsThen(() =>
{
mover.Speed = defaultSpeed;
isArriveNearNest = false;
var wait = states[State.Wait] as Wait;
wait.SetState();
next = wait;
animator.SetBool("IsDead", false);
soundManager.StopSE();
});
}
return next;
}
public void SetState()
{
mover.SetWaypoints(nestWaypoints);
mover.Speed = defaultSpeed *2f;
animator.SetBool("IsScare", false);
animator.SetBool("IsCalmSoon", false);
animator.SetBool("IsDead", true);
soundManager.PlaySE("GhostDead", 0.2f);
}
public IState Frighten(float scareSpan)
{
return this;
}
public IState Calm()
{
return this;
}
public IState Eaten()
{
OnTouch(this, EventArgs.Empty);
return this;
}
public void Warp(Vector2 pos, float warpSpan)
{
mover.Warp(pos);
}
public void Animate()
{
animator.SetFloat("DirX", mover.Direction.x);
animator.SetFloat("DirY", mover.Direction.y);
}
}
public class Return : IState
{
public event EventHandler OnTouch;
private readonly Dictionary<State, IState> states;
private readonly Mover mover;
private readonly Animator animator;
private readonly Vector2 scatterPoint;
private readonly SpriteRenderer sprite;
private Scatter next;
private bool warped;
private float warpEndTime;
public Return(Mover mover, Dictionary<State, IState> states,
Animator animator, SpriteRenderer sprite, Vector2 scatterPoint)
{
this.mover = mover;
this.states = states;
this.animator = animator;
this.sprite = sprite;
this.scatterPoint = scatterPoint;
states.Add(State.Return, this);
}
public IState Excute()
{
IState state = this;
if (!warped)
{
if (next == null)
{
mover.MoveToWaypointsThen(scatterPoint,
() =>
{
next = states[State.Scatter] as Scatter;
next.SetState();
});
}
else state = next;
}
else
{
if (warpEndTime < Time.fixedTime)
{
sprite.enabled = true;
warped = false;
}
}
return state;
}
public void SetState()
{
next = null;
}
public IState Frighten(float scareSpan)
{
var next = states[State.Scare] as Scare;
next.SetState(this, scareSpan);
return next;
}
public IState Calm()
{
return this;
}
public IState Eaten()
{
OnTouch(this, EventArgs.Empty);
return this;
}
public void Warp(Vector2 pos, float warpSpan)
{
sprite.enabled = false;
warpEndTime = Time.fixedTime + warpSpan;
warped = true;
mover.Warp(pos);
}
public void Animate()
{
animator.SetFloat("DirX", mover.Direction.x);
animator.SetFloat("DirY", mover.Direction.y);
}
}