cirnogodot/Scripts/Interactables/ShootableSwitch3D.cs

127 lines
3.9 KiB
C#

using Cirno.Scripts.Weapons;
using Godot;
namespace Cirno.Scripts.Interactables;
/// <summary>
/// A Switch3D variant that activates when hit by a Bullet3D.
/// Supports filtering by bullet owner and an optional cooldown between activations.
/// </summary>
[Tool]
public partial class ShootableSwitch3D : Switch3D
{
/// <summary>
/// Which bullet owner can trigger this switch.
/// None means both Player and Enemy bullets are accepted.
/// </summary>
[Export] public BulletOwner ReactsTo { get; set; } = BulletOwner.None;
/// <summary>
/// Minimum time in seconds between consecutive activations. 0 disables the cooldown.
/// </summary>
[Export] public float CooldownSeconds { get; set; } = 0f;
/// <summary>
/// Enable runtime debug logging for this node. Toggle in the editor to diagnose bullet-trigger behavior.
/// </summary>
[Export]
public bool EnableDebugLogs { get; set; } = false;
private double _cooldownRemaining = 0.0;
// Track whether we were on cooldown last frame so we don't spam logs every frame.
private bool _wasOnCooldown = false;
public override void _Ready()
{
base._Ready();
Log($"_Ready() called (EditorHint={Engine.IsEditorHint()})");
// Log the initial ActivationType (name + numeric) to make it obvious what value was deserialized.
Log($"Initial ActivationType={ActivationType} ({(int)ActivationType})");
if (Engine.IsEditorHint()) return;
AreaEntered += OnAreaEntered;
Log("Subscribed to AreaEntered events");
}
public override void _Process(double delta)
{
if (_cooldownRemaining > 0.0)
{
// Log only when cooldown starts/ends to avoid spamming the console every frame.
if (!_wasOnCooldown)
{
Log($"Cooldown started: {_cooldownRemaining:F2}s");
_wasOnCooldown = true;
}
_cooldownRemaining -= delta;
if (_cooldownRemaining <= 0.0 && _wasOnCooldown)
{
Log("Cooldown ended");
_wasOnCooldown = false;
}
}
}
private void OnAreaEntered(Area3D area)
{
Log($"AreaEntered event received from: {area?.GetType().Name}");
if (area is not Bullet3D bullet)
{
Log("Area is not a Bullet3D - ignoring");
return;
}
Log($"Bullet detected - Enabled={bullet.Enabled}, Owner={bullet.BulletOwner}");
if (!bullet.Enabled)
{
Log("Bullet is disabled - ignoring");
return;
}
// Filter by owner if a specific owner is configured
if (ReactsTo is not BulletOwner.None && bullet.BulletOwner != ReactsTo)
{
Log($"Bullet owner {bullet.BulletOwner} does not match configured ReactsTo={ReactsTo} - ignoring");
return;
}
if (_cooldownRemaining > 0.0)
{
Log($"On cooldown ({_cooldownRemaining:F2}s remaining) - ignoring");
return;
}
Log("Requesting bullet collision destruction");
bullet.RequestCollisionDestruction();
// Include the numeric value when logging so it's easy to cross-reference serialized files.
Log($"Activating switch (ActivationType={ActivationType} ({(int)ActivationType}))");
Activate(ActivationType);
if (CooldownSeconds > 0f)
{
_cooldownRemaining = CooldownSeconds;
Log($"Cooldown set to {CooldownSeconds:F2}s");
}
}
/// <summary>
/// Helper to centralize debug printing and include the node name for easier filtering.
/// Respects the <see cref="EnableDebugLogs"/> toggle.
/// </summary>
/// <param name="message">Message to print when logging is enabled.</param>
private void Log(string message)
{
if (!EnableDebugLogs) return;
GD.Print($"[ShootableSwitch3D:{Name}] {message}");
}
}