Enemy pathfinding AI

This commit is contained in:
Marco 2025-01-31 16:45:31 +01:00
commit f0eee13e57

View file

@ -12,6 +12,8 @@ public partial class Enemy : CharacterBody2D
[Export] public float WalkSpeed = 2500f;
[Export] public float PlayerDisengageRange = 500f;
[Export] public Weapon EquippedWeapon;
private float _currentHealth = 0f;
@ -20,6 +22,10 @@ public partial class Enemy : CharacterBody2D
private NavigationAgent2D _navigationAgent;
private bool _isPlayerInRange = false;
private Vector2? _lastPlayerPosition = null;
[Export] public bool NavigationEnabled { get; set; } = false;
// Called when the node enters the scene tree for the first time.
@ -29,13 +35,13 @@ public partial class Enemy : CharacterBody2D
_navigationAgent = GetNode<NavigationAgent2D>("NavigationAgent2D");
CallDeferred("Setup");
//CallDeferred("Setup");
}
private void Setup()
{
}
// private void Setup()
// {
//
// }
// Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(double delta)
@ -45,10 +51,7 @@ public partial class Enemy : CharacterBody2D
case EnemyState.Idle:
break;
case EnemyState.Primed:
// Have the raycast follow the player and shoot if visible
//HandlePlayerDetection();
case EnemyState.Alert:
break;
//case EnemyState.Shooting:
@ -61,17 +64,29 @@ public partial class Enemy : CharacterBody2D
public override void _PhysicsProcess(double delta)
{
if (NavigationEnabled)
switch (_currentState)
{
// Only do these actions if the enemy has been alerted
if (_currentState is EnemyState.Primed)
{
_navigationAgent.SetTargetPosition(_cachedPlayer.GlobalPosition);
case EnemyState.Idle:
HandlePlayerDetection();
break;
case EnemyState.Alert:
// Update last known player position if it's in range
if (_isPlayerInRange)
{
_lastPlayerPosition = _cachedPlayer.GlobalPosition;
}
if (_lastPlayerPosition.HasValue)
{
_navigationAgent.SetTargetPosition(_lastPlayerPosition.Value);
}
var currentAgentPosition = GlobalPosition;
var nextPathPosition = _navigationAgent.GetNextPathPosition();
var newVelocity = currentAgentPosition.DirectionTo(nextPathPosition) * (float)(WalkSpeed * delta);
@ -79,7 +94,10 @@ public partial class Enemy : CharacterBody2D
if (_navigationAgent.IsNavigationFinished())
{
// Shoot player
HandlePlayerDetection();
Shoot();
// TODO: If player totally left the max range it should stop shooting and go back to idle
return;
}
@ -95,7 +113,11 @@ public partial class Enemy : CharacterBody2D
MoveAndSlide();
}
break;
case EnemyState.Patrolling:
break;
default:
throw new ArgumentOutOfRangeException();
}
}
@ -107,7 +129,7 @@ public partial class Enemy : CharacterBody2D
private void HandlePlayerDetection()
{
if (_cachedPlayer == null || _currentState is not EnemyState.Primed)
if (_cachedPlayer == null)
{
return;
}
@ -119,17 +141,18 @@ public partial class Enemy : CharacterBody2D
// {
// _navigationAgent.SetTargetPosition(_cachedPlayer.GlobalPosition);
// }
Shoot();
//Shoot();
_currentState = EnemyState.Alert;
}
}
private void Shoot()
{
if (EquippedWeapon == null) return;
if (EquippedWeapon == null || !_lastPlayerPosition.HasValue) return;
EquippedWeapon.ShootDirection = (_cachedPlayer.GlobalPosition - this.GlobalPosition).Normalized();
// Shoot at the player's last known position
EquippedWeapon.ShootDirection = (_lastPlayerPosition.Value - this.GlobalPosition).Normalized();
EquippedWeapon.Shoot();
@ -176,19 +199,23 @@ public partial class Enemy : CharacterBody2D
Debug.WriteLine("Enemy detection area Entered by interaction controller");
_cachedPlayer = player;
if (_currentState is EnemyState.Idle)
{
_currentState = EnemyState.Primed;
}
_isPlayerInRange = true;
// if (_currentState is EnemyState.Idle)
// {
// _currentState = EnemyState.Primed;
// }
}
}
private void _on_player_detection_area_exited(Area2D area)
{
if (_currentState is EnemyState.Primed)
{
_currentState = EnemyState.Idle;
}
_isPlayerInRange = false;
// if (_currentState is EnemyState.Primed)
// {
// _currentState = EnemyState.Idle;
// }
}
private void _on_damage_hitbox_area_entered(Area2D area)
@ -231,7 +258,7 @@ public partial class Enemy : CharacterBody2D
private enum EnemyState
{
Idle,
Primed,
Alert,
Patrolling
}
}