Files
mod_turn_battle_base/src/ShowDamageBehaviour.cs
T

118 lines
4.3 KiB
C#

using Cthangover.Core.UI.Theming;
using Godot;
namespace Cthangover.TurnBattle
{
/// <summary>
/// Floating damage-number overlay. Self-contained: creates its own Label
/// in _Ready, floats upward with random horizontal drift, fades alpha,
/// then QueueFrees itself. Static factory methods (SpawnDamage,
/// SpawnDefence) instantiate and parent it in one call — damage is red,
/// heal is green, defence is blue. MouseFilter is Ignore so clicks pass
/// through to cards underneath.
/// </summary>
public partial class ShowDamageBehaviour : Control
{
private Label _label;
private float duration = 1.0f;
private float floatDistance = 80f;
private float driftRange = 30f;
private Vector2 startPosition;
/// <summary>
/// Builds the label on first use. Godot does not dispatch <c>_Ready</c>
/// overrides declared in mod assemblies (only methods generated in the core
/// project run), so the label cannot be created in <c>_Ready</c> — it is
/// created here, right before the first animation starts.
/// </summary>
private void EnsureLabel()
{
if (_label != null)
return;
MouseFilter = MouseFilterEnum.Ignore;
_label = new Label();
_label.SetAnchorsAndOffsetsPreset(LayoutPreset.Center);
_label.HorizontalAlignment = HorizontalAlignment.Center;
_label.VerticalAlignment = VerticalAlignment.Center;
_label.AddThemeFontSizeOverride("font_size", 28);
_label.AddThemeColorOverride("font_outline_color", UiTokens.Alpha(Colors.Black, 1f));
_label.AddThemeConstantOverride("outline_size", 6);
AddChild(_label);
}
/// <summary>
/// Creates and parents a floating damage (or heal) number.
/// Damage is red, heal is green. The label floats upward with
/// a random horizontal drift and auto-destructs after the
/// tween completes. Skips values &lt;= 0.
/// </summary>
public static void SpawnDamage(int amount, Node parent, Vector2 position, bool isHeal = false)
{
if (amount <= 0)
return;
var color = isHeal
? UiTokens.SuccessText
: UiTokens.DangerText;
var hint = new ShowDamageBehaviour();
parent.AddChild(hint);
hint.Init(amount, position, color);
}
/// <summary>
/// Creates and parents a floating defence number (blue).
/// Same floating behaviour as <see cref="SpawnDamage"/>.
/// Skips values &lt;= 0.
/// </summary>
public static void SpawnDefence(int amount, Node parent, Vector2 position)
{
if (amount <= 0)
return;
var hint = new ShowDamageBehaviour();
parent.AddChild(hint);
hint.Init(amount, position, UiTokens.Info);
}
/// <summary>
/// Sets the label text, colour, and world position, then starts
/// the floating animation tween. Called by the static factory
/// methods after instantiation.
/// </summary>
public void Init(int amount, Vector2 worldPosition, Color? color = null)
{
EnsureLabel();
_label.Text = amount.ToString();
if (color.HasValue)
_label.Modulate = color.Value;
GlobalPosition = worldPosition;
startPosition = Position;
RunAnimation();
}
private async void RunAnimation()
{
float driftX = (float)GD.RandRange(-driftRange, driftRange);
Vector2 targetPos = startPosition + new Vector2(driftX, -floatDistance);
var tween = CreateTween();
tween.SetParallel(true);
tween.SetEase(Tween.EaseType.Out).SetTrans(Tween.TransitionType.Cubic);
tween.TweenProperty(this, "position", targetPos, duration);
var fadeTween = CreateTween();
fadeTween.TweenProperty(_label, "modulate:a", 0f, duration * 0.8f);
await ToSignal(tween, "finished");
QueueFree();
}
}
}