Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question Having trouble getting my animation to loop

Discussion in 'Animation' started by theprogrammersleigh, Mar 26, 2022.

  1. theprogrammersleigh

    theprogrammersleigh

    Joined:
    Mar 18, 2022
    Posts:
    2
    I could use the assistance of a second brain here. I'm making what is essentially an auto-battler with unity. I want characters to identify targets and run towards and continuously attack them until they die, and then go find a new target, etc until this battle is won.

    Everything works great, except for the attacking animation.

    I've attached my scripts below, but essentially the issue is that the attacking prop (found on the Movement Controller) is updating too fast from false back to true. In the inspector you can see the checkmark stuttering. This causes the attack animation to only trigger the first time attacking is set to true.

    I've been reading around some tutorials but since everything else has been centered around triggering animations based on player input I'm at a loss as to how to get the desired result where the npc characters continuously attack each other until one dies.

    It's probably a silly error or logical error of some kind. Just need someone to be my animator rubber ducky right now to solve this lol.



    Code (CSharp):
    1. public class MovementController : MonoBehaviour
    2. {
    3.     public bool moving;
    4.     public bool attacking;
    5.     public float moveSpeed = 1.5f;
    6.  
    7.     private StatsManager statsManager;
    8.     private Transform currentTarget;
    9.     private DetectRange rangeDetector;
    10.     private Vector2 movement;
    11.     private bool m_FacingRight = false;
    12.  
    13.     private void Awake()
    14.     {
    15.         statsManager = GetComponent<StatsManager>();
    16.         rangeDetector = GetComponentInChildren<DetectRange>();
    17.     }
    18.  
    19.     private void Update()
    20.     {
    21.         // Update our target
    22.         currentTarget = FindClosestTarget();
    23.  
    24.         // If no targets, they must be dead
    25.         if (!currentTarget) {
    26.             attacking = false;
    27.             moving = false;
    28.         }
    29.  
    30.         // We're not in range, but we have a target.
    31.         // Must mean we are moving
    32.         if (currentTarget && !rangeDetector.inRange)
    33.         {
    34.             moving = true;
    35.             attacking = false;
    36.  
    37.             // MOVE
    38.             movement.x = currentTarget.transform.position.x - transform.position.x;
    39.             movement.y = currentTarget.transform.position.y - transform.position.y;
    40.  
    41.             // Flip if we must
    42.             Flip(movement.x, movement.y);
    43.         }
    44.         // We have a target and we're in range, attack that sucker
    45.         else if (currentTarget && rangeDetector.inRange) {
    46.             attacking = true;
    47.             moving = false;
    48.         }
    49.     }
    50.  
    51.     private void FixedUpdate()
    52.     {
    53.         if (moving)
    54.         {
    55.             transform.position =
    56.                 Vector2.MoveTowards(transform.position, currentTarget.transform.position, moveSpeed * Time.fixedDeltaTime);
    57.         }
    58.     }
    59.  
    60.     private Transform FindClosestTarget()
    61.     {
    62.         var potentialTargets = GameObject.FindGameObjectsWithTag(statsManager.enemyTag);
    63.         float minDistance = -1f;
    64.         GameObject closestTarget = null;
    65.  
    66.         foreach (var target in potentialTargets)
    67.         {
    68.  
    69.             if (target.GetComponent<StatsManager>().currentHealth == 0f)
    70.             {
    71.                 // Skip if character is dead
    72.                 continue;
    73.             }
    74.  
    75.             var dist = Vector2.Distance(target.transform.position, gameObject.transform.position);
    76.  
    77.             if (dist < minDistance || minDistance == -1f)
    78.             {
    79.                 minDistance = dist;
    80.                 closestTarget = target;
    81.             }
    82.         }
    83.  
    84.         return closestTarget.transform;
    85.     }
    86.     private void Flip(float x, float y)
    87.     {
    88.         if (m_FacingRight && x < 0 || !m_FacingRight && x > 0)
    89.         {
    90.  
    91.             // Switch the way the player is labelled as facing.
    92.             m_FacingRight = !m_FacingRight;
    93.  
    94.             // Multiply the player's x local scale by -1.
    95.             Vector3 theScale = transform.localScale;
    96.             theScale.x *= -1;
    97.             transform.localScale = theScale;
    98.         }
    99.     }
    100. }
    Code (CSharp):
    1. public class AnimController : MonoBehaviour
    2. {
    3.     private Animator anim;
    4.     private MovementController movementScript;
    5.     private StatsManager stats;
    6.     private PolygonCollider2D[] weaponColliders;
    7.  
    8.     //*******************
    9.     //  ANIMATION STATES
    10.     //*******************
    11.     const string RUNNING = "1_Run";
    12.     const string IDLE = "0_idle";
    13.     const string ATTACK_BOW = "2_Attack_Bow";
    14.     const string ATTACK_MAGIC = "2_Attack_Magic";
    15.     const string ATTACK_MELEE = "2_Attack_Normal";
    16.     const string STAGGER = "3_Debuff_Stun";
    17.     const string DEATH = "4_Death";
    18.  
    19.     private void Awake()
    20.     {
    21.         anim = GetComponent<Animator>();
    22.         movementScript = transform.parent.GetComponent<MovementController>();
    23.         stats = transform.parent.GetComponent<StatsManager>();
    24.         weaponColliders = gameObject.FindComponentsInChildrenWithTag<PolygonCollider2D>("weapon");
    25.     }
    26.  
    27.     private void Update()
    28.     {
    29.  
    30.         if (stats.percentageHealth <= 0f)
    31.         {
    32.             anim.Play(DEATH);
    33.         }
    34.         else if (movementScript.moving)
    35.         {
    36.             anim.Play(RUNNING);
    37.         }
    38.         else if (movementScript.attacking)
    39.         {
    40.             anim.Play(ATTACK_MELEE);
    41.         }
    42.         else
    43.         {
    44.             anim.Play(IDLE);
    45.         }
    46.     }
    47.  
    48.     public void EnableWeapon() {
    49.         foreach (PolygonCollider2D weapon in weaponColliders) {
    50.             weapon.enabled = true;
    51.         }
    52.        
    53.     }
    54.  
    55.     public void DisableWeapon() {
    56.         foreach (PolygonCollider2D weapon in weaponColliders)
    57.         {
    58.             weapon.enabled = false;
    59.         }
    60.     }
    61. }
    Code (CSharp):
    1. public class DetectRange : MonoBehaviour
    2. {
    3.     private StatsManager statsManager;
    4.     public bool inRange;
    5.  
    6.     private void Awake()
    7.     {
    8.         statsManager = GetComponentInParent<StatsManager>();
    9.     }
    10.  
    11.     private void OnTriggerEnter2D(Collider2D collision)
    12.     {
    13.         if (collision.transform.tag == statsManager.enemyTag) {
    14.             inRange = true;
    15.         }
    16.     }
    17.  
    18.     private void OnTriggerExit2D(Collider2D collision)
    19.     {
    20.         if (collision.transform.tag == statsManager.enemyTag)
    21.         {
    22.             inRange = false;
    23.         }
    24.     }
    25. }
    26.