Why draw_string only draw an square?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By navi2000

I’m trying to write some text without using labels on screen with each of the sprites. My scene is like this:

Node2D
    |-> KinematicBody2D
        |->Sprite
        |->CollisionShape2D

The Sprite has the 50x50 texture (a rounded piece) and I want to add text over it using _draw():

func _draw():
    var _font = load("res://FreePixel.ttf")

	var dynamic_font = DynamicFont.new()
	dynamic_font.font_data = load("res://FreePixel.ttf")
	dynamic_font.size = 30
	draw_string(dynamic_font, Vector2(12, 32), 'aC', Color.red)

All I get is this:

enter image description here

Both characters (‘aC’) are just a red box. If I use the _font instead of dynamic_font resource I get nothing. TTF is here.

What’s wrong?

:bust_in_silhouette: Reply From: Zylann

It’s a bit unintuitive, but the way you wrote your _draw function will not work.
Resources are reference-counted by the places where they are in use.
You are loading the font, but also you don’t store it anywhere. So it gets unloaded when the function finishes… which means Godot has to do the effort of reading it from disk and uploading it to the graphics card every frame.

And as it turns out, the renderer does not actually draw things immediately. Drawing commands are all executed in one go later, in the rendering thread. But at this moment, the font will have been unloaded because you didn’t hold it anywhere. So Godot just draws quads because the font is no longer available.

Finally, you even load the font twice. Once in _font, once in dynamic_font.font_data, this is not necessary.

You should load and create the font in _ready(), store it in a member variable, and use that variable in _draw():

var _dynamic_font

func _ready():
    _dynamic_font = DynamicFont.new()
    _dynamic_font.font_data = load("res://FreePixel.ttf")
    _dynamic_font.size = 30

func _draw():
    draw_string(_dynamic_font, Vector2(12, 32), 'aC', Color.red)

Also, if you want to save yourself some hassle about file paths and renaming, you could even create the DynamicFont resource as a file, and use an export(DynamicFont) var _dynamic_font in your script to assign it in the inspector. This way the path is no longer hardcoded and Godot will update it automatically if you move or rename the resource.
So your code would become:

export(DynamicFont) var _dynamic_font

func _draw():
    draw_string(_dynamic_font, Vector2(12, 32), 'aC', Color.red)

And if you want no code at all, you can use the Label node.