using Godot; using System.Diagnostics.CodeAnalysis; public partial class CryingGhost : CharacterBase { private AnimatedSprite2D _animatedSprite = default!; private NavigationAgent2D _navigationAgent = default!; private Area2D _detectionArea = default!; private Timer _targetTimer = default!; protected Node2D? Target { get; private set; } [MemberNotNullWhen(true, nameof(Target))] protected bool HasTarget => Target is not null; public override void _Ready() { _animatedSprite = GetNode("AnimatedSprite2D"); _navigationAgent = GetNode("NavigationAgent2D"); _detectionArea = GetNode("DetectionArea"); _targetTimer = GetNode("TargetTimer"); _animatedSprite?.Play("idle"); _detectionArea.BodyEntered += OnBodyEntered; _detectionArea.BodyExited += OnBodyExited; _targetTimer.Timeout += OnTimeout; _navigationAgent.VelocityComputed += OnVelocityComputed; } public override void _PhysicsProcess(double delta) { if (!HasTarget) { Velocity = Vector2.Zero; } else { var nextPosition = _navigationAgent.GetNextPathPosition(); var direction = (nextPosition - GlobalPosition).Normalized(); _navigationAgent.Velocity = direction * Speed; } MoveAndSlide(); } void OnBodyEntered(Node2D body) { if (body.IsInGroup("Player")) { Target = body; _navigationAgent.TargetPosition = Target.GlobalPosition; _targetTimer.Start(); } } void OnBodyExited(Node2D body) { if (body == Target) { Target = null; _navigationAgent.TargetPosition = GlobalPosition; _targetTimer.Stop(); } } void OnTimeout() { if (HasTarget) { _navigationAgent.TargetPosition = Target.GlobalPosition; } } void OnVelocityComputed(Vector2 safeVelocity) { Velocity = safeVelocity; } }