using Godot; namespace Cirno.Scripts.Interactables; /// /// Listens to the signal and plays a named animation /// on an that reflects the switch's new state. /// /// Works with any Switch3D subclass (including ). /// /// Usage: /// 1. Add this node as a child of the Switch3D node. /// 2. Optionally assign and /// in the inspector; if left empty both are discovered automatically from the parent. /// 3. Set the three animation name exports to match animations in your AnimationPlayer. /// Leave a name empty to skip playing an animation for that state. /// [Tool] public partial class SwitchAnimationManager : Node { /// /// The switch to listen to. Auto-discovered from the parent if left empty. /// [Export] public Switch3D TargetSwitch { get; set; } /// /// The AnimationPlayer to drive. Auto-discovered from the parent if left empty. /// [Export] public AnimationPlayer TargetAnimationPlayer { get; set; } // --- State-based animation name exports --- /// Animation to play when the switch transitions to the enabled (on) state. [Export] public StringName AnimationEnabled { get; set; } = ""; /// Animation to play when the switch transitions to the disabled (off) state. [Export] public StringName AnimationDisabled { get; set; } = ""; /// Animation to play when the switch is destroyed. [Export] public StringName AnimationDestroyed { get; set; } = ""; /// /// Whether the switch is currently considered enabled (on) or disabled (off). /// Updated on each successful activation. /// public bool IsEnabled { get; private set; } /// /// When true the switch has been destroyed and will no longer respond to activations. /// public bool IsDestroyed { get; private set; } public override void _Ready() { if (Engine.IsEditorHint()) return; ResolveReferences(); if (TargetSwitch is null) { GD.PushWarning($"[SwitchAnimationManager:{Name}] No Switch3D found. Assign TargetSwitch or place this node as a child of one."); return; } TargetSwitch.OnActivated += OnSwitchActivated; // Start in the disabled state so the AnimationPlayer is running from the beginning. PlayAnimation(AnimationDisabled); } /// /// Fills in and from the /// parent node when they have not been assigned explicitly in the inspector. /// private void ResolveReferences() { var parent = GetParent(); if (TargetSwitch is null) TargetSwitch = parent as Switch3D; if (TargetAnimationPlayer is null) TargetAnimationPlayer = parent?.FindChild("AnimationPlayer", recursive: true, owned: false) as AnimationPlayer ?? parent?.GetNodeOrNull("AnimationPlayer"); } private void OnSwitchActivated(ActivationType activationType, bool success) { // Ignore failed activations and permanently destroyed switches. if (!success || IsDestroyed) return; UpdateState(activationType); StringName animationName = IsDestroyed ? AnimationDestroyed : IsEnabled ? AnimationEnabled : AnimationDisabled; PlayAnimation(animationName); } /// /// Transitions (and ) according to /// the activation type that was successfully applied: /// /// / → enabled /// / → disabled /// / → inverted /// → disabled + destroyed /// /// private void UpdateState(ActivationType activationType) { switch (activationType) { case ActivationType.Enable: case ActivationType.Open: IsEnabled = true; break; case ActivationType.Disable: case ActivationType.Close: IsEnabled = false; break; case ActivationType.Toggle: case ActivationType.Use: IsEnabled = !IsEnabled; break; case ActivationType.Destroy: IsEnabled = false; IsDestroyed = true; break; } } /// /// Plays the given animation on if the name is non-empty /// and the animation exists. Pushes a warning otherwise. /// private void PlayAnimation(StringName animationName) { if (animationName is null || animationName == "") return; if (TargetAnimationPlayer is null) { GD.PushWarning($"[SwitchAnimationManager:{Name}] No AnimationPlayer found. Assign TargetAnimationPlayer or add one under the switch."); return; } if (!TargetAnimationPlayer.HasAnimation(animationName)) { GD.PushWarning($"[SwitchAnimationManager:{Name}] AnimationPlayer has no animation named '{(string)animationName}'."); return; } TargetAnimationPlayer.Play(animationName); } }