` I’m working on a project that has some specific label requirements that involve curved text. One of them I’ve already hacked together, but would love some extra guidance on, which is bending text around a curve. My jerry-rigged solution is to use a Path2D to demarcate the curve, and then re-process the label (making a new label for every character- bad I know!) and rotate those new labels to match the rotation of the Path2D. It works, but it does look kind of bad because the characters don’t deform to the curve, they just rotate to match it.
My other issue, which I haven’t yet solved, is having the bounding box for a label instead be a bounding circle. In other words, changing the text wrapping to wrap at the edge of a circle rather than at the edge of the default rectangle. I know in the absolute worst case I could hardcode this effect for a given font and font size by just counting the number of lines in the label and truncating them as necessary, but I would love a more elegant solution before I do all of that work.
I’m really loving using Godot, but it does definitely make it hard to do creative things with text when you can’t easily bend it!`
Have you tried a RichTextLabel with a Tornado effect?
The other solution I can think of is finding a curved text library in C# and plugging that in by using Godot Mono (the C# version) because it can also use GDScript code. Which would be easier than using a plugin from another language and using GDExtension.
@tool
extends Path2D
@export var text: String:
set(value):
if text != value:
text = value
queue_redraw()
@export var label_settings: LabelSettings:
set(value):
if is_instance_valid(label_settings) and label_settings.changed.is_connected(queue_redraw):
label_settings.changed.disconnect(queue_redraw)
label_settings = value
if is_instance_valid(label_settings):
label_settings.changed.connect(queue_redraw)
var _line = TextLine.new()
func _draw() -> void:
# Get the font, font size and color from the ThemeDB
var font = ThemeDB.fallback_font
var font_size = ThemeDB.fallback_font_size
var font_color = Color.WHITE
# If the label_settings is valid, then use the values from it
if is_instance_valid(label_settings):
font = label_settings.font
font_size = label_settings.font_size
font_color = label_settings.font_color
# Clear the line and add the new string
_line.clear()
_line.add_string(text, font, font_size)
# Get the primary TextServer
var ts = TextServerManager.get_primary_interface()
# And get the glyph information from the line
var glyphs = ts.shaped_text_get_glyphs(_line.get_rid())
var offset = 0.0
for glyph_data in glyphs:
# Sample the curve with rotation at the offset
var trans = curve.sample_baked_with_rotation(offset)
# set the draw matrix to that transform
draw_set_transform_matrix(trans)
# draw the glyph
ts.font_draw_glyph(glyph_data["font_rid"], get_canvas_item(), font_size, Vector2.ZERO, glyph_data["index"], font_color, 2.0)
# add the advance to the offset
offset += glyph_data.get("advance", 0.0)
Wow, this is incredible! This should be a built in feature!! I might make a new topic to get help on a circular bounding box for text wrapping, but this definitely solves my curve problem.