You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -39,14 +39,22 @@ Add a script to any :ref:`CanvasItem <class_CanvasItem>`
39
39
derived node, like :ref:`Control <class_Control>` or
40
40
:ref:`Node2D <class_Node2D>`. Then override the _draw() function.
41
41
42
-
::
42
+
.. tabs::
43
+
.. code-tab:: gdscript GDScript
43
44
44
45
extends Node2D
45
46
46
47
func _draw():
47
-
#your draw commands here
48
+
# Your draw commands here
48
49
pass
49
50
51
+
.. code-tab:: csharp
52
+
53
+
public override void _Draw()
54
+
{
55
+
// Your draw commands here
56
+
}
57
+
50
58
Draw commands are described in the :ref:`CanvasItem <class_CanvasItem>`
51
59
class reference. There are plenty of them.
52
60
@@ -63,7 +71,8 @@ in that same node and a new _draw() call will happen.
63
71
Here is a little more complex example. A texture variable that will be
64
72
redrawn if modified:
65
73
66
-
::
74
+
.. tabs::
75
+
.. code-tab:: gdscript GDScript
67
76
68
77
extends Node2D
69
78
@@ -78,20 +87,61 @@ redrawn if modified:
78
87
func _draw():
79
88
draw_texture(texture, Vector2())
80
89
90
+
.. code-tab:: csharp
91
+
92
+
public class CustomNode2D : Node2D
93
+
{
94
+
private Texture _texture;
95
+
public Texture Texture
96
+
{
97
+
get
98
+
{
99
+
return _texture;
100
+
}
101
+
102
+
set
103
+
{
104
+
_texture = value;
105
+
Update();
106
+
}
107
+
}
108
+
109
+
public override void _Draw()
110
+
{
111
+
DrawTexture(_texture, new Vector2());
112
+
}
113
+
}
114
+
81
115
In some cases, it may be desired to draw every frame. For this, just
82
116
call update() from the _process() callback, like this:
83
117
84
-
::
118
+
.. tabs::
119
+
.. code-tab:: gdscript GDScript
85
120
86
121
extends Node2D
87
122
88
123
func _draw():
89
-
#your draw commands here
124
+
# Your draw commands here
90
125
pass
91
126
92
127
func _process(delta):
93
128
update()
94
129
130
+
.. code-tab:: csharp
131
+
132
+
public class CustomNode2D : Node2D
133
+
{
134
+
public override _Draw()
135
+
{
136
+
// Your draw commands here
137
+
}
138
+
139
+
public override _Process(delta)
140
+
{
141
+
Update();
142
+
}
143
+
}
144
+
95
145
96
146
An example: drawing circular arcs
97
147
----------------------------------
@@ -106,20 +156,38 @@ An arc is defined by its support circle parameters. That is: the center position
106
156
107
157
Basically, drawing a shape on screen requires it to be decomposed into a certain number of points, linked from one to the following one. As you can imagine, the more points your shape is made of, the smoother it will appear, but the heavier it will be, in terms of processing cost. In general, if your shape is huge (or in 3D, close to the camera), it will require more points to be drawn without it being angular-looking. On the contrary, if your shape is small (or in 3D, far from the camera), you may reduce its number of points to save processing costs. This is called *Level of Detail (LoD)*. In our example, we will simply use a fixed number of points, no matter the radius.
pointsArc[i] = center + new Vector2(Mathf.Cos(anglePoint), Mathf.Sin(anglePoint)) * radius;
184
+
}
185
+
186
+
for (int i = 0; i < nbPoints - 1; ++i)
187
+
DrawLine(pointsArc[i], pointsArc[i + 1], color);
188
+
}
189
+
190
+
123
191
Remember the number of points our shape has to be decomposed into? We fixed this number in the nb_points variable to a value of 32. Then, we initialize an empty PoolVector2Array, which is simply an array of Vector2.
124
192
125
193
The next step consists of computing the actual positions of these 32 points that compose an arc. This is done in the first for-loop: we iterate over the number of points for which we want to compute the positions, plus one to include the last point. We first determine the angle of each point, between the starting and ending angles.
@@ -134,7 +202,9 @@ Draw the arc on screen
134
202
^^^^^^^^^^^^^^^^^^^^^^
135
203
We now have a function that draws stuff on the screen: it is time to call in the _draw() function.
136
204
137
-
::
205
+
.. tabs::
206
+
207
+
.. code-tab:: gdscript GDScript
138
208
139
209
func _draw():
140
210
var center = Vector2(200, 200)
@@ -144,6 +214,18 @@ We now have a function that draws stuff on the screen: it is time to call in the
We can take this a step further and not only write a function that draws the plain portion of the disc defined by the arc, but also its shape. The method is exactly the same as previously, except that we draw a polygon instead of lines:
pointsArc[i + 1] = center + new Vector2(Mathf.Cos(anglePoint), Mathf.Sin(anglePoint)) * radius;
266
+
}
267
+
268
+
DrawPolygon(pointsArc, colors);
269
+
}
270
+
170
271
171
272
.. image:: img/result_drawarc_poly.png
172
273
@@ -176,48 +277,95 @@ Alright, we are now able to draw custom stuff on screen. However, it is very sta
176
277
177
278
First, we have to make both angle_from and angle_to variables global at the top of our script. Also note that you can store them in other nodes and access them using get_node().
178
279
179
-
::
280
+
.. tabs::
281
+
.. code-tab:: gdscript GDScript
180
282
181
-
extends Node2D
283
+
extends Node2D
182
284
183
-
var rotation_ang = 50
184
-
var angle_from = 75
185
-
var angle_to = 195
285
+
var rotation_angle = 50
286
+
var angle_from = 75
287
+
var angle_to = 195
186
288
289
+
.. code-tab:: csharp
187
290
291
+
public class CustomNode2D : Node2D
292
+
{
293
+
private float _rotationAngle = 50;
294
+
private float _angleFrom = 75;
295
+
private float _angleTo = 195;
296
+
}
188
297
189
298
We make these values change in the _process(delta) function.
190
299
191
300
We also increment our angle_from and angle_to values here. However, we must not forget to wrap() the resulting values between 0 and 360°! That is, if the angle is 361°, then it is actually 1°. If you don't wrap these values, the script will work correctly. But angle values will grow bigger and bigger over time, until they reach the maximum integer value Godot can manage (2^31 - 1). When this happens, Godot may crash or produce unexpected behavior. Since Godot doesn't provide a wrap() function, we'll create it here, as it is relatively simple.
192
301
193
302
Finally, we must not forget to call the update() function, which automatically calls _draw(). This way, you can control when you want to refresh the frame.
194
303
195
-
::
304
+
.. tabs::
305
+
.. code-tab:: gdscript GDScript
196
306
197
-
func wrap(value, min_val, max_val):
198
-
var f1 = value - min_val
199
-
var f2 = max_val - min_val
200
-
return fmod(f1, f2) + min_val
307
+
func wrap(value, min_val, max_val):
308
+
var f1 = value - min_val
309
+
var f2 = max_val - min_val
310
+
return fmod(f1, f2) + min_val
201
311
202
-
func _process(delta):
203
-
angle_from += rotation_ang
204
-
angle_to += rotation_ang
312
+
func _process(delta):
313
+
angle_from += rotation_ang
314
+
angle_to += rotation_ang
205
315
206
-
# we only wrap angles if both of them are bigger than 360
207
-
if angle_from > 360 and angle_to > 360:
208
-
angle_from = wrap(angle_from, 0, 360)
209
-
angle_to = wrap(angle_to, 0, 360)
210
-
update()
316
+
# We only wrap angles if both of them are bigger than 360
draw_circle_arc( center, radius, angle_from, angle_to, color )
221
369
222
370
Let's run!
223
371
It works, but the arc is rotating insanely fast! What's wrong?
@@ -226,17 +374,35 @@ The reason is that your GPU is actually displaying the frames as fast as it can.
226
374
227
375
In our case, we simply need to multiply our 'rotation_ang' variable by 'delta' in the _process() function. This way, our 2 angles will be increased by a much smaller value, which directly depends on the rendering speed.
228
376
229
-
::
377
+
.. tabs::
378
+
.. code-tab:: gdscript GDScript
230
379
231
-
func _process(delta):
232
-
angle_from += rotation_ang * delta
233
-
angle_to += rotation_ang * delta
380
+
func _process(delta):
381
+
angle_from += rotation_ang * delta
382
+
angle_to += rotation_ang * delta
234
383
235
-
# we only wrap angles if both of them are bigger than 360
236
-
if angle_from > 360 and angle_to > 360:
237
-
angle_from = wrap(angle_from, 0, 360)
238
-
angle_to = wrap(angle_to, 0, 360)
239
-
update()
384
+
# we only wrap angles if both of them are bigger than 360
385
+
if angle_from > 360 and angle_to > 360:
386
+
angle_from = wrap(angle_from, 0, 360)
387
+
angle_to = wrap(angle_to, 0, 360)
388
+
update()
389
+
390
+
.. code-tab:: csharp
391
+
392
+
public override void _Process(float delta)
393
+
{
394
+
_angleFrom += _rotationAngle * delta;
395
+
_angleTo += _rotationAngle * delta;
396
+
397
+
// We only wrap angles if both of them are bigger than 360
398
+
if (_angleFrom > 360 && _angleTo > 360)
399
+
{
400
+
_angleFrom = Wrap(_angleFrom, 0, 360);
401
+
_angleTo = Wrap(_angleTo, 0, 360);
402
+
}
403
+
Update();
404
+
}
405
+
240
406
241
407
Let's run again! This time, the rotation displays fine!
0 commit comments