Advanced Chase & Alert AI Logic
2This was a slight modification to the AIController, to add more features I wanted in my game, it adds a minimum chase timer, i.e., if you are at the edge of the range of a monster, and attack it and run away, it won’t just stop chasing you, it will chase you outside it’s range for at least the duration of the min chase timer. Secondly, I wanted to alert enemies around the provoked enemy, so there are alert settings, including a radius to alert, and a cooldown so they won’t just keep screaming HELP HELP HELP attack the player.
In Chase Settings Add:
[SerializeField, Min(0.1f)] private float m_minimumChaseDuration = 6.0f;
Add a new Alert Settings:
[Header("Alert Settings")]
public bool wasAlerted = false;
[SerializeField, Min(1.0f)] private float m_alertRadius = 3.0f;
[SerializeField, Min(1.0f)] private float m_alertCooldown = 5.0f;
Add two private variables:
private float m_alertCooldownTimer = 0.0f;
private float m_chaseDurationTimer = 0.0f;
Modify OnProvoked:
private void OnProvoked(CharacterBase source)
{
if (source == null) return;
if (source && !m_target && m_retargetCooldownTimer == 0.0f && CombatSolver.IsJudiciousTarget(m_subject, source))
{
m_target = source;
GameManager.NotificationSystem.targetDetected.Invoke(this, m_subject);
if (!wasAlerted)
{
AlertNearbyAllies(source.transform.position);
wasAlerted = true;
m_alertCooldownTimer = m_alertCooldown;
}
m_chaseDurationTimer = m_minimumChaseDuration; // Start the minimum chase timer
}
}
Add a new helper Method:
private void AlertNearbyAllies(Vector3 attackerPosition)
{
Collider2D[] nearbyAllies = Physics2D.OverlapCircleAll(transform.position, m_alertRadius);
foreach (Collider2D allyCollider in nearbyAllies)
{
if (allyCollider.CompareTag("Enemy"))
{
if (allyCollider.TryGetComponent<CharacterBase>(out CharacterBase allyCharacter))
{
if (allyCharacter.controller is AIController allyAI)
{
if (allyAI != this && allyAI.m_target == null && !allyAI.wasAlerted)
{
allyAI.m_target = this.m_target;
GameManager.NotificationSystem.targetDetected.Invoke(allyAI, m_target);
allyAI.wasAlerted = true;
allyAI.m_alertCooldownTimer = allyAI.m_alertCooldown;
allyAI.m_chaseDurationTimer = allyAI.m_minimumChaseDuration;
}
}
}
}
}
}
Add a new timer into UpdateCooldowns():
if (m_alertCooldown > 0.0f)
{
m_alertCooldownTimer = Math.Max(m_alertCooldownTimer - Time.fixedDeltaTime, 0.0f);
}
Modify CheckIfTargetOutOfRange() Method to use chase timer:
private void CheckIfTargetOutOfRange(float distanceToTarget)
{
// Update the timer
if (m_chaseDurationTimer > 0.0f)
{
m_chaseDurationTimer -= Time.fixedDeltaTime;
}
// Only allow returning if the minimum chase duration has passed
if (m_chaseDurationTimer <= 0.0f)
{
float distanceToInitialPosition = Vector2.Distance(m_initialPosition, transform.position);
bool isTooFarFromInitialPosition = distanceToInitialPosition > m_resetFromInitialPositionRadius;
bool isTooFarFromTarget = distanceToTarget > m_resetFromTargetDistanceRadius;
if (isTooFarFromInitialPosition || isTooFarFromTarget)
{
StopChase(m_targetOutOfRangeRetargetCooldown);
}
}
}
In StopChase(), reset alerted flag:
wasAlerted = false;
In OnFixedUpdate() add:
if (m_alertCooldownTimer <= 0.0f)
{
wasAlerted = false;
}
Also in OnFixedUpdate(), replace the if (!m_target) section with:
if (!m_target)
{
if (m_retargetCooldownTimer == 0.0f)
{
var foundTarget = FindTarget();
if (foundTarget)
{
OnProvoked(foundTarget);
}
}
}

💬 Comments (7)
Glad you like it… I did notice one more optional change depending on how ‘aggressive’ and ‘persistent’ you want monsters to be in the CheckIfTargetOutOfRange() setting the final check to && instead of || - will make it so the monster continues to chase you unless it’s both too far from home and too far from you
Adds a bit more - don’t pull more than you can chew 😉
It’s not that i’m stupid, i’m just lazy (as always), i can do all the steps if it’s really needed
But do you by any chance have the whole “aicontroller” script with all of those stuff added that you can share? 🤔
Want to continue the conversation?