Hello all, pretty new to Unity.
Tl;Dr: I have 2 instances of a prefab, when I try and animate one through its corresponding GameObject, the animation plays for both.
I’ve tried to setup a little 2D sim with a few characters. Two characters are created from the same prefab “Miner”.
What is happening is when an action is invoked on one of those “Miner” characters, it’ll invoke that objects animator and play an animation. But the animation is being played for both of the prefab objects.
My BaseCharacterController is a state machine design pattern, where the controller delegates its behavior to the current CharacterState.
using UnityEngine;
using System.Collections;
// Base class for all character controllers
// CharacterController is a state machine pattern. The context of the state machine is the CharacterController.
// The CharacterState class is the state interface of the state machine.
// CharacterController is a base class for all character controllers.
// It contains the majority of properties and methods for all characters.
// Concrete character controllers mainly just define needed variables and override the Start() method.
public abstract class BaseCharacterController : MonoBehaviour
{
public float m_moveSpeed = 5.0f;
public GameObject m_target;
public CharacterState m_state;
protected virtual void Start()
{
}
public void TransitionTo(CharacterState state)
{
m_state = state;
}
void Update()
{
m_state.Update();
}
void FixedUpdate()
{
m_state.FixedUpdate();
}
void OnTriggerEnter2D(Collider2D other)
{
m_state.OnTriggerEnter2D(other);
}
void OnTriggerStay2D(Collider2D other)
{
m_state.OnTriggerStay2D(other);
}
}
public class PlayerController : BaseCharacterController
{
protected override void Start()
{
base.Start();
TransitionTo(new PlayerStateIdle(this));
}
}
// Base class for all character states
// CharacterState is a state interface of the state machine, which the concrete states inherit from.
// The context of the state machine is the CharacterController.
public abstract class CharacterState
{
protected BaseCharacterController m_context;
public CharacterState(BaseCharacterController context)
{
this.m_context = context;
}
public abstract void Update();
public abstract void FixedUpdate();
public virtual void OnTriggerEnter2D(Collider2D other) { }
public virtual void OnTriggerStay2D(Collider2D other) { }
}
public class PlayerStateDie : CharacterState
{
private float m_respawnCooldownTimer = 5.0f;
public PlayerStateDie(PlayerController context) : base(context)
{
m_context.GetComponent<Animator>().Play("MinerDie");
}
public override void Update()
{
}
public override void FixedUpdate()
{
m_respawnCooldownTimer -= Time.fixedDeltaTime;
if (m_respawnCooldownTimer <= 0)
{
m_context.TransitionTo(new PlayerStateIdle((PlayerController)m_context));
}
}
}
I’ve seen posts describing a similar issue, but the solution always seems to be to invoke the animation function on the GameObject you want to animate. That is being done in the enemy’s logic, where it invokes the function on the enemy’s m_target
public class EnemyStateAttack : EnemyState
{
private float m_attackTimer = 1.0f;
public EnemyStateAttack(EnemyController context) : base(context)
{
Vector2 contextPosition = m_context.transform.position;
Vector2 targetPosition = m_context.m_target.transform.position;
m_context.GetComponent<Animator>().Play(targetPosition.x > contextPosition.x ? "ThiefAttackRight" : "ThiefAttackLeft");
// Transition the target player to the die state
PlayerController targetPlayerController = m_context.m_target.GetComponent<PlayerController>();
targetPlayerController.TransitionTo(new PlayerStateDie(targetPlayerController));
}
public override void Update()
{
}
public override void FixedUpdate()
{
m_attackTimer -= Time.fixedDeltaTime;
if (m_attackTimer <= 0)
{
m_context.m_target = null;
m_context.TransitionTo(new EnemyStateIdle((EnemyController)m_context));
}
}
}