Search Unity

[SOLVED] Why my enemy knockback coroutine is so slow and choppy?

Discussion in 'Scripting' started by Pixitales, Jun 3, 2019.

  1. Pixitales

    Pixitales

    Joined:
    Oct 24, 2018
    Posts:
    227
    I am still a beginner. I want to make a game similar to zelda link to the past when you hit an enemy with your sword, it knocks back the enemy. I don't know why my knockback coroutine is running so slow and the knockback movement is so choppy i.e moving down 1 pixel per unit. Theres another knock back script for player similar to this and it works very smoothly for but not for enemy.

    The enemy has 2 box colliders and one of them is a trigger with rigidbody2d. My sword has one polygon collider which only turns on when I swing my sword. I added a debug and it shows the message so slow, where as the player knockback shows 45+ debug messages in one second. I have about 4 coroutines in the game and only 1 is running very slow. Why is that?

    Here are my scripts, have fun and you might learn something:

    Enemy script is a bit messy at the moment. Trying to fix the problem first.
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public enum EnemyState
    6. {
    7.     idle,
    8.     walk,
    9.     attack,
    10.     stagger
    11. }
    12.  
    13. public class Enemy : Character
    14. {
    15.     public EnemyState currentState;
    16.     public string enemyName;
    17.     private float maxHealth;
    18.     public float currentHealth;
    19.     public float damage;
    20.     public float thrust;
    21.  
    22.     private Vector3 startPosition;
    23.  
    24.     public Transform target;
    25.     public float chaseRadius;
    26.     public float attackRadius;
    27.  
    28.     public float knockbackLength;
    29.     public float knockbackDistance;
    30.  
    31.     private bool isBeingAttacked = false;
    32.  
    33.     private void Awake()
    34.     {
    35.         maxHealth = currentHealth;
    36.  
    37.         //startPosition = transform.position; //Set enemy start position
    38.     }
    39.  
    40.     protected override void Start()
    41.     {
    42.         base.Start();
    43.  
    44.         currentState = EnemyState.idle;
    45.  
    46.         target = GameObject.FindWithTag("Player").transform;
    47.     }
    48.  
    49.     protected override void Update()
    50.     {
    51.         base.Update();
    52.     }
    53.  
    54.     public void FixedUpdate()
    55.     {
    56.         CheckDistance();
    57.     }
    58.  
    59.  
    60.     //-------------------------------------------------------------
    61.     //--------IF PLAYER IN RANGE, FOLLOW
    62.     //-------------------------------------------------------------
    63.     public void CheckDistance()
    64.     {
    65.         if (IsAlive &&!IsAttacking && !isBeingAttacked && currentState != EnemyState.stagger)
    66.         {
    67.             if (Vector2.Distance(target.position, transform.position) <= chaseRadius)
    68.             {
    69.                 if (currentState == EnemyState.idle || currentState == EnemyState.walk && currentState != EnemyState.stagger)
    70.                 {
    71.                     Direction = (target.transform.position - transform.position);
    72.  
    73.                     transform.position = Vector2.MoveTowards(transform.position, target.position, MoveSpeed * Time.deltaTime);
    74.  
    75.                     float distance = Vector2.Distance(target.position, transform.position);
    76.  
    77.                     //currentState = EnemyState.walk;
    78.                     //MyAnimator.SetBool("wakeUp", true);
    79.  
    80.                     if (distance < attackRadius)
    81.                     {
    82.                         IsAttacking = true;
    83.  
    84.                         Direction = Vector2.zero;
    85.                     }
    86.                 }
    87.             }
    88.             else if (Vector2.Distance(target.position, transform.position) > chaseRadius && currentState != EnemyState.stagger)
    89.             {
    90.                 Direction = (startPosition - transform.position).normalized;
    91.  
    92.                 transform.position = Vector2.MoveTowards(transform.position, startPosition, MoveSpeed * Time.deltaTime);
    93.  
    94.                 float distance = Vector2.Distance(startPosition, transform.position);
    95.  
    96.                 if (Vector3.Distance(startPosition, transform.position) <= 0)
    97.                 {
    98.                     Direction = Vector2.zero;
    99.                 }
    100.             }
    101.         }
    102.     }
    103.  
    104.     //-------------------------------------------------------------
    105.     //--------TAKE DAMAGE AND CHECK CURRENT HEALTH
    106.     //-------------------------------------------------------------
    107.     public void TakeDamage(float damage)
    108.     {
    109.         currentHealth -= damage;
    110.         if (currentHealth <= 0)
    111.         {
    112.             SoundManager.PlaySound("Kill");
    113.             this.gameObject.SetActive(false);
    114.         }
    115.     }
    116.  
    117.  
    118.     //-------------------------------------------------------------
    119.     //--------If Player hits Enemy with a weapon
    120.     //-------------------------------------------------------------
    121.     private void OnTriggerEnter2D(Collider2D other)
    122.     {
    123.         //If Player hits an Enemy with a weapon
    124.         if (other.gameObject.tag == "Weapon")
    125.         {
    126.             SoundManager.PlaySound("Hit");
    127.  
    128.             currentState = EnemyState.stagger;
    129.  
    130.             StartCoroutine(KnockbackCoroutine((this.transform.position - other.transform.position).normalized));
    131.         }
    132.  
    133.         //If Player touches an Enemy, give damage to Player
    134.         if (other.gameObject.CompareTag("Player"))
    135.         {
    136.             other.GetComponent<PlayerController>().TakeDamage(damage);
    137.         }
    138.     }
    139.  
    140.     private IEnumerator KnockbackCoroutine(Vector2 direction)
    141.     {
    142.         if (IsAlive)
    143.         {
    144.             Vector2 startPos = this.transform.position;
    145.  
    146.             //Knock back player
    147.             Vector2 targetPosition = startPos + (direction * knockbackDistance);
    148.  
    149.             //Knockback Length
    150.             float t = 0;
    151.  
    152.             while (t != knockbackLength)
    153.             {
    154.                 t = Mathf.MoveTowards(t, knockbackLength, Time.deltaTime);
    155.  
    156.                 SetPosition(Vector3.Lerp(startPos, targetPosition, t / knockbackLength));
    157.  
    158.                Debug.Log("knockback enemy");
    159.  
    160.                 yield return new WaitForSeconds(1f);
    161.  
    162.                 currentState = EnemyState.walk;
    163.  
    164.                 yield return null;
    165.             }
    166.         }
    167.     }
    168. }
    Player Script
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public enum PlayerState
    6. {
    7.     walk,
    8.     attack,
    9.     interact,
    10.     stagger,
    11.     idle
    12. }
    13.  
    14. public class PlayerController : Character
    15. {
    16.     public PlayerState currentState;
    17.     public float initHealth = 100;
    18.  
    19.     public float attackCooldown; //Cooldown
    20.     private float nextAttackTimer;
    21.  
    22.     public float knockbackLength;
    23.     public float knockbackDistance;
    24.  
    25.     public bool delayMove = false;
    26.  
    27.     [SerializeField]
    28.     private Stat health;
    29.  
    30.     protected override void Start()
    31.     {
    32.         base.Start();
    33.  
    34.         health.Initialize(initHealth, initHealth);
    35.  
    36.         currentState = PlayerState.idle;
    37.     }
    38.  
    39.     protected override void Update()
    40.     {
    41.         base.Update();
    42.  
    43.         GetInputs();
    44.     }
    45.  
    46.     //-------------------------------------------------------------
    47.     //--------KEYBOARD CONTROLS/INPUTS
    48.     //-------------------------------------------------------------
    49.     private void GetInputs()
    50.     {
    51.         Direction = Vector2.zero;
    52.  
    53.         if (Input.GetKey(KeyCode.W) && !delayMove || Input.GetKey(KeyCode.UpArrow) && !delayMove)
    54.         {
    55.             Direction += Vector2.up;
    56.         }
    57.  
    58.         if (Input.GetKey(KeyCode.A) && !delayMove || Input.GetKey(KeyCode.LeftArrow) && !delayMove)
    59.         {
    60.             Direction += Vector2.left;
    61.         }
    62.  
    63.         if (Input.GetKey(KeyCode.S) && !delayMove || Input.GetKey(KeyCode.DownArrow) && !delayMove)
    64.         {
    65.             Direction += Vector2.down;
    66.         }
    67.  
    68.         if (Input.GetKey(KeyCode.D) && !delayMove || Input.GetKey(KeyCode.RightArrow) && !delayMove)
    69.         {
    70.             Direction += Vector2.right;
    71.         }
    72.  
    73.         if (Input.GetKeyDown(KeyCode.Space) && !IsAttacking && IsAlive && Time.time > nextAttackTimer && currentState != PlayerState.attack && currentState != PlayerState.stagger)
    74.         {
    75.             nextAttackTimer = Time.time + attackCooldown;
    76.             StartCoroutine(MeleeAttack());
    77.         }
    78.  
    79.         //------DEBUGGING ONLY-----------------------
    80.         if (Input.GetKeyDown(KeyCode.I))
    81.         {
    82.             health.MyCurrentValue -= 10;
    83.             //mana.MyCurrentValue -= 10;
    84.         }
    85.         if (Input.GetKeyDown(KeyCode.O))
    86.         {
    87.             health.MyCurrentValue += 10;
    88.             //mana.MyCurrentValue += 10;
    89.         }
    90.  
    91.         if (!IsMoving && !IsAttacking && currentState != PlayerState.stagger)
    92.         {
    93.             currentState = PlayerState.idle;
    94.         }
    95.         else if(IsMoving && !IsAttacking)
    96.         {
    97.             currentState = PlayerState.walk;
    98.         }
    99.  
    100.         //------END OF DEBUGGING ---------------------
    101.     }
    102.  
    103.  
    104.     //-------------------------------------------------------------
    105.     //--------SWORD ATTACK
    106.     //-------------------------------------------------------------
    107.     public IEnumerator MeleeAttack()
    108.     {
    109.         IsAttacking = true;
    110.         currentState = PlayerState.attack;
    111.         delayMove = true;
    112.         MyAnimator.SetTrigger("attacking 0");
    113.         SoundManager.PlaySound("Sword");
    114.  
    115.         yield return null;
    116.  
    117.         IsAttacking = false;
    118.  
    119.         yield return new WaitForSeconds(.6f);
    120.  
    121.         delayMove = false;
    122.         currentState = PlayerState.walk;
    123.     }
    124.  
    125.     //-------------------------------------------------------------
    126.     //--------TAKE DAMAGE FROM ENEMIES
    127.     //-------------------------------------------------------------
    128.     public void TakeDamage(float damage)
    129.     {
    130.         health.MyCurrentValue -= damage;
    131.         currentState = PlayerState.stagger;
    132.  
    133.         if (health.MyCurrentValue > 0)
    134.         {
    135.             StartCoroutine("DamageFlash");
    136.         }
    137.     }
    138.  
    139.     //-------------------------------------------------------------
    140.     //--------TAKE DAMAGE COLLIDING WITH ENEMIES
    141.     //-------------------------------------------------------------
    142.     public void OnCollisionEnter2D(Collision2D other)
    143.     {
    144.         if (other.gameObject.tag == "Enemy" && other.gameObject != null && health.MyCurrentValue > 0)
    145.         {
    146.             SoundManager.PlaySound("PlayerHurt");
    147.  
    148.             currentState = PlayerState.stagger;
    149.  
    150.             StartCoroutine(MoveCoroutine((this.transform.position - other.transform.position).normalized));
    151.         }
    152.     }
    153.  
    154.     private IEnumerator MoveCoroutine(Vector2 direction)
    155.     {
    156.         Vector2 startPos = this.transform.position;
    157.  
    158.         //Knock back player
    159.         Vector2 targetPosition = startPos + (direction * knockbackDistance);
    160.  
    161.         //Knockback Length
    162.         float t = 0;
    163.  
    164.         while (t != knockbackLength)
    165.         {
    166.             t = Mathf.MoveTowards(t, knockbackLength, Time.deltaTime);
    167.  
    168.             SetPosition(Vector3.Lerp(startPos, targetPosition, t / knockbackLength));
    169.  
    170.             yield return null;
    171.  
    172.             currentState = PlayerState.walk;
    173.  
    174.             Debug.Log("player takes damage");
    175.         }
    176.     }
    177.  
    178.     //-------------------------------------------------------------
    179.     //--------FLASH COLOR WHEN PLAYER TAKES DAMAGE
    180.     //-------------------------------------------------------------
    181.     public IEnumerator DamageFlash()
    182.     {
    183.         new Color32(254, 152, 203, 255);
    184.         GetComponent<SpriteRenderer>().material.color = new Color32(255, 160, 171, 255); //Pink
    185.         yield return new WaitForSeconds(0.3f);
    186.         GetComponent<SpriteRenderer>().material.color = Color.white;
    187.     }
    188. }
    189.  
     
    Last edited: Jun 3, 2019
  2. Pixitales

    Pixitales

    Joined:
    Oct 24, 2018
    Posts:
    227
    Looks like I narrow down to the problem.... This line on my enemy script "yield return new WaitForSeconds(1f);" Its slowing the whole coroutine down. But I do really need to wait for seconds there.

    I rewrite this part and it works!
    Code (CSharp):
    1.     private IEnumerator KnockbackCoroutine(Vector2 direction)
    2.     {
    3.         if (IsAlive)
    4.         {
    5.             Vector2 startPos = this.transform.position;
    6.  
    7.             //Knock back player
    8.             Vector2 targetPosition = startPos + (direction * knockbackDistance);
    9.  
    10.             //Knockback Length
    11.             float t = 0;
    12.  
    13.             while (t != knockbackLength)
    14.             {
    15.                 t = Mathf.MoveTowards(t, knockbackLength, Time.deltaTime);
    16.  
    17.                 SetPosition(Vector3.Lerp(startPos, targetPosition, t / knockbackLength));
    18.  
    19.                 Debug.Log("knockback enemy");
    20.  
    21.                 yield return null;
    22.             }
    23.         }
    24.  
    25.         yield return new WaitForSeconds(2f);
    26.  
    27.         currentState = EnemyState.walk;
    28.     }
     
    Last edited: Jun 3, 2019