Search Unity

Stop enemy movement when Stagger animation plays

Discussion in 'Scripting' started by BorjaZoroza, Jun 22, 2018.

  1. BorjaZoroza

    BorjaZoroza

    Joined:
    Aug 14, 2017
    Posts:
    28
    Hi!

    I've got this code for an enemy in my game, and it's pretty much finished save for one thing:

    When this enemy is hit by a bullet, it plays a short stagger animation.
    But if it's moving towards the player, it'll do this animation while sliding across the floor and it looks silly.
    I'd like to make it so that it stops moving until it's done playing this stagger animation.

    Here's the code. "Hit" refers to the animation I was talking about.

    Code (CSharp):
    1. public Transform player;
    2.     private Animator anim;
    3.     public float health = 50f;
    4.     bool enemyDead = false;
    5.     bool firstAttack = false;
    6.     Collider hitBox;
    7.  
    8.     void Start () {
    9.  
    10.         anim = GetComponent<Animator> ();
    11.         hitBox = GetComponent<Collider> ();
    12.        
    13.     }
    14.        
    15.     void Update () {
    16.  
    17.         if (enemyDead == true)
    18.         {
    19.             this.enabled = false;
    20.         }
    21.  
    22.         Vector3 direction = player.position - this.transform.position;
    23.         float angle = Vector3.Angle (direction, this.transform.forward);
    24.         if(Vector3.Distance(player.position, this.transform.position) < 5 && angle < 60 || firstAttack == true)
    25.         {
    26.            
    27.             direction.y = 0;
    28.  
    29.             this.transform.rotation = Quaternion.Slerp (this.transform.rotation, Quaternion.LookRotation (direction), 0.1f);
    30.  
    31.             anim.SetBool ("isIdle", false);
    32.             if (direction.magnitude > 1.5)
    33.             {
    34.                 this.transform.Translate (0, 0, 0.05f);
    35.                 anim.SetBool ("isWalking", true);
    36.                 anim.SetBool ("isAttacking", false);
    37.             }
    38.             else
    39.             {
    40.                 anim.SetBool ("isAttacking", true);
    41.                 anim.SetBool ("isWalking", false);
    42.  
    43.             }
    44.         }
    45.         else
    46.         {
    47.             anim.SetBool ("isIdle", true);
    48.             anim.SetBool ("isWalking", false);
    49.             anim.SetBool ("isAttacking", false);
    50.         }
    51.     }
    52.  
    53.     public void TakeDamage (float amount)
    54.     {
    55.         health -= amount;
    56.         firstAttack = true;
    57.         if (health > 0f)
    58.         {
    59.         anim.Play ("Hit", 0, 0.2f);
    60.         anim.SetBool ("isIdle", false);
    61.         anim.SetBool ("isWalking", false);
    62.         anim.SetBool ("isAttacking", false);
    63.         }
    64.  
    65.         if (health <= 0f)
    66.         {
    67.             Die();
    68.         }
    69.     }
    70.  
    71.     void Die()
    72.     {
    73.         hitBox.enabled = !hitBox.enabled;
    74.         anim.SetBool ("isDead", true);
    75.         anim.SetBool ("isHit", false);
    76.         anim.SetBool ("isIdle", false);
    77.         anim.SetBool ("isWalking", false);
    78.         anim.SetBool ("isAttacking", false);
    79.         enemyDead = true;
    80.  
    81.     }
    82. }
    83.  
    Any ideas on how to achieve this?
     
  2. dgoyette

    dgoyette

    Joined:
    Jul 1, 2016
    Posts:
    4,195
    Well, once super simple approach is to just stop moving your character for a short time after getting hit. For that you could set a private float value (for example, _timeSinceLastHit) to 0. Increment that in every Update by Time.deltaTime, and only perform your movement code when that value is higher than a certain amount, like 0.5 or 1, depending on how long you want the character to be stunned.
     
  3. BorjaZoroza

    BorjaZoroza

    Joined:
    Aug 14, 2017
    Posts:
    28
    That could work, but I also wanted to add a pause menu in the future. Wouldn't Time.deltaTime mess with that?
     
  4. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    It would depend on how you implement your pause feature. For example, if you use time scale (setting it to zero along with Time.fixedDeltaTime), that will affect all frame rate related calls.
     
  5. BorjaZoroza

    BorjaZoroza

    Joined:
    Aug 14, 2017
    Posts:
    28
    I tried using dgoyette's system, but it doesn't seem to be working, even though I set that private float value back to 0 each time the stagger animation is triggered. Here's what I've got:

    Code (CSharp):
    1.     public Transform player;
    2.     private Animator anim;
    3.     public float health = 50f;
    4.     bool strangerDead = false;
    5.     bool firstBlood = false;
    6.     Collider hitBox;
    7.     public GameObject attackCollider;
    8.  
    9.     private float lastHit = 0;
    10.  
    11.     void Start () {
    12.  
    13.  
    14.         anim = GetComponent<Animator> ();
    15.         hitBox = GetComponent<Collider> ();
    16.         attackCollider.SetActive (false);
    17.        
    18.     }
    19.        
    20.     void Update () {
    21.  
    22.         lastHit += Time.deltaTime;
    23.  
    24.         if (strangerDead == true)
    25.         {
    26.             attackCollider.SetActive (false);
    27.             this.enabled = false;
    28.         }
    29.  
    30.         Vector3 direction = player.position - this.transform.position;
    31.         float angle = Vector3.Angle (direction, this.transform.forward);
    32.         if(Vector3.Distance(player.position, this.transform.position) < 5 && angle < 60 || health < 50 || lastHit == 1)
    33.         {
    34.            
    35.             direction.y = 0;
    36.  
    37.             this.transform.rotation = Quaternion.Slerp (this.transform.rotation, Quaternion.LookRotation (direction), 0.1f);
    38.  
    39.             anim.SetBool ("isIdle", false);
    40.             if (direction.magnitude > 1.5)
    41.             {
    42.                 this.transform.Translate (0, 0, 0.05f);
    43.                 anim.SetBool ("isWalking", true);
    44.                 anim.SetBool ("isAttacking", false);
    45.                 attackCollider.SetActive (false);
    46.             }
    47.             else
    48.             {
    49.                 anim.SetBool ("isAttacking", true);
    50.                 anim.SetBool ("isWalking", false);
    51.                 if (health > 0f)
    52.                 {
    53.                 attackCollider.SetActive (true);
    54.                 }
    55.             }
    56.         }
    57.         else
    58.         {
    59.             anim.SetBool ("isIdle", true);
    60.             anim.SetBool ("isWalking", false);
    61.             anim.SetBool ("isAttacking", false);
    62.             attackCollider.SetActive (false);
    63.         }
    64.     }
    65.  
    66.     public void TakeDamage (float amount)
    67.     {
    68.         lastHit = 0;
    69.         health -= amount;
    70.         firstBlood = true;
    71.         if (health > 0f)
    72.         {
    73.         anim.Play ("Hit", 0, 0.2f);
    74.         anim.SetBool ("isIdle", false);
    75.         anim.SetBool ("isWalking", false);
    76.         anim.SetBool ("isAttacking", false);
    77.         }
    78.  
    79.         if (health <= 0f)
    80.         {
    81.             Die();
    82.         }
    83.     }
    84.  
    85.     void Die()
    86.     {
    87.         hitBox.enabled = !hitBox.enabled;
    88.         anim.SetBool ("isDead", true);
    89.         anim.SetBool ("isHit", false);
    90.         anim.SetBool ("isIdle", false);
    91.         anim.SetBool ("isWalking", false);
    92.         anim.SetBool ("isAttacking", false);
    93.         strangerDead = true;
    94.  
    95.     }
    96. }
    97.  
    98.  
    "lastHit" should prevent the enemy from moving until the float value reaches 1 again, but for some reason it's disregarding the TakeDamage void (where it sets the value back to 0).
    Maybe I'm just tired, but I can't spot the error here.
     
  6. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    Have you stepped it through in the debugger?
     
  7. BorjaZoroza

    BorjaZoroza

    Joined:
    Aug 14, 2017
    Posts:
    28
    I have, it does register lastHit's value going back to 0 but then for some reason it doesn't interrupt enemy movement.
     
  8. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    You mean the enemy "hit" animation plays but the enemy keeps moving rather than remaining at the same position? Are you expecting the Update() method to do nothing whilst lastHit is zero?
     
  9. BorjaZoroza

    BorjaZoroza

    Joined:
    Aug 14, 2017
    Posts:
    28
    Yeah, that's what I meant. Update shouldn't do anything else.
     
  10. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    Try adding a check as the first thing at the beginning of
    Update()
    to return immediately if lastHit is zero.
     
    BorjaZoroza likes this.
  11. BorjaZoroza

    BorjaZoroza

    Joined:
    Aug 14, 2017
    Posts:
    28
    That was it! It's working!

    Thank you so much, it was driving me crazy! :D
     
    Doug_B likes this.