Stop aggro from getting called every frame

I included some code to make sure enemies can only get aggroed after cooldown time. But the else if statement never gets executed, i dunno why.

private void AttackBehaviour()
        {
            fighter.Attack(player);
            // only aggrevate nearby enemies if you havent already done so.
            if (aggrevated == false)
            {
                AggrevateNearbyEnemies();
                aggrevated = true;
            }
             
            else if (aggrevated == true && timeSinceAggrevated > agroCooldownTime)
            {
                aggrevated = false;
                timeSinceAggrevated = Mathf.Infinity;
            }    
        }

Do you set timeSinceAggrevated? You’re not showing it. What does the code that calls AttackBehaviour() look like?

As @bixarrio points out… we don’t have enough information to determine why the if statement is never called. Paste in your full AIController.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using RPG.Combat;
using RPG.Core;
using RPG.Movement;
using RPG.Attributes;
using System;
using GameDevTV.Utils;

namespace RPG.Control
{
    public class AIController : MonoBehaviour
    {
        [SerializeField] float defaultChaseDistance = 5f;
        [SerializeField] float chaseDistance = 5f;
        [SerializeField] float suspicionTime = 5f;
        [SerializeField] float WaypointDwellTime = 3f;
        [SerializeField] float agroCooldownTime = 3f;
        [SerializeField] float shoutDistance = 10f;
        bool aggrevated = false;
        
        // makes sure patrolSpeedFraction can only be between 0 and 1.
        // incase we give it an absurd value.
        [Range(0,1)]
        // 20 % of maxspeed.
        [SerializeField] float patrolSpeedFraction = 0.2f;
        // must add patrolpath gameobject with patrolpath script in unity
        // since each patrolpath is different and must be attached to only one enemy.
        [SerializeField] PatrolPath patrolPath;
        [SerializeField] float waypointTolerance = 1f;
        

        Fighter fighter;
        GameObject player;
        Health health;
        Mover mover;
        LazyValue<Vector3> guardPosition;

        // when we start the game, last time since guard saw player is very large, no delay.
        float timeSinceLastSawPlayer = Mathf.Infinity;
        // dwell at waypoints.
        float timeSinceArrivedAtWaypoint = Mathf.Infinity;
        // timer for when we stop aggro. start as not aggrevated.
        float timeSinceAggrevated = Mathf.Infinity;
        // waypoint guard should walk to.
        int currentWaypointIndex = 0;

        // set up all states in awake. if another start method tries to use a public method in this script
        // that uses any of these states, they might not be there if initialized in start.
        private void Awake()
        {
            fighter = GetComponent<Fighter>();
            player = GameObject.FindWithTag("Player");
            health = GetComponent<Health>();
            mover = GetComponent<Mover>();
            // must be ready before start if we use guardposition in another class start method.
            guardPosition = new LazyValue<Vector3>(GetGuardPosition);
        }

        private Vector3 GetGuardPosition()
        {
            return transform.position;
        }
        private void Start()
        {
            // sets the start position of the guard.
            guardPosition.ForceInit();
        }



        private void Update()
        {
            // if enemy is dead do nothing. Cant move when dead.
            if (health.IsDead()) return;
            // make enemy chase and attack player. Enemy are withing the range of the player and player is not dead or null.
            if (isAggrevated() && fighter.CanAttack(player))
            {
                // reset suspicion variable when we attack.
                timeSinceLastSawPlayer = 0;
                // move thowards enemy to attack.
                AttackBehaviour();
            }
            // suspicion state. guard should wait before returning to post.
            else if (timeSinceLastSawPlayer < suspicionTime)
            {
                SuspicionBehaviour();
                // set chase distance back to original chase distance after we shot a projectile and have run outside of his chasedistance.
                chaseDistance = defaultChaseDistance;
                
            }
            else
            {
                PatrolBehaviour();
            }
            // updates time every frame
            timeSinceLastSawPlayer += Time.deltaTime;
            timeSinceArrivedAtWaypoint += Time.deltaTime;
            timeSinceAggrevated += Time.deltaTime;
            print("AGGREVATED" + timeSinceAggrevated + aggrevated);
            // If his no longer aggroed he can aggro again.
            
        }

        public void Aggrevate()
        {
            // starts aggro.
            timeSinceAggrevated = 0;
        }

        private void PatrolBehaviour()
        {
            // no patrol path, just use start position.
            Vector3 nextPosition = guardPosition.value;
            // if the guard has a patrol path.
            if(patrolPath != null)
            {
                // when we are close enough to a waypoint.
                if (AtWaypoint())
                {
                    timeSinceArrivedAtWaypoint = 0;
                    // we get the next waypoint index.
                    CycleWayPoint();
                                        
                }
                // we get the vector, the position of the waypoint. 
                nextPosition = GetCurrentWaypoint();
            }
            // moves guard to next waypoint after guard has dwelled. Enemy will stop 
            // following us when we are out of range or dead. And moves back to nextposition, last waypoint. 
            if (timeSinceArrivedAtWaypoint > WaypointDwellTime)
            {
                mover.StartMoveAction(nextPosition, patrolSpeedFraction);
            }
            
        }

        // when we are close to a waypoint return true.
        private bool AtWaypoint()
        {
            float distanceToWaypoint = Vector3.Distance(transform.position, GetCurrentWaypoint());
            return distanceToWaypoint < waypointTolerance;
        }

        // Gets next index. if the guard is already at last waypoint, currentWayPointIndex
        // is the last waypoint, we get the first index for the first waypoint.
        private void CycleWayPoint()
        {
            currentWaypointIndex = patrolPath.GetNextIndex(currentWaypointIndex);
        }

        // Get waypoints position at index. 
        private Vector3 GetCurrentWaypoint()
        {
            return patrolPath.GetWayPoint(currentWaypointIndex);
        }

        
        private void SuspicionBehaviour()
        {
            // cancel action, stops to be suspicious.
            GetComponent<ActionScheduler>().CancelCurrentAction();
        }

        private void AttackBehaviour()
        {
            fighter.Attack(player);
            // only aggrevate nearby enemies if you havent already done so.
            if (aggrevated == false)
            {
                AggrevateNearbyEnemies();
                aggrevated = true;
            }
             
            else if (aggrevated == true && timeSinceAggrevated > agroCooldownTime)
            {
                aggrevated = false;
                timeSinceAggrevated = Mathf.Infinity;
            }    
        }

        // Aggro enemies within a radius of aggrevated enemy.
        private void AggrevateNearbyEnemies()
        {
            // Find all enemies within a certain radius. Centered on enemy, radius out from enemy, direction of sphere(just around enemy),
            // max distance(0 dont wont to move sphere anywhere no distance just a radius around enemy) we get an array of raycasthits. 
            RaycastHit[] hits = Physics.SphereCastAll(transform.position, shoutDistance, Vector3.up, 0);

            foreach (RaycastHit hit in hits)
            {
                AIController ai = hit.transform.GetComponent<AIController>();
                // If what we hit has not an AIController we continue with for loop.
                if (ai == null) continue;
                // else we aggrevate enemy.
                ai.Aggrevate();
                     
            }
        }

        // Enemy is aggrevated or not. True if aggrevated.
        private bool isAggrevated()
        {
            // distance between enemy and player.
            float distanceToPlayer = Vector3.Distance(player.transform.position, transform.position);
            // returns true if we are withing chasedistance or if enemy is still aggrevated.
            return distanceToPlayer < chaseDistance || timeSinceAggrevated < agroCooldownTime;
        }
        // unity will call this when you want to draw gizmos.
        // draws a sphere around the enemy.
        private void OnDrawGizmosSelected()
        {
            Gizmos.color = Color.blue;
            // draw a lined sphere. center of sphere, radius.
            Gizmos.DrawWireSphere(transform.position, chaseDistance);
        }

        public void SetChaseDistance(float weaponRange)
        {
            chaseDistance = weaponRange;
        }
    }
}

I guess I’m not clear on what the intent is…
The character should quit being aggravated after it hasn’t seen the player (or gotten the aggrevated signal from another character) since the aggroCooldownTime.
There is a small bug that Sam never corrected, however, where once a character is aggrevated, as it aggrevates nearby enemies, it winds up aggrevating itself…

In AggrevateNearbyEnemies, make this slight change to the if statement

if(ai==null || ai==this) continue;

Thnx! The intent is that enemy only gets aggrevated if aggrevated is false. then after agrocooldowntime is large enough its set to false again and he can get aggrevated again.

Your solution worked great, but im not sure how it works?

The problem with the original course code is that when we AggrevateNearbyEnemies, we also Aggrevate ourselves… but in circumstances where the player has eluded the enemy, the enemy is still aggrevated, and still resetting the countdown…

In terms of what you’re describing, there’s actually a simpler solution (leave the “this” trap in place, that’s an outright bug).

public void Aggrevate()
{
   if(!(timeSinceAggrevated < aggroCooldownTime))
   {
         timeSinceAggrevated = 0:
    }
}

thnx!

This topic was automatically closed 20 days after the last reply. New replies are no longer allowed.

Privacy & Terms