118 lines
4.3 KiB
C#
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 <= 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 <= 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();
|
|
}
|
|
}
|
|
}
|