using System.Diagnostics; using Godot; using Godot.Collections; namespace Cirno.Scripts.Components; public partial class CameraPlayerDetection : PlayerDetection { [Export] public float SweepAngle = 90f; // In degrees [Export] public float SweepSpeed = 1f; // Speed of sweeping [Export] public bool Debug = false; // Enable debug lines [Export] public NodePath SpritePath; private float _currentAngle; private float _sweepDirection = 1f; private float _raycastLength; private AnimatedSprite2D _animatedSprite; public override void _Ready() { base._Ready(); _animatedSprite = GetNode(SpritePath); var collisionShape = GetNode("CollisionShape2D"); if (collisionShape.Shape is CircleShape2D circle) { _raycastLength = circle.Radius; } } public override void _PhysicsProcess(double delta) { base._PhysicsProcess(delta); SweepCamera((float)delta); UpdateSpriteDirection(); } private void SweepCamera(float delta) { _currentAngle += _sweepDirection * SweepSpeed * delta; // Clamp angle within the sweep range float halfAngle = SweepAngle / 2f; if (_currentAngle > halfAngle || _currentAngle < -halfAngle) { _sweepDirection *= -1f; _currentAngle = Mathf.Clamp(_currentAngle, -halfAngle, halfAngle); } // if (result.Count > 0 && result["collider"] is InteractionController interactionController && interactionController == _cachedPlayer) // { // GD.Print("Player detected!"); // // Handle detection logic here // } } private void DrawDebugLine(Vector2 endPoint) { // Request the node to redraw QueueRedraw(); _debugLineEndPoint = endPoint; } private void UpdateSpriteDirection() { if (_animatedSprite == null) return; var frames = _animatedSprite.SpriteFrames.GetFrameCount("default"); // Map angle (-SweepAngle/2 to +SweepAngle/2) to frame (0 to 5) float normalizedAngle = (_currentAngle + (SweepAngle / 2)) / SweepAngle; int frame = Mathf.Clamp((int)(normalizedAngle * frames), 0, frames); _animatedSprite.Frame = frame; } private Vector2 _debugLineEndPoint; public override void _Draw() { if (Debug) { DrawLine(Vector2.Zero, ToLocal(_debugLineEndPoint), Colors.Red, 2); } } public override bool IsPlayerInSight(uint collisionMask) { if (_cachedPlayer == null) return false; Vector2 direction = new Vector2(0, 1).Rotated(Mathf.DegToRad(_currentAngle)); Vector2 rayEnd = GlobalPosition + direction * _raycastLength; // Perform raycast var spaceState = GetWorld2D().DirectSpaceState; var query = PhysicsRayQueryParameters2D.Create(GlobalPosition, rayEnd); query.Exclude = [GetRid()]; query.CollideWithAreas = true; query.CollideWithBodies = true; query.CollisionMask = collisionMask; var result = spaceState.IntersectRay(query); bool detected = false; Vector2 debugLineEnd = rayEnd; if (result.Count > 0) { Node colliderNode = result["collider"].As(); if (colliderNode is InteractionController interactionController && interactionController == _cachedPlayer) { detected = true; } // Adjust debug line to collision point debugLineEnd = (Vector2)result["position"]; } if (Debug) { DrawDebugLine(debugLineEnd); } return detected; } private void _on_area_entered(Area2D area) { // Assume area is player for now if (area is not InteractionController player) return; GD.Print("Enemy detection area Entered by interaction controller"); _cachedPlayer = player; IsPlayerInRange = true; } private void _on_area_exited(Area2D area) { if (area is not InteractionController player) return; IsPlayerInRange = false; } }