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.
- Global API:
GodotxLabelUp.show(position, text, style)andGodotxLabelUp.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
- Copy the
addons/godotx_label_upfolder into your Godot project. - Enable the plugin in Project → Project Settings → Plugins.
- The plugin registers
GodotxLabelUpas an autoload singleton.
# 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()| 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). |
GodotxLabelUp.label_spawned.connect(func(id): ...)
GodotxLabelUp.label_finished.connect(func(id): ...)- Empty
text→push_errorand returns -1. - Null
style→push_errorand returns -1. - No silent fallbacks.
- 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.
- Fonts: Use the same Font resource in styles; do not create new Font instances per label.
- Materials: Reuse
CanvasItemMaterialin 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.
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)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.
- Prewarm at startup:
GodotxLabelUp.prewarm(500)or higher for heavy screens. - Reuse styles: Use
GodotxLabelUpStyles.get_style(...)or shared.tresresources; avoid creating newGodotxLabelUpStyleinstances every spawn. - Reuse fonts: Assign one Font (or theme font) in your style; do not create new Font instances per label.
- Limit spawn rate if needed (e.g. cap damage numbers per frame) so the pool doesn’t grow unbounded.
- Use dismiss(id) or clear_all() when changing scenes or closing UIs to return labels to the pool.
demo.mp4
This project is licensed under the MIT License.
Made with ❤️ by Paulo Coutinho