Enemy AI and Navigation - UQcsse3200/2026-studio-4 GitHub Wiki

Enemy AI and Navigation

Implementation baseline: main at 78c7cd4, checked on 21 October 2026.

Overview

This page documents Team 1 enemy pursuit, attack interruption and obstacle handling. Enemies lists skins, statistics, resources and room/death integration. Boss-specific controllers remain documented on their encounter pages.

Task selection and movement ownership

The shared AITaskComponent selects tasks by priority. Chase/split enemies built by NPCFactory.createChaseEnemy receive wandering, GroundChaseTask (priority 10) and LungeAttackTask (priority 20). A lunge temporarily owns movement; pursuit resumes afterwards if the target remains eligible. PhysicsMovementComponent executes the selected movement destination.

Ground pursuit uses a 3-unit acquisition range and 10-unit retention range in this factory. A previously acquired target remains remembered when a higher-priority attack interrupts pursuit. A concealed target is not eligible for pursuit; the active task stops movement and clears its route when it loses eligibility.

This assembly is specific to the chase/split archetypes. Bombs and giants still use their configured ChaseTask, while flying enemies use patrol/ranged behaviour. Boss navigation uses separate controllers.

Ground obstacle navigation

ObstacleNavigation uses solid physics fixtures and the mover's actual collider footprint. Walkable sensors are ignored. Pursuit checks also account for other solid bodies while allowing contact with the intended target.

  1. If the entire footprint can move directly to the target, chase uses that direct destination.
  2. Otherwise, a local path is searched around obstacles. When the target stands too near a wall or crowd, reachable approach positions are considered.
  3. Routes are replanned on a 400 ms interval while blocked. A waypoint is skipped only when the full collider can reach a later waypoint safely.
  4. If no route segment is safely reachable, movement stops rather than cutting through the obstacle. Movement limiting prevents overshooting the selected waypoint.
  5. After 500 ms without sufficient progress, the task can yield to a lower-ID moving neighbour for up to 900 ms, using a short clear retreat position. A deliberately reached approach position is not treated as a traffic jam.

The local search is bounded; it is not a guarantee of a route through every crowded or impossible layout. Room entry, corners, narrow passages and large colliders need in-game checks in addition to algorithm tests.

Lunge and hit recovery

LungeAttackTask gives an attack higher priority than ordinary pursuit. Stopping that attack must allow chase to restart with the retained target. Obstacle checks and movement limiting apply to movement independently of the task's animation.

Medusa adds MedusaHitRecoveryComponent. An effective, nonlethal player hit starts or refreshes a 350 ms recovery window. It cancels the pending/current lunge, immobilises the enemy, suppresses its contact damage and prevents hit knockback during recovery. The Medusa-specific factory uses a 3-second lunge cooldown and 1.5-second contact interval. Split children receive the same recovery behaviour.

Minotaur uses MinotaurAnimationController, MinotaurAttackRenderComponent and MinotaurDashTrailComponent instead of generic touch damage. Its damage window follows the axe attack and is limited to one hit per attack; normal attacks, post-charge attacks, directional visuals and dash trails must stay synchronised. The attack/visual contribution was supplied by Team 5 in PR #312 and integrated with Team 1 pursuit.

Flying patrol and wall-safe projectiles

FlyingEnemyPatrolComponent builds a triangular PatrolTask around the actual spawn position. The same patrol task supports Sleipnir's rectangular route through its non-flying mode. Spawn-relative construction prevents patrols being centred on an unrelated world origin.

Flying ranged attacks use ProjectileMovementComponent and the selected theme's projectile atlas, with a shared fallback. Projectile obstacle checks sweep along movement, preventing a fast shot from crossing a wall between updates. The room owns spawned projectiles but does not count them as enemies required for room completion.

Snake underground navigation

The Snake encounter uses SnakeBurrowNavigator, SnakeBurrowCollision and SnakeBurrowArena, not GroundChaseTask. Its underground route and emergence positions are constrained by room bounds, walls and its footprint. It can detour/replan when blocked, and an unsafe emergence is cancelled. Burrowing immunity and health-bar visibility remain separate responsibilities of the encounter controller.

Integration rules

  • Keep room placement checks, route clearance and attack collision checks separate: a valid spawn position does not imply a safe path or attack.
  • Use the entity's actual collider dimensions when adding or rescaling an enemy.
  • Preserve concealment and task-stop checks when adding a new pursuit task.
  • Use deferred spawn/disposal for physics objects and clear timers, routes and owned projectiles on death/room disposal.
  • Do not give non-splitting chase variants a SplitComponent; splitting is a separate death-triggered behaviour.

Tests and sources

Ground movement: GroundChaseTask.java, ObstacleNavigation.java, PhysicsMovementComponent.java, GroundChaseTaskTest.java, ObstacleNavigationTest.java.

Combat specialisation: MedusaHitRecoveryComponent.java, MedusaHitRecoveryComponentTest.java, MinotaurCombatIntegrationTest.java, LungeAttackTaskTest.java.

Flying/Snake: FlyingEnemyPatrolComponentTest.java, ProjectileMovementComponentTest.java, SnakeBurrowNavigatorTest.java, SnakeBurrowWallCollisionTest.java, SnakeBurrowRoomTraversalTest.java.

Merged changes: #226, #299, #312, #325, #332, #341, #380. Manual scenarios and result recording are in the Team 1 Test Plan.