Animation out of time with custom clock
I have a system where a game phase manager cycles through various phases that make up my core game loop. In one of those phases, the game runs a clock that fires an event every fraction of a second, announcing what "tick" the clock is on. Each unit in my game has a listener that checks the current tick, and changes the animation if it has been issued a command to execute at that tick. Commands all have a certain AP cost, which maps to a set number of ticks per AP for each unit based on the units speed (units with more AP will spend fewer ticks performing that ap).
This works well...almost. When playing back my move command animations, the units are arriving just slightly before they're supposed to, giving it a jerky effect. I can't figure out where I am falling out of sync; help is appreciated!
Clock (Phase manager):
private IEnumerator PlayAnimations()
{
for (int t = 0; t <= Game.TICK_PER_ROUND; t++) {
OnTickUpdated.Invoke(t);
Debug.Log("Time = " + t);
yield return new WaitForSeconds(Game.SecPerTick);
}
}
Listener (UnitAnimation):
private void OnTickUpdated(int tick)
{
Debug.Log(unit.name + " hears the tick: " + tick);
if (unit.Commands.GetAtTick(tick) != null) {
if (nowPlaying != null) nowPlaying.Execute(); // finish current command
PlayNext(unit.Commands.GetAtTick(tick)); // start playing next command
}
}
private void PlayNext(ICommand next)
{
StopAllCoroutines();
nowPlaying = next;
CommandAnimation NextAnim = SelectAnimation(nowPlaying); // runs a switch statement to choose which animation coroutine to play.
if (NextAnim != null) {
StartCoroutine(NextAnim(nowPlaying));
}
else {
IdleAnimation();
isPlaying = false;
}
}
private void IdleAnimation()
{
foreach (AnimatorControllerParameter parameter in animator.parameters) {
animator.SetBool(parameter.name, false);
}
}
IEnumerator Move(ICommand c)
{
animator.SetBool("moving", true);
if (unit.Heading != c.Heading) {
StartCoroutine(SlerpUnit(c.Heading));
}
Vector3 a = unit.transform.position;
Vector3 b = c.End.Position;
float duration = timePerAP * c.AP;
for (float t = 0f; t < 1f; t += Time.deltaTime / duration) {
unit.transform.position = Vector3.Lerp(a, b, t);
yield return null;
}
animator.SetBool("moving", false);
}