diff --git a/Scripts/Components/Actors/PlayerAnimationProvider.cs b/Scripts/Components/Actors/PlayerAnimationProvider.cs index bbee1cfd..3b96d2ea 100644 --- a/Scripts/Components/Actors/PlayerAnimationProvider.cs +++ b/Scripts/Components/Actors/PlayerAnimationProvider.cs @@ -73,6 +73,19 @@ public partial class PlayerAnimationProvider : Node2D } } + + public void SweepSprite(float angle, float sweepAngle) + { + if (_animatedSprite == null) return; + + var frames = _animatedSprite.SpriteFrames.GetFrameCount("default"); + + // Map angle (-SweepAngle/2 to +SweepAngle/2) to frame (0 to 5) + float normalizedAngle = (angle + (sweepAngle / 2)) / sweepAngle; + int frame = Mathf.Clamp((int)(normalizedAngle * frames), 0, frames); + + _animatedSprite.Frame = frame; + } public void SetAnimation(Vector2 direction) { diff --git a/Scripts/Components/FSM/Enemy/TurretAnimationModule.cs b/Scripts/Components/FSM/Enemy/TurretAnimationModule.cs new file mode 100644 index 00000000..010775a6 --- /dev/null +++ b/Scripts/Components/FSM/Enemy/TurretAnimationModule.cs @@ -0,0 +1,104 @@ +using Cirno.Scripts.Components.Actors; +using Cirno.Scripts.Enums; +using Godot; + +namespace Cirno.Scripts.Components.FSM.Enemy; + +public partial class TurretAnimationModule : ModuleBase +{ + private IStateMachine _machine; + [Export] public PlayerAnimationProvider AnimationProvider { get; set; } + + [Export] public EnemyStorageModule StorageModule { get; set; } + [Export] public ActorResourceProvider HealthProvider { get; set; } + + + [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; + + public override void EnterState(EnemyState state) + { + AnimationProvider.SetAnimation(StorageModule.AimingDirection); + AnimationProvider.SetAnimation(Vector2.Zero); + if (HealthProvider is not null) + { + HealthProvider.ResourceDecreased += HealthProviderOnResourceDecreased; + } + } + + private void HealthProviderOnResourceDecreased(float oldValue, float newValue, float maxValue) + { + AnimationProvider?.Blink(); + } + + public override void ExitState(EnemyState state) + { + AnimationProvider.SetAnimation(Vector2.Zero); + if (HealthProvider is not null) + { + HealthProvider.ResourceDecreased -= HealthProviderOnResourceDecreased; + } + } + + public override void Init(IStateMachine machine) + { + _machine = machine; + } + + public override void Process(double delta) + { + AnimationProvider.SetAnimation(StorageModule.AimingDirection); + + if (_machine.MainObject.Velocity == Vector2.Zero) + { + AnimationProvider.SetAnimation(Vector2.Zero); + } + } + + public override void PhysicsProcess(double delta) + { + + } + + private void Sweep(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); + } + } + + private void DrawDebugLine(Vector2 endPoint) + { + // Request the node to redraw + QueueRedraw(); + _debugLineEndPoint = endPoint; + } + + private void UpdateSpriteDirection() + { + AnimationProvider.SweepSprite(_currentAngle, SweepAngle); + } + + private Vector2 _debugLineEndPoint; + + public override void _Draw() + { + if (Debug) + { + DrawLine(Vector2.Zero, ToLocal(_debugLineEndPoint), Colors.Red, 2); + } + } + +} \ No newline at end of file