using Cirno.Scripts.Enums; using Godot; using Godot.Collections; namespace Cirno.Scripts.Components.FSM.Enemy; public partial class PlayerDetectionModule : Area2D { [Signal] public delegate void PlayerInRangeEventHandler(); [Signal] public delegate void PlayerOutOfRangeEventHandler(); [Export(PropertyHint.Layers2DPhysics)] public uint ObstaclesCollisionMask { get; private set; } public Vector2? LastKnownPlayerPosition { get; private set; } //public bool PlayerInActiveArea { get; private set; } private CollisionShape2D _collisionShape2D; public override void _Ready() { } public void SetRange(float range) { _collisionShape2D ??= this.GetNode("CollisionShape2D"); if (_collisionShape2D.Shape is CircleShape2D shape2D) { shape2D.Radius = range; } } public bool IsPlayerInRange(float range) { if (!GameManager.Instance?.PlayerPosition.HasValue ?? false) { return false; } return this.GlobalPosition.DistanceTo(GameManager.Instance.PlayerPosition.Value) < range; } public bool IsPlayerInSight() { //if (_cachedPlayer == null) return false; if (!GameManager.Instance?.PlayerPosition.HasValue ?? false) return false; 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 { 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; } return found; } private void _on_area_entered(Area2D area) { if (area is not InteractionController player) return; EmitSignal(SignalName.PlayerInRange); //PlayerInActiveArea = true; } private void _on_area_exited(Area2D area) { if (area is not InteractionController player) return; EmitSignal(SignalName.PlayerOutOfRange); //PlayerInActiveArea = false; } }