mirror of
https://gitlab.com/MaddoScientisto/cirnogodot.git
synced 2026-06-01 09:45:33 +00:00
159 lines
5.8 KiB
C#
159 lines
5.8 KiB
C#
using Godot;
|
|
|
|
namespace Cirno.Scripts.Interactables;
|
|
|
|
/// <summary>
|
|
/// Listens to the <see cref="Switch3D.OnActivated"/> signal and plays a named animation
|
|
/// on an <see cref="AnimationPlayer"/> that reflects the switch's new state.
|
|
///
|
|
/// Works with any Switch3D subclass (including <see cref="ShootableSwitch3D"/>).
|
|
///
|
|
/// Usage:
|
|
/// 1. Add this node as a child of the Switch3D node.
|
|
/// 2. Optionally assign <see cref="TargetSwitch"/> and <see cref="TargetAnimationPlayer"/>
|
|
/// 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.
|
|
/// </summary>
|
|
[Tool]
|
|
public partial class SwitchAnimationManager : Node
|
|
{
|
|
/// <summary>
|
|
/// The switch to listen to. Auto-discovered from the parent if left empty.
|
|
/// </summary>
|
|
[Export] public Switch3D TargetSwitch { get; set; }
|
|
|
|
/// <summary>
|
|
/// The AnimationPlayer to drive. Auto-discovered from the parent if left empty.
|
|
/// </summary>
|
|
[Export] public AnimationPlayer TargetAnimationPlayer { get; set; }
|
|
|
|
// --- State-based animation name exports ---
|
|
|
|
/// <summary>Animation to play when the switch transitions to the enabled (on) state.</summary>
|
|
[Export] public StringName AnimationEnabled { get; set; } = "";
|
|
|
|
/// <summary>Animation to play when the switch transitions to the disabled (off) state.</summary>
|
|
[Export] public StringName AnimationDisabled { get; set; } = "";
|
|
|
|
/// <summary>Animation to play when the switch is destroyed.</summary>
|
|
[Export] public StringName AnimationDestroyed { get; set; } = "";
|
|
|
|
/// <summary>
|
|
/// Whether the switch is currently considered enabled (on) or disabled (off).
|
|
/// Updated on each successful activation.
|
|
/// </summary>
|
|
public bool IsEnabled { get; private set; }
|
|
|
|
/// <summary>
|
|
/// When true the switch has been destroyed and will no longer respond to activations.
|
|
/// </summary>
|
|
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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fills in <see cref="TargetSwitch"/> and <see cref="TargetAnimationPlayer"/> from the
|
|
/// parent node when they have not been assigned explicitly in the inspector.
|
|
/// </summary>
|
|
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>("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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Transitions <see cref="IsEnabled"/> (and <see cref="IsDestroyed"/>) according to
|
|
/// the activation type that was successfully applied:
|
|
/// <list type="bullet">
|
|
/// <item><see cref="ActivationType.Enable"/> / <see cref="ActivationType.Open"/> → enabled</item>
|
|
/// <item><see cref="ActivationType.Disable"/> / <see cref="ActivationType.Close"/> → disabled</item>
|
|
/// <item><see cref="ActivationType.Toggle"/> / <see cref="ActivationType.Use"/> → inverted</item>
|
|
/// <item><see cref="ActivationType.Destroy"/> → disabled + destroyed</item>
|
|
/// </list>
|
|
/// </summary>
|
|
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;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Plays the given animation on <see cref="TargetAnimationPlayer"/> if the name is non-empty
|
|
/// and the animation exists. Pushes a warning otherwise.
|
|
/// </summary>
|
|
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);
|
|
}
|
|
}
|