Home > Software design >  How can I make an enemy stop for half a second after attacking? Unity2D
How can I make an enemy stop for half a second after attacking? Unity2D

Time:11-29

After the enemy collides with the player I want him to stop for some time, so it doesnt chase after him all the time. It looks weird. Like, add an Invoke function or something(not a pro). Would appreciate your help) Here is the code(I was following some 7 hour tutorial):

// Experience
public int xpValue = 1;

//Particle system
public GameObject effect;

// Logic
public float triggerLength = 1;
public float chaseLength = 5;
public bool chasing;
public bool collidingWithPlayer;
private Transform playerTransform;
private Vector3 startingPosition;

// Hitbox
public ContactFilter2D filter;
private BoxCollider2D hitbox;
private Collider2D[] hits = new Collider2D[10];

protected override void Start()
{
    base.Start();
    playerTransform = GameManager.instance.player.transform;
    startingPosition = transform.position;
    hitbox = transform.GetChild(0).GetComponent<BoxCollider2D>();
}

protected void FixedUpdate(){
    //Is the player in range?
    if(Vector3.Distance(playerTransform.position, startingPosition) < chaseLength)
    {
        if(Vector3.Distance(playerTransform.position, startingPosition) < triggerLength)
        chasing = true;

        if (chasing){
            if(!collidingWithPlayer){
                UpdateMotor((playerTransform.position - transform.position).normalized);
            }
        }
        else{
            UpdateMotor(startingPosition - transform.position);
        }
    }
    else{
        UpdateMotor(startingPosition - transform.position);
        chasing = false;
    }

    //Check for overlap
    collidingWithPlayer = false;
    boxCollider.OverlapCollider(filter, hits); // null reference expection
    for (int i = 0; i < hits.Length; i  )
    {
        if (hits[i] == null)\

            continue;

            if(hits[i].tag == "Fighter" && hits[i].name == "Player"){
                collidingWithPlayer = true;
            }

        //this array is not cleaned up, so we do it ourself
        hits[i] = null;
    }
}

CodePudding user response:

You will probably want to use either Coroutines or timers to achieve this. This is untested and there is likely some optimization that can be done on this.

Timers

private bool hasAttacked = false;

private float attackTimer = 0;
private float waitTime = 0.5f;

private void Update()
{
   if (!hasAttacked)
   {
      hasAttacked = true;
      attack();
      attackTimer = Time.time   waitTime;
   }
   else
   {
      if ( Time.time > attackTimer)
      {
         hasAttacked = false;
      }
   }
}

This snippet will run an attack function, then wait for 0.5 seconds, and run the code again.

CodePudding user response:

Easiest solution would be to look into coroutines. They run on the main thread but can be paused and wait for delays or events.

bool CanAttack() => true;
void Attack() { }

void Start()
{
    StartCoroutine(AttackLoop());
}

IEnumerator AttackLoop()
{
    while (true)
    {
        //Check if enemy can attack
        if (CanAttack())
        {
            Attack();
            //Waits 2 seconds before continuing
            yield return new WaitForSeconds(2f);
        }

        //Wait one frame
        //Prevents an infinite loop
        yield return null;

        //Some other Examples
        //Wait until true
        yield return new WaitUntil(CanAttack);
        //Wait until false
        yield return new WaitWhile(CanAttack);
    }
}
  • Related