Up to date
This page is up to date for Godot 4.1
.
If you still find outdated information, please open an issue.
Custom drawing in 2D¶
Introduction¶
Godot has nodes to draw sprites, polygons, particles, and all sorts of stuff. For most cases, this is enough. If there's no node to draw something specific you need, you can make any 2D node (for example, Control or Node2D based) draw custom commands.
Custom drawing in a 2D node is really useful. Here are some use cases:
Drawing shapes or logic that existing nodes can't do, such as an image with trails or a special animated polygon.
Visualizations that are not that compatible with nodes, such as a tetris board. (The tetris example uses a custom draw function to draw the blocks.)
Drawing a large number of simple objects. Custom drawing avoids the overhead of using a large number of nodes, possibly lowering memory usage and improving performance.
Making a custom UI control. There are plenty of controls available, but when you have unusual needs, you will likely need a custom control.
Drawing¶
Add a script to any CanvasItem
derived node, like Control or
Node2D. Then override the _draw()
function.
extends Node2D
func _draw():
# Your draw commands here
pass
public override void _Draw()
{
// Your draw commands here
}
Draw commands are described in the CanvasItem class reference. There are plenty of them.
Updating¶
The _draw()
function is only called once, and then the draw commands
are cached and remembered, so further calls are unnecessary.
If re-drawing is required because a state or something else changed,
call CanvasItem.queue_redraw()
in that same node and a new _draw()
call will happen.
Here is a little more complex example, a texture variable that will be redrawn if modified:
extends Node2D
@export var texture: Texture:
set = _set_texture
func _set_texture(value):
# If the texture variable is modified externally,
# this callback is called.
texture = value # Texture was changed.
queue_redraw() # Trigger a redraw of the node.
func _draw():
draw_texture(texture, Vector2())
using Godot;
public partial class MyNode2D : Node2D
{
private Texture _texture;
public Texture Texture
{
get
{
return _texture;
}
set
{
_texture = value;
QueueRedraw();
}
}
public override void _Draw()
{
DrawTexture(_texture, new Vector2());
}
}
In some cases, it may be desired to draw every frame. For this,
call queue_redraw()
from the _process()
callback, like this:
extends Node2D
func _draw():
# Your draw commands here
pass
func _process(delta):
queue_redraw()