Skip to content

Repository files navigation

GodotX Label Up - Logo

GodotX Label Up

A high-performance floating text system for Godot 4.5+ (2D) designed for damage numbers, heals, XP, gold, combos, and any animated floating text. Built to sustain 10,000+ simultaneous labels with zero frame spikes and no memory leaks.

Features

  • Global API: GodotxLabelUp.show(position, text, style) and GodotxLabelUp.show_xy(x, y, text, style)
  • Object pool: Pre-allocated nodes, no runtime allocation after warmup
  • Style-driven: Every visual and animation is configurable via GodotxLabelUpStyle (Resource)
  • Built-in styles: Default, Damage, Critical, Heal, XP, Gold, Fire, Ice, Poison
  • Movement: 13 directions (UP, DOWN, cardinal/diagonal, UP_FAN, DOWN_FAN, LEFT_FAN, RIGHT_FAN, RANDOM), fan spread for *_FAN, distance, duration, easing, optional Curve
  • Motion styles: Straight, Arc, Wiggle, Shake, Scale up, Scale down
  • Appear: Fade, scale, pop, scale-and-fade
  • Exit: None, fade out, scale out, or scale and fade
  • Stacking & jitter: Spawn offset and random jitter when multiple labels spawn at the same position
  • Optional follow target: Style can attach to a Node2D with offset; safe if target is freed
  • Signals: label_spawned(id), label_finished(id)
  • 2D only: No 3D; production-grade, no deprecated APIs

Installation

  1. Copy the addons/godotx_label_up folder into your Godot project.
  2. Enable the plugin in Project → Project Settings → Plugins.
  3. The plugin registers GodotxLabelUp as an autoload singleton.

Basic Usage

# By position
var id = GodotxLabelUp.show(Vector2(100, 200), "42", GodotxLabelUpStyles.get_instance().get_style(GodotxLabelUpStyles.DAMAGE))

# By x, y
var id = GodotxLabelUp.show_xy(100.0, 200.0, "+50 XP", GodotxLabelUpStyles.get_instance().get_style(GodotxLabelUpStyles.XP))

# Control
GodotxLabelUp.dismiss(id)
GodotxLabelUp.clear_all()

# Pool
GodotxLabelUp.prewarm(500)
var active = GodotxLabelUp.get_active_count()
var pool_size = GodotxLabelUp.get_pool_size()

API Reference

Main methods

Method Description
GodotxLabelUp.show(position: Vector2, text: String, style: GodotxLabelUpStyle) -> int Spawn a floating label; position is the center of the label. Returns unique id or -1.
GodotxLabelUp.show_xy(x: float, y: float, text: String, style: GodotxLabelUpStyle) -> int Same as show with x, y.
GodotxLabelUp.dismiss(id: int) -> bool Dismiss one label by id and return it to the pool.
GodotxLabelUp.clear_all() Dismiss all active labels.
GodotxLabelUp.prewarm(amount: int) Pre-allocate pool nodes (default prewarm is 200).
GodotxLabelUp.get_active_count() -> int Number of labels currently visible.
GodotxLabelUp.get_pool_size() -> int Total pool size (active + available).

Signals

GodotxLabelUp.label_spawned.connect(func(id): ...)
GodotxLabelUp.label_finished.connect(func(id): ...)

Validation

  • Empty text → push_error and returns -1.
  • Null style → push_error and returns -1.
  • No silent fallbacks.

Pooling

  • Prewarm: Call GodotxLabelUp.prewarm(amount) at startup (e.g. 200–500). Default prewarm is 200.
  • Reuse: When a label finishes its animation (or is dismissed), it is reset and returned to the pool.
  • Growth: If the pool is empty and growth is allowed, a new node is created. You can configure the pool to drop the oldest label instead when at capacity.
  • No queue_free: Labels are never freed during gameplay; they are only reset and reused.

Performance (10k+ labels)

  • Fonts: Use the same Font resource in styles; do not create new Font instances per label.
  • Materials: Reuse CanvasItemMaterial in styles when needed.
  • No per-frame allocation: No new objects in _process, no string concatenation in hot paths, no dynamic arrays per spawn.
  • Tweens: One-shot tweens per label; no lambdas that allocate.
  • Pool: Prewarm to your expected peak (e.g. 500–1000). For 10k stress tests, allow pool growth or drop-oldest so the game doesn’t allocate in a burst.

Custom style

Create a GodotxLabelUpStyle resource (or duplicate a built-in one):

var style = GodotxLabelUpStyle.new()
style.font_size = 28
style.font_color = Color.GOLD
style.movement_direction = GodotxLabelUpEnums.MovementDirection.UP
style.movement_fan_spread_degrees = 90.0  # used by UP_FAN, DOWN_FAN, LEFT_FAN, RIGHT_FAN
style.duration = 1.2
style.distance = 80.0
style.motion_style = GodotxLabelUpEnums.MotionStyle.SCALE_UP
style.appear_animation = GodotxLabelUpEnums.AppearAnimation.POP
style.exit_animation = GodotxLabelUpEnums.ExitAnimation.FADE_OUT
# ... outline, follow_target, initial_scale, final_scale, etc.

GodotxLabelUp.show(position, "Custom!", style)

You can also save .tres resources and load them:

var style = load("res://my_styles/critical.tres") as GodotxLabelUpStyle
GodotxLabelUp.show(pos, "999!", style)

Demo and stress testing

Open scenes/demo/godotx_label_up_demo.tscn and run the project.

  • Stress Test: “Spawn 10,000 Labels” to verify FPS and pool; “Clear All” to clear.
  • Style Showcase: Buttons for each built-in style; sliders for duration, distance, font size, outline, scale; motion and exit animation dropdowns; click area to spawn.
  • World Example: Click in the panel to spawn damage numbers; enable “Follow target” to spawn on the character (Node2D) so labels follow it.

Best practices for 10k usage

  1. Prewarm at startup: GodotxLabelUp.prewarm(500) or higher for heavy screens.
  2. Reuse styles: Use GodotxLabelUpStyles.get_style(...) or shared .tres resources; avoid creating new GodotxLabelUpStyle instances every spawn.
  3. Reuse fonts: Assign one Font (or theme font) in your style; do not create new Font instances per label.
  4. Limit spawn rate if needed (e.g. cap damage numbers per frame) so the pool doesn’t grow unbounded.
  5. Use dismiss(id) or clear_all() when changing scenes or closing UIs to return labels to the pool.

Screenshot

demo.mp4

License

This project is licensed under the MIT License.


Made with ❤️ by Paulo Coutinho

About

No description, website, or topics provided.

Resources

Stars

8 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages