Skip to content

Commit 0d75c4f

Browse files
committed
Add a custom drawing in 2D demo
1 parent fad2469 commit 0d75c4f

25 files changed

+1020
-0
lines changed

2d/custom_drawing/README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Custom drawing in 2D
2+
3+
A demo showing how to draw 2D elements in Godot without using nodes. This can be done
4+
to create procedural graphics, perform debug drawing to help troubleshoot issues in
5+
game logic, or to improve performance by not creating a node for every visible element.
6+
7+
Antialiasing can be performed using two approaches: either by enabling the `antialiasing`
8+
parameter provided by some of the CanvasItem `draw_*` methods, or by enabling 2D MSAA
9+
in the Project Settings. 2D MSAA is generally slower, but it works with any kind of line-based
10+
or polygon-based 2D drawing, even for `draw_*` methods that don't support an `antialiasing`
11+
parameter. Note that 2D MSAA is only available in the Forward+ and Mobile
12+
renderers, not Compatibility.
13+
14+
See [Custom drawing in 2D](https://docs.godotengine.org/en/latest/tutorials/2d/custom_drawing_in_2d.html)
15+
in the documentation for more information.
16+
17+
Language: GDScript
18+
19+
Renderer: Mobile
20+
21+
## Screenshots
22+
23+
![Screenshot](screenshots/custom_drawing.webp)

2d/custom_drawing/animation.gd

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# This is a `@tool` script so that the custom 2D drawing can be seen in the editor.
2+
@tool
3+
extends Panel
4+
5+
var use_antialiasing := false
6+
7+
var time := 0.0
8+
9+
func _process(delta: float) -> void:
10+
# Increment a counter variable that we use in `_draw()`.
11+
time += delta
12+
# Force redrawing on every processed frame, so that the animation can visibly progress.
13+
# Only do this when the node is visible in tree, so that we don't force continuous redrawing
14+
# when not needed (low-processor usage mode is enabled in this demo).
15+
if is_visible_in_tree():
16+
queue_redraw()
17+
18+
19+
func _draw() -> void:
20+
var margin := Vector2(240, 70)
21+
var offset := Vector2()
22+
23+
# Line width of `-1.0` is only usable with draw antialiasing disabled,
24+
# as it uses hardware line drawing as opposed to polygon-based line drawing.
25+
# Automatically use polygon-based line drawing when needed to avoid runtime warnings.
26+
# We also use a line width of `0.5` instead of `1.0` to better match the appearance
27+
# of non-antialiased line drawing, as draw antialiasing tends to make lines look thicker.
28+
var line_width_thin := 0.5 if use_antialiasing else -1.0
29+
30+
# Draw an animated arc to simulate a circular progress bar.
31+
# The start angle is set so the arc starts from the top.
32+
const POINT_COUNT = 48
33+
var progress := wrapf(time, 0.0, 1.0)
34+
draw_arc(
35+
margin + offset,
36+
50.0,
37+
0.75 * TAU,
38+
(0.75 + progress) * TAU,
39+
POINT_COUNT,
40+
Color.MEDIUM_AQUAMARINE,
41+
line_width_thin,
42+
use_antialiasing
43+
)

2d/custom_drawing/animation.gd.uid

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
uid://b8d4d0s3gujbp

2d/custom_drawing/animation_slice.gd

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
extends Control
2+
3+
var use_antialiasing := false
4+
5+
func _draw() -> void:
6+
var margin := Vector2(240, 70)
7+
var offset := Vector2(0, 150)
8+
# This is an example of using draw commands to create animations.
9+
# For "continuous" animations, you can use a timer within `_draw()` and call `queue_redraw()`
10+
# in `_process()` to redraw every frame.
11+
# Animation length in seconds. The animation will loop after the specified duration.
12+
const ANIMATION_LENGTH = 2.0
13+
# 5 frames per second.
14+
const ANIMATION_FRAMES = 10
15+
16+
# Declare an animation frame with randomized rotation and color for each frame.
17+
# `draw_animation_slice()` makes it so the following draw commands are only visible
18+
# on screen when the current time is within the animation slice.
19+
# NOTE: Pause does not affect animations drawn by `draw_animation_slice()`
20+
# (they will keep playing).
21+
for frame in ANIMATION_FRAMES:
22+
# `remap()` is useful to determine the time slice in which a frame is visible.
23+
# For example, on the 2nd frame, `slice_begin` is `0.2` and `slice_end` is `0.4`.
24+
var slice_begin := remap(frame, 0, ANIMATION_FRAMES, 0, ANIMATION_LENGTH)
25+
var slice_end := remap(frame + 1, 0, ANIMATION_FRAMES, 0, ANIMATION_LENGTH)
26+
draw_animation_slice(ANIMATION_LENGTH, slice_begin, slice_end)
27+
draw_set_transform(margin + offset, deg_to_rad(randf_range(-5.0, 5.0)))
28+
draw_rect(
29+
Rect2(Vector2(), Vector2(100, 50)),
30+
Color.from_hsv(randf(), 0.4, 1.0),
31+
true,
32+
-1.0,
33+
use_antialiasing
34+
)
35+
36+
draw_end_animation()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
uid://wksdrvv65620

2d/custom_drawing/custom_drawing.gd

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
extends Control
2+
3+
4+
func _on_msaa_2d_item_selected(index: int) -> void:
5+
get_viewport().msaa_2d = index as Viewport.MSAA
6+
7+
8+
func _on_draw_antialiasing_toggled(toggled_on: bool) -> void:
9+
var nodes: Array[Node] = %TabContainer.get_children()
10+
nodes.push_back(%AnimationSlice)
11+
for tab: Control in nodes:
12+
tab.use_antialiasing = toggled_on
13+
# Force all tabs to redraw so that the antialiasing updates.
14+
tab.queue_redraw()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
uid://cinaeqsrawkbw

2d/custom_drawing/custom_drawing.tscn

Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
[gd_scene load_steps=10 format=3 uid="uid://btxwm0qudsn3t"]
2+
3+
[ext_resource type="Script" uid="uid://cinaeqsrawkbw" path="res://custom_drawing.gd" id="1_rtndo"]
4+
[ext_resource type="Script" uid="uid://3gt2v4l0gy1" path="res://lines.gd" id="2_exx0l"]
5+
[ext_resource type="Script" uid="uid://cquneapbjf3e0" path="res://rectangles.gd" id="3_yrx86"]
6+
[ext_resource type="Script" uid="uid://clsf8dubgyrig" path="res://polygons.gd" id="4_obj11"]
7+
[ext_resource type="Script" uid="uid://dtxyrnurokare" path="res://textures.gd" id="5_84cac"]
8+
[ext_resource type="Script" uid="uid://dy8ofskb8bg4a" path="res://meshes.gd" id="5_exx0l"]
9+
[ext_resource type="Script" uid="uid://0kv1wvfyg058" path="res://text.gd" id="6_4w081"]
10+
[ext_resource type="Script" uid="uid://b8d4d0s3gujbp" path="res://animation.gd" id="8_yrx86"]
11+
[ext_resource type="Script" uid="uid://wksdrvv65620" path="res://animation_slice.gd" id="9_obj11"]
12+
13+
[node name="CustomDrawing" type="Control"]
14+
layout_mode = 3
15+
anchors_preset = 15
16+
anchor_right = 1.0
17+
anchor_bottom = 1.0
18+
grow_horizontal = 2
19+
grow_vertical = 2
20+
script = ExtResource("1_rtndo")
21+
22+
[node name="TabContainer" type="TabContainer" parent="."]
23+
unique_name_in_owner = true
24+
layout_mode = 1
25+
anchors_preset = 15
26+
anchor_right = 1.0
27+
anchor_bottom = 1.0
28+
grow_horizontal = 2
29+
grow_vertical = 2
30+
current_tab = 0
31+
32+
[node name="Lines" type="Panel" parent="TabContainer"]
33+
layout_mode = 2
34+
script = ExtResource("2_exx0l")
35+
metadata/_tab_index = 0
36+
37+
[node name="DrawLine" type="Label" parent="TabContainer/Lines"]
38+
layout_mode = 0
39+
offset_left = 24.0
40+
offset_top = 48.0
41+
offset_right = 172.0
42+
offset_bottom = 97.0
43+
theme_override_colors/font_color = Color(0.501961, 1, 0.501961, 1)
44+
text = "draw_line()
45+
draw_dashed_line()"
46+
47+
[node name="DrawCircle" type="Label" parent="TabContainer/Lines"]
48+
layout_mode = 0
49+
offset_left = 24.0
50+
offset_top = 154.0
51+
offset_right = 122.0
52+
offset_bottom = 177.0
53+
theme_override_colors/font_color = Color(0.501961, 1, 0.501961, 1)
54+
text = "draw_circle()"
55+
56+
[node name="DrawArc" type="Label" parent="TabContainer/Lines"]
57+
layout_mode = 0
58+
offset_left = 24.0
59+
offset_top = 264.0
60+
offset_right = 109.0
61+
offset_bottom = 287.0
62+
theme_override_colors/font_color = Color(0.501961, 1, 0.501961, 1)
63+
text = "draw_arc()"
64+
65+
[node name="Rectangles" type="Panel" parent="TabContainer"]
66+
visible = false
67+
layout_mode = 2
68+
script = ExtResource("3_yrx86")
69+
metadata/_tab_index = 1
70+
71+
[node name="DrawRect" type="Label" parent="TabContainer/Rectangles"]
72+
layout_mode = 0
73+
offset_left = 24.0
74+
offset_top = 48.0
75+
offset_right = 109.0
76+
offset_bottom = 71.0
77+
theme_override_colors/font_color = Color(0.501961, 1, 0.501961, 1)
78+
text = "draw_rect()"
79+
80+
[node name="DrawStyleBox" type="Label" parent="TabContainer/Rectangles"]
81+
layout_mode = 0
82+
offset_left = 24.0
83+
offset_top = 296.0
84+
offset_right = 153.0
85+
offset_bottom = 319.0
86+
text = "draw_style_box()"
87+
88+
[node name="Polygons" type="Panel" parent="TabContainer"]
89+
visible = false
90+
layout_mode = 2
91+
script = ExtResource("4_obj11")
92+
metadata/_tab_index = 2
93+
94+
[node name="DrawPrimitive" type="Label" parent="TabContainer/Polygons"]
95+
layout_mode = 0
96+
offset_left = 24.0
97+
offset_top = 48.0
98+
offset_right = 207.0
99+
offset_bottom = 97.0
100+
text = "draw_primitive()"
101+
102+
[node name="DrawPolygon" type="Label" parent="TabContainer/Polygons"]
103+
layout_mode = 0
104+
offset_left = 24.0
105+
offset_top = 168.0
106+
offset_right = 207.0
107+
offset_bottom = 217.0
108+
text = "draw_polygon()
109+
draw_colored_polygon()"
110+
111+
[node name="DrawPolyline" type="Label" parent="TabContainer/Polygons"]
112+
layout_mode = 0
113+
offset_left = 24.0
114+
offset_top = 264.0
115+
offset_right = 195.0
116+
offset_bottom = 313.0
117+
theme_override_colors/font_color = Color(0.501961, 1, 0.501961, 1)
118+
text = "draw_polyline()
119+
draw_polyline_colors()"
120+
121+
[node name="DrawMultiline" type="Label" parent="TabContainer/Polygons"]
122+
layout_mode = 0
123+
offset_left = 24.0
124+
offset_top = 392.0
125+
offset_right = 203.0
126+
offset_bottom = 441.0
127+
theme_override_colors/font_color = Color(0.501961, 1, 0.501961, 1)
128+
text = "draw_multiline()
129+
draw_multiline_colors()"
130+
131+
[node name="Meshes" type="Panel" parent="TabContainer"]
132+
visible = false
133+
layout_mode = 2
134+
script = ExtResource("5_exx0l")
135+
metadata/_tab_index = 3
136+
137+
[node name="DrawMesh" type="Label" parent="TabContainer/Meshes"]
138+
layout_mode = 0
139+
offset_left = 24.0
140+
offset_top = 48.0
141+
offset_right = 207.0
142+
offset_bottom = 97.0
143+
text = "draw_mesh()"
144+
145+
[node name="DrawMultiMesh" type="Label" parent="TabContainer/Meshes"]
146+
layout_mode = 0
147+
offset_left = 24.0
148+
offset_top = 208.0
149+
offset_right = 207.0
150+
offset_bottom = 257.0
151+
text = "draw_multimesh()"
152+
153+
[node name="Textures" type="Panel" parent="TabContainer"]
154+
visible = false
155+
texture_repeat = 2
156+
layout_mode = 2
157+
script = ExtResource("5_84cac")
158+
metadata/_tab_index = 4
159+
160+
[node name="DrawTexture" type="Label" parent="TabContainer/Textures"]
161+
layout_mode = 0
162+
offset_left = 24.0
163+
offset_top = 48.0
164+
offset_right = 175.0
165+
offset_bottom = 97.0
166+
text = "draw_texture()
167+
draw_texture_rect()"
168+
169+
[node name="DrawTextureRectRegion" type="Label" parent="TabContainer/Textures"]
170+
layout_mode = 0
171+
offset_left = 24.0
172+
offset_top = 392.0
173+
offset_right = 231.0
174+
offset_bottom = 415.0
175+
text = "draw_texture_rect_region()"
176+
177+
[node name="Text" type="Panel" parent="TabContainer"]
178+
visible = false
179+
layout_mode = 2
180+
script = ExtResource("6_4w081")
181+
metadata/_tab_index = 5
182+
183+
[node name="DrawChar" type="Label" parent="TabContainer/Text"]
184+
layout_mode = 0
185+
offset_left = 24.0
186+
offset_top = 48.0
187+
offset_right = 125.0
188+
offset_bottom = 97.0
189+
text = "draw_char()
190+
draw_string()"
191+
192+
[node name="Animation" type="Panel" parent="TabContainer"]
193+
visible = false
194+
layout_mode = 2
195+
script = ExtResource("8_yrx86")
196+
metadata/_tab_index = 6
197+
198+
[node name="DrawArcTime" type="Label" parent="TabContainer/Animation"]
199+
layout_mode = 0
200+
offset_left = 24.0
201+
offset_top = 48.0
202+
offset_right = 125.0
203+
offset_bottom = 97.0
204+
theme_override_colors/font_color = Color(0.501961, 1, 0.501961, 1)
205+
text = "draw_arc()
206+
+ time variable"
207+
208+
[node name="DrawAnimationSlice" type="Label" parent="TabContainer/Animation"]
209+
layout_mode = 0
210+
offset_left = 24.0
211+
offset_top = 216.0
212+
offset_right = 201.0
213+
offset_bottom = 265.0
214+
text = "draw_animation_slice()"
215+
216+
[node name="AnimationSlice" type="Control" parent="TabContainer/Animation"]
217+
unique_name_in_owner = true
218+
layout_mode = 1
219+
anchors_preset = 15
220+
anchor_right = 1.0
221+
anchor_bottom = 1.0
222+
grow_horizontal = 2
223+
grow_vertical = 2
224+
script = ExtResource("9_obj11")
225+
226+
[node name="Options" type="HBoxContainer" parent="."]
227+
layout_mode = 1
228+
anchors_preset = 2
229+
anchor_top = 1.0
230+
anchor_bottom = 1.0
231+
offset_left = 24.0
232+
offset_top = -64.0
233+
offset_right = 441.0
234+
offset_bottom = -24.0
235+
grow_vertical = 0
236+
theme_override_constants/separation = 20
237+
238+
[node name="MSAA2DLabel" type="Label" parent="Options"]
239+
layout_mode = 2
240+
text = "MSAA 2D"
241+
242+
[node name="MSAA2DOptionButton" type="OptionButton" parent="Options"]
243+
layout_mode = 2
244+
selected = 0
245+
item_count = 4
246+
popup/item_0/text = "Disabled"
247+
popup/item_0/id = 0
248+
popup/item_1/text = "2×"
249+
popup/item_1/id = 1
250+
popup/item_2/text = "4×"
251+
popup/item_2/id = 2
252+
popup/item_3/text = "8×"
253+
popup/item_3/id = 3
254+
255+
[node name="VSeparator" type="VSeparator" parent="Options"]
256+
layout_mode = 2
257+
258+
[node name="DrawAntialiasing" type="CheckButton" parent="Options"]
259+
layout_mode = 2
260+
tooltip_text = "Performs antialiasing by adding a feathered outline
261+
to lines that are drawn in 2D. This is generally faster to render
262+
than 2D MSAA, but not all draw commands support it.
263+
264+
Commands that support draw antialiasing are
265+
highlighted in green."
266+
theme_override_colors/font_color = Color(0.501961, 1, 0.501961, 1)
267+
theme_override_colors/font_focus_color = Color(0.501961, 1, 0.501961, 1)
268+
theme_override_colors/font_pressed_color = Color(0.501961, 1, 0.501961, 1)
269+
text = "Draw Antialiasing"
270+
271+
[connection signal="item_selected" from="Options/MSAA2DOptionButton" to="." method="_on_msaa_2d_item_selected"]
272+
[connection signal="toggled" from="Options/DrawAntialiasing" to="." method="_on_draw_antialiasing_toggled"]

0 commit comments

Comments
 (0)