mirror of
https://gitlab.com/MaddoScientisto/cirnogodot.git
synced 2026-06-01 10:05:34 +00:00
Enemy strafing
This commit is contained in:
parent
a18dc11eb3
commit
b35772f519
6 changed files with 112 additions and 16 deletions
|
|
@ -108,11 +108,12 @@ DamageReceiver = NodePath("../../DamageReceiver")
|
|||
NavigationModule = NodePath("../../NavigationModule")
|
||||
_moduleNodes = [NodePath("../../AnimationModule")]
|
||||
|
||||
[node name="Shooting" type="Node2D" parent="StateMachine" node_paths=PackedStringArray("StorageModule", "PlayerDetection", "DamageReceiver", "EquippedWeapon", "_moduleNodes")]
|
||||
[node name="Shooting" type="Node2D" parent="StateMachine" node_paths=PackedStringArray("StorageModule", "PlayerDetection", "DamageReceiver", "NavigationModule", "EquippedWeapon", "_moduleNodes")]
|
||||
script = ExtResource("7_br0mr")
|
||||
StorageModule = NodePath("../../Storage")
|
||||
PlayerDetection = NodePath("../../PlayerDetection")
|
||||
DamageReceiver = NodePath("../../DamageReceiver")
|
||||
NavigationModule = NodePath("../../NavigationModule")
|
||||
EquippedWeapon = NodePath("../../EnemyWeapon")
|
||||
_moduleNodes = [NodePath("../../AnimationModule")]
|
||||
|
||||
|
|
|
|||
|
|
@ -108,11 +108,12 @@ DamageReceiver = NodePath("../../DamageReceiver")
|
|||
NavigationModule = NodePath("../../NavigationModule")
|
||||
_moduleNodes = [NodePath("../../AnimationModule")]
|
||||
|
||||
[node name="Shooting" type="Node2D" parent="StateMachine" node_paths=PackedStringArray("StorageModule", "PlayerDetection", "DamageReceiver", "EquippedWeapon", "_moduleNodes")]
|
||||
[node name="Shooting" type="Node2D" parent="StateMachine" node_paths=PackedStringArray("StorageModule", "PlayerDetection", "DamageReceiver", "NavigationModule", "EquippedWeapon", "_moduleNodes")]
|
||||
script = ExtResource("7_w6ssf")
|
||||
StorageModule = NodePath("../../Storage")
|
||||
PlayerDetection = NodePath("../../PlayerDetection")
|
||||
DamageReceiver = NodePath("../../DamageReceiver")
|
||||
NavigationModule = NodePath("../../NavigationModule")
|
||||
EquippedWeapon = NodePath("../../EnemyWeapon")
|
||||
_moduleNodes = [NodePath("../../AnimationModule")]
|
||||
|
||||
|
|
@ -173,6 +174,7 @@ target_desired_distance = 8.0
|
|||
path_max_distance = 800.0
|
||||
path_postprocessing = 1
|
||||
avoidance_enabled = true
|
||||
debug_enabled = true
|
||||
debug_path_custom_color = Color(1, 0, 0, 1)
|
||||
|
||||
[node name="EnemyWeapon" parent="." instance=ExtResource("17_i8o8t")]
|
||||
|
|
|
|||
|
|
@ -108,11 +108,12 @@ DamageReceiver = NodePath("../../DamageReceiver")
|
|||
NavigationModule = NodePath("../../NavigationModule")
|
||||
_moduleNodes = [NodePath("../../AnimationModule")]
|
||||
|
||||
[node name="Shooting" type="Node2D" parent="StateMachine" node_paths=PackedStringArray("StorageModule", "PlayerDetection", "DamageReceiver", "EquippedWeapon", "_moduleNodes")]
|
||||
[node name="Shooting" type="Node2D" parent="StateMachine" node_paths=PackedStringArray("StorageModule", "PlayerDetection", "DamageReceiver", "NavigationModule", "EquippedWeapon", "_moduleNodes")]
|
||||
script = ExtResource("7_0b4ec")
|
||||
StorageModule = NodePath("../../Storage")
|
||||
PlayerDetection = NodePath("../../PlayerDetection")
|
||||
DamageReceiver = NodePath("../../DamageReceiver")
|
||||
NavigationModule = NodePath("../../NavigationModule")
|
||||
EquippedWeapon = NodePath("../../EnemyWeapon")
|
||||
_moduleNodes = [NodePath("../../AnimationModule")]
|
||||
|
||||
|
|
|
|||
|
|
@ -66,4 +66,15 @@ public partial class NavigationMovementModule : Node2D
|
|||
StorageModule.FacingDirection = _characterBody.Velocity.Normalized();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsNavigable(Vector2 newPos)
|
||||
{
|
||||
_navigationAgent.SetTargetPosition(newPos);
|
||||
return _navigationAgent.IsTargetReachable();
|
||||
}
|
||||
|
||||
public bool IsNavigationFinished()
|
||||
{
|
||||
return _navigationAgent.IsNavigationFinished();
|
||||
}
|
||||
}
|
||||
|
|
@ -60,18 +60,20 @@ public partial class PlayerDetectionModule : Area2D
|
|||
//if (_cachedPlayer == null) return false;
|
||||
if (!GameManager.Instance.PlayerPosition.HasValue) return false;
|
||||
|
||||
var spaceState = GetWorld2D().DirectSpaceState;
|
||||
var found = HasLineOfSight(this.GlobalPosition, GameManager.Instance.PlayerPosition.Value);
|
||||
|
||||
// It needs to use its own collision mask because it's detecting obstacles rather than the player
|
||||
var query = PhysicsRayQueryParameters2D.Create(this.GlobalPosition, GameManager.Instance.PlayerPosition.Value, ObstaclesCollisionMask,
|
||||
[GetRid()]);
|
||||
//query.CollideWithBodies = true;
|
||||
//query.CollideWithAreas = true;
|
||||
// var query = PhysicsRayQueryParameters2D.Create(this.GlobalPosition, _cachedPlayer.GlobalPosition, CollisionMask, new Array<Rid> { GetRid() });
|
||||
var result = spaceState.IntersectRay(query);
|
||||
|
||||
// If count is 0 then the player is in sight, otherwise there is level geometry in the way
|
||||
var found = result.Count == 0;
|
||||
// var spaceState = GetWorld2D().DirectSpaceState;
|
||||
//
|
||||
// // It needs to use its own collision mask because it's detecting obstacles rather than the player
|
||||
// var query = PhysicsRayQueryParameters2D.Create(this.GlobalPosition, GameManager.Instance.PlayerPosition.Value, ObstaclesCollisionMask,
|
||||
// [GetRid()]);
|
||||
// //query.CollideWithBodies = true;
|
||||
// //query.CollideWithAreas = true;
|
||||
// // var query = PhysicsRayQueryParameters2D.Create(this.GlobalPosition, _cachedPlayer.GlobalPosition, CollisionMask, new Array<Rid> { GetRid() });
|
||||
// var result = spaceState.IntersectRay(query);
|
||||
//
|
||||
// // If count is 0 then the player is in sight, otherwise there is level geometry in the way
|
||||
// var found = result.Count == 0;
|
||||
if (found)
|
||||
{
|
||||
LastKnownPlayerPosition = GameManager.Instance.PlayerPosition;
|
||||
|
|
@ -92,4 +94,22 @@ public partial class PlayerDetectionModule : Area2D
|
|||
EmitSignal(SignalName.PlayerOutOfRange);
|
||||
//PlayerInActiveArea = false;
|
||||
}
|
||||
|
||||
public bool HasLineOfSight(Vector2 startPos, Vector2 endPos)
|
||||
{
|
||||
var spaceState = GetWorld2D().DirectSpaceState;
|
||||
|
||||
// It needs to use its own collision mask because it's detecting obstacles rather than the player
|
||||
var query = PhysicsRayQueryParameters2D.Create(startPos, endPos, ObstaclesCollisionMask,
|
||||
[GetRid()]);
|
||||
//query.CollideWithBodies = true;
|
||||
//query.CollideWithAreas = true;
|
||||
// var query = PhysicsRayQueryParameters2D.Create(this.GlobalPosition, _cachedPlayer.GlobalPosition, CollisionMask, new Array<Rid> { GetRid() });
|
||||
var result = spaceState.IntersectRay(query);
|
||||
|
||||
// If count is 0 then the player is in sight, otherwise there is level geometry in the way
|
||||
var found = result.Count == 0;
|
||||
|
||||
return found;
|
||||
}
|
||||
}
|
||||
|
|
@ -17,10 +17,18 @@ public partial class Shooting : EnemyStateBase
|
|||
[Export]
|
||||
public GenericDamageReceiver DamageReceiver { get; private set; }
|
||||
|
||||
[Export]
|
||||
public NavigationMovementModule NavigationModule { get; private set; }
|
||||
|
||||
[Export] public float MaxStrafeDistance { get; private set; } = 64f;
|
||||
[Export] public float MinStrafeDistance { get; private set; } = 16f;
|
||||
|
||||
[Export] public Weapon EquippedWeapon;
|
||||
|
||||
private bool _isPlayerInRange = false;
|
||||
|
||||
private Vector2? _currentStrafeTarget = null;
|
||||
|
||||
public override void EnterState()
|
||||
{
|
||||
base.EnterState();
|
||||
|
|
@ -35,6 +43,8 @@ public partial class Shooting : EnemyStateBase
|
|||
DamageReceiver.HealthProvider.ResourceDepleted += HealthProviderOnResourceDepleted;
|
||||
|
||||
EquippedWeapon.WeaponData = StorageModule.Root.EnemyResource.Weapon;
|
||||
|
||||
_currentStrafeTarget = null;
|
||||
// PlayerDetection.SetRange(StorageModule.Root.EnemyResource.PlayerDetectionRange);
|
||||
//
|
||||
// _isPlayerInRange = PlayerDetection.IsPlayerInRange(StorageModule.Root.EnemyResource.PlayerDetectionRange);
|
||||
|
|
@ -67,6 +77,9 @@ public partial class Shooting : EnemyStateBase
|
|||
PlayerDetection.PlayerOutOfRange -= PlayerDetectionOnPlayerOutOfRange;
|
||||
|
||||
DamageReceiver.HealthProvider.ResourceDepleted -= HealthProviderOnResourceDepleted;
|
||||
|
||||
_currentStrafeTarget = null;
|
||||
|
||||
DamageReceiver.ChangeState(false);
|
||||
|
||||
}
|
||||
|
|
@ -79,14 +92,62 @@ public partial class Shooting : EnemyStateBase
|
|||
{
|
||||
// SHOOT
|
||||
Shoot();
|
||||
|
||||
// Check if a strafe position is needed
|
||||
if (!_currentStrafeTarget.HasValue || NavigationModule.IsNavigationFinished())
|
||||
{
|
||||
_currentStrafeTarget = CalculateStrafePosition();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
StateMachine.SetState(EnemyState.Alert);
|
||||
return;
|
||||
}
|
||||
|
||||
// Strafe
|
||||
|
||||
if (_currentStrafeTarget.HasValue)
|
||||
{
|
||||
NavigationModule.SetTarget(_currentStrafeTarget.Value);
|
||||
NavigationModule.Move();
|
||||
}
|
||||
}
|
||||
|
||||
private Vector2? CalculateStrafePosition()
|
||||
{
|
||||
Vector2 playerPos = PlayerDetection.LastKnownPlayerPosition.Value;
|
||||
Vector2 enemyPos = MainObject.GlobalPosition;
|
||||
|
||||
// Calculate direction to player
|
||||
Vector2 directionToPlayer = (playerPos - enemyPos).Normalized();
|
||||
|
||||
// Get perpendicular vectors (left and right strafing directions)
|
||||
Vector2 leftStrafe = directionToPlayer.Rotated(-Mathf.Pi / 2);
|
||||
Vector2 rightStrafe = directionToPlayer.Rotated(Mathf.Pi / 2);
|
||||
|
||||
// Randomly decide left or right first
|
||||
bool tryLeftFirst = GD.Randf() < 0.5f;
|
||||
|
||||
for (float factor = 1f; factor > 0.25f; factor *= 0.75f)
|
||||
{
|
||||
float strafeDistance = Mathf.Lerp(MinStrafeDistance, MaxStrafeDistance, factor);
|
||||
Vector2 newPos = enemyPos + (tryLeftFirst ? leftStrafe : rightStrafe) * strafeDistance;
|
||||
if (NavigationModule.IsNavigable(newPos) && PlayerDetection.HasLineOfSight(newPos, playerPos))
|
||||
{
|
||||
return newPos;
|
||||
}
|
||||
}
|
||||
|
||||
for (float factor = 1f; factor > 0.25f; factor *= 0.75f)
|
||||
{
|
||||
float strafeDistance = Mathf.Lerp(MinStrafeDistance, MaxStrafeDistance, factor);
|
||||
Vector2 newPos = enemyPos + (tryLeftFirst ? rightStrafe : leftStrafe) * strafeDistance;
|
||||
if (NavigationModule.IsNavigable(newPos) && PlayerDetection.HasLineOfSight(newPos, playerPos))
|
||||
{
|
||||
return newPos;
|
||||
}
|
||||
}
|
||||
|
||||
return null; // No valid strafe position found
|
||||
}
|
||||
|
||||
private void Shoot()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue