Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/tests/scene/test_path_follow_3d.cpp
45993 views
1
/**************************************************************************/
2
/* test_path_follow_3d.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#include "tests/test_macros.h"
32
33
TEST_FORCE_LINK(test_path_follow_3d)
34
35
#ifndef _3D_DISABLED
36
37
#include "scene/3d/path_3d.h"
38
#include "scene/main/scene_tree.h"
39
#include "scene/main/window.h"
40
41
namespace TestPathFollow3D {
42
43
bool is_equal_approx(const Vector3 &p_a, const Vector3 &p_b) {
44
const real_t tolerance = 0.001;
45
return Math::is_equal_approx(p_a.x, p_b.x, tolerance) &&
46
Math::is_equal_approx(p_a.y, p_b.y, tolerance) &&
47
Math::is_equal_approx(p_a.z, p_b.z, tolerance);
48
}
49
50
TEST_CASE("[SceneTree][PathFollow3D] Sampling with progress ratio") {
51
Ref<Curve3D> curve;
52
curve.instantiate();
53
curve->add_point(Vector3(0, 0, 0));
54
curve->add_point(Vector3(100, 0, 0));
55
curve->add_point(Vector3(100, 100, 0));
56
curve->add_point(Vector3(100, 100, 100));
57
curve->add_point(Vector3(100, 0, 100));
58
Path3D *path = memnew(Path3D);
59
path->set_curve(curve);
60
PathFollow3D *path_follow_3d = memnew(PathFollow3D);
61
path_follow_3d->set_loop(false);
62
path->add_child(path_follow_3d);
63
SceneTree::get_singleton()->get_root()->add_child(path);
64
65
path_follow_3d->set_progress_ratio(0);
66
CHECK(is_equal_approx(Vector3(0, 0, 0), path_follow_3d->get_transform().get_origin()));
67
68
path_follow_3d->set_progress_ratio(0.125);
69
CHECK(is_equal_approx(Vector3(50, 0, 0), path_follow_3d->get_transform().get_origin()));
70
71
path_follow_3d->set_progress_ratio(0.25);
72
CHECK(is_equal_approx(Vector3(100, 0, 0), path_follow_3d->get_transform().get_origin()));
73
74
path_follow_3d->set_progress_ratio(0.375);
75
CHECK(is_equal_approx(Vector3(100, 50, 0), path_follow_3d->get_transform().get_origin()));
76
77
path_follow_3d->set_progress_ratio(0.5);
78
CHECK(is_equal_approx(Vector3(100, 100, 0), path_follow_3d->get_transform().get_origin()));
79
80
path_follow_3d->set_progress_ratio(0.625);
81
CHECK(is_equal_approx(Vector3(100, 100, 50), path_follow_3d->get_transform().get_origin()));
82
83
path_follow_3d->set_progress_ratio(0.75);
84
CHECK(is_equal_approx(Vector3(100, 100, 100), path_follow_3d->get_transform().get_origin()));
85
86
path_follow_3d->set_progress_ratio(0.875);
87
CHECK(is_equal_approx(Vector3(100, 50, 100), path_follow_3d->get_transform().get_origin()));
88
89
path_follow_3d->set_progress_ratio(1);
90
CHECK(is_equal_approx(Vector3(100, 0, 100), path_follow_3d->get_transform().get_origin()));
91
92
memdelete(path);
93
}
94
95
TEST_CASE("[SceneTree][PathFollow3D] Sampling with progress") {
96
Ref<Curve3D> curve;
97
curve.instantiate();
98
curve->add_point(Vector3(0, 0, 0));
99
curve->add_point(Vector3(100, 0, 0));
100
curve->add_point(Vector3(100, 100, 0));
101
curve->add_point(Vector3(100, 100, 100));
102
curve->add_point(Vector3(100, 0, 100));
103
Path3D *path = memnew(Path3D);
104
path->set_curve(curve);
105
PathFollow3D *path_follow_3d = memnew(PathFollow3D);
106
path_follow_3d->set_loop(false);
107
path->add_child(path_follow_3d);
108
SceneTree::get_singleton()->get_root()->add_child(path);
109
110
path_follow_3d->set_progress(0);
111
CHECK(is_equal_approx(Vector3(0, 0, 0), path_follow_3d->get_transform().get_origin()));
112
113
path_follow_3d->set_progress(50);
114
CHECK(is_equal_approx(Vector3(50, 0, 0), path_follow_3d->get_transform().get_origin()));
115
116
path_follow_3d->set_progress(100);
117
CHECK(is_equal_approx(Vector3(100, 0, 0), path_follow_3d->get_transform().get_origin()));
118
119
path_follow_3d->set_progress(150);
120
CHECK(is_equal_approx(Vector3(100, 50, 0), path_follow_3d->get_transform().get_origin()));
121
122
path_follow_3d->set_progress(200);
123
CHECK(is_equal_approx(Vector3(100, 100, 0), path_follow_3d->get_transform().get_origin()));
124
125
path_follow_3d->set_progress(250);
126
CHECK(is_equal_approx(Vector3(100, 100, 50), path_follow_3d->get_transform().get_origin()));
127
128
path_follow_3d->set_progress(300);
129
CHECK(is_equal_approx(Vector3(100, 100, 100), path_follow_3d->get_transform().get_origin()));
130
131
path_follow_3d->set_progress(350);
132
CHECK(is_equal_approx(Vector3(100, 50, 100), path_follow_3d->get_transform().get_origin()));
133
134
path_follow_3d->set_progress(400);
135
CHECK(is_equal_approx(Vector3(100, 0, 100), path_follow_3d->get_transform().get_origin()));
136
137
memdelete(path);
138
}
139
140
TEST_CASE("[SceneTree][PathFollow3D] Removal of a point in curve") {
141
Ref<Curve3D> curve;
142
curve.instantiate();
143
curve->add_point(Vector3(0, 0, 0));
144
curve->add_point(Vector3(100, 0, 0));
145
curve->add_point(Vector3(100, 100, 0));
146
Path3D *path = memnew(Path3D);
147
path->set_curve(curve);
148
PathFollow3D *path_follow_3d = memnew(PathFollow3D);
149
path->add_child(path_follow_3d);
150
SceneTree::get_singleton()->get_root()->add_child(path);
151
152
path_follow_3d->set_progress_ratio(0.5);
153
CHECK(is_equal_approx(Vector3(100, 0, 0), path_follow_3d->get_transform().get_origin()));
154
155
curve->remove_point(1);
156
157
path_follow_3d->set_progress_ratio(0.5);
158
CHECK_MESSAGE(
159
is_equal_approx(Vector3(50, 50, 0), path_follow_3d->get_transform().get_origin()),
160
"Path follow's position should be updated after removing a point from the curve");
161
162
memdelete(path);
163
}
164
165
TEST_CASE("[SceneTree][PathFollow3D] Progress ratio out of range") {
166
Ref<Curve3D> curve;
167
curve.instantiate();
168
curve->add_point(Vector3(0, 0, 0));
169
curve->add_point(Vector3(100, 0, 0));
170
Path3D *path = memnew(Path3D);
171
path->set_curve(curve);
172
PathFollow3D *path_follow_3d = memnew(PathFollow3D);
173
path->add_child(path_follow_3d);
174
SceneTree::get_singleton()->get_root()->add_child(path);
175
176
path_follow_3d->set_loop(true);
177
178
path_follow_3d->set_progress_ratio(-0.3);
179
CHECK_MESSAGE(
180
Math::is_equal_approx(path_follow_3d->get_progress_ratio(), (real_t)0.7),
181
"Progress Ratio should loop back from the end in the opposite direction");
182
183
path_follow_3d->set_progress_ratio(1.3);
184
CHECK_MESSAGE(
185
Math::is_equal_approx(path_follow_3d->get_progress_ratio(), (real_t)0.3),
186
"Progress Ratio should loop back from the end in the opposite direction");
187
188
path_follow_3d->set_loop(false);
189
190
path_follow_3d->set_progress_ratio(-0.3);
191
CHECK_MESSAGE(
192
Math::is_equal_approx(path_follow_3d->get_progress_ratio(), 0),
193
"Progress Ratio should be clamped at 0");
194
195
path_follow_3d->set_progress_ratio(1.3);
196
CHECK_MESSAGE(
197
Math::is_equal_approx(path_follow_3d->get_progress_ratio(), 1),
198
"Progress Ratio should be clamped at 1");
199
200
memdelete(path);
201
}
202
203
TEST_CASE("[SceneTree][PathFollow3D] Progress out of range") {
204
Ref<Curve3D> curve;
205
curve.instantiate();
206
curve->add_point(Vector3(0, 0, 0));
207
curve->add_point(Vector3(100, 0, 0));
208
Path3D *path = memnew(Path3D);
209
path->set_curve(curve);
210
PathFollow3D *path_follow_3d = memnew(PathFollow3D);
211
path->add_child(path_follow_3d);
212
SceneTree::get_singleton()->get_root()->add_child(path);
213
214
path_follow_3d->set_loop(true);
215
216
path_follow_3d->set_progress(-50);
217
CHECK_MESSAGE(
218
Math::is_equal_approx(path_follow_3d->get_progress(), 50),
219
"Progress should loop back from the end in the opposite direction");
220
221
path_follow_3d->set_progress(150);
222
CHECK_MESSAGE(
223
Math::is_equal_approx(path_follow_3d->get_progress(), 50),
224
"Progress should loop back from the end in the opposite direction");
225
226
path_follow_3d->set_loop(false);
227
228
path_follow_3d->set_progress(-50);
229
CHECK_MESSAGE(
230
Math::is_equal_approx(path_follow_3d->get_progress(), 0),
231
"Progress should be clamped at 0");
232
233
path_follow_3d->set_progress(150);
234
CHECK_MESSAGE(
235
Math::is_equal_approx(path_follow_3d->get_progress(), 100),
236
"Progress should be clamped at max value of curve");
237
238
memdelete(path);
239
}
240
241
TEST_CASE("[SceneTree][PathFollow3D] Calculate forward vector") {
242
const real_t dist_cube_100 = 100 * Math::sqrt(3.0);
243
Ref<Curve3D> curve;
244
curve.instantiate();
245
curve->add_point(Vector3(0, 0, 0));
246
curve->add_point(Vector3(100, 0, 0));
247
curve->add_point(Vector3(200, 100, -100));
248
curve->add_point(Vector3(200, 100, 200));
249
curve->add_point(Vector3(100, 0, 100));
250
curve->add_point(Vector3(0, 0, 100));
251
Path3D *path = memnew(Path3D);
252
path->set_curve(curve);
253
PathFollow3D *path_follow_3d = memnew(PathFollow3D);
254
path->add_child(path_follow_3d);
255
SceneTree::get_singleton()->get_root()->add_child(path);
256
257
path_follow_3d->set_loop(false);
258
path_follow_3d->set_rotation_mode(PathFollow3D::RotationMode::ROTATION_ORIENTED);
259
260
path_follow_3d->set_progress(-50);
261
CHECK(is_equal_approx(Vector3(-1, 0, 0), path_follow_3d->get_transform().get_basis().get_column(2)));
262
263
path_follow_3d->set_progress(0);
264
CHECK(is_equal_approx(Vector3(-1, 0, 0), path_follow_3d->get_transform().get_basis().get_column(2)));
265
266
path_follow_3d->set_progress(50);
267
CHECK(is_equal_approx(Vector3(-1, 0, 0), path_follow_3d->get_transform().get_basis().get_column(2)));
268
269
path_follow_3d->set_progress(100);
270
CHECK(is_equal_approx(Vector3(-1, 0, 0), path_follow_3d->get_transform().get_basis().get_column(2)));
271
272
path_follow_3d->set_progress(100 + dist_cube_100 / 2);
273
CHECK(is_equal_approx(Vector3(-0.577348, -0.577348, 0.577348), path_follow_3d->get_transform().get_basis().get_column(2)));
274
275
path_follow_3d->set_progress(100 + dist_cube_100 - 0.01);
276
CHECK(is_equal_approx(Vector3(-0.577348, -0.577348, 0.577348), path_follow_3d->get_transform().get_basis().get_column(2)));
277
278
path_follow_3d->set_progress(250 + dist_cube_100);
279
CHECK(is_equal_approx(Vector3(0, 0, -1), path_follow_3d->get_transform().get_basis().get_column(2)));
280
281
path_follow_3d->set_progress(400 + dist_cube_100 - 0.01);
282
CHECK(is_equal_approx(Vector3(0, 0, -1), path_follow_3d->get_transform().get_basis().get_column(2)));
283
284
path_follow_3d->set_progress(400 + 1.5 * dist_cube_100);
285
CHECK(is_equal_approx(Vector3(0.577348, 0.577348, 0.577348), path_follow_3d->get_transform().get_basis().get_column(2)));
286
287
path_follow_3d->set_progress(400 + 2 * dist_cube_100 - 0.01);
288
CHECK(is_equal_approx(Vector3(0.577348, 0.577348, 0.577348), path_follow_3d->get_transform().get_basis().get_column(2)));
289
290
path_follow_3d->set_progress(500 + 2 * dist_cube_100);
291
CHECK(is_equal_approx(Vector3(1, 0, 0), path_follow_3d->get_transform().get_basis().get_column(2)));
292
293
memdelete(path);
294
}
295
296
TEST_CASE("[SceneTree][PathFollow3D] Calculate forward vector with degenerate curves") {
297
Ref<Curve3D> curve;
298
curve.instantiate();
299
curve->add_point(Vector3(0, 0, 1), Vector3(), Vector3(1, 0, 0));
300
curve->add_point(Vector3(1, 0, 0), Vector3(0, 0, 0), Vector3(0, 0, 0));
301
curve->add_point(Vector3(0, 0, -1), Vector3(1, 0, 0), Vector3(-1, 0, 0));
302
curve->add_point(Vector3(-1, 0, 0), Vector3(0, 0, 0), Vector3(0, 0, 0));
303
curve->add_point(Vector3(0, 0, 1), Vector3(-1, 0, 0), Vector3());
304
Path3D *path = memnew(Path3D);
305
path->set_curve(curve);
306
PathFollow3D *path_follow_3d = memnew(PathFollow3D);
307
path->add_child(path_follow_3d);
308
SceneTree::get_singleton()->get_root()->add_child(path);
309
310
path_follow_3d->set_loop(false);
311
path_follow_3d->set_rotation_mode(PathFollow3D::RotationMode::ROTATION_ORIENTED);
312
313
path_follow_3d->set_progress_ratio(0.00);
314
CHECK(is_equal_approx(Vector3(-1, 0, 0), path_follow_3d->get_transform().get_basis().get_column(2)));
315
316
path_follow_3d->set_progress_ratio(0.25);
317
CHECK(is_equal_approx(Vector3(0, 0, 1), path_follow_3d->get_transform().get_basis().get_column(2)));
318
319
path_follow_3d->set_progress_ratio(0.50);
320
CHECK(is_equal_approx(Vector3(1, 0, 0), path_follow_3d->get_transform().get_basis().get_column(2)));
321
322
path_follow_3d->set_progress_ratio(0.75);
323
CHECK(is_equal_approx(Vector3(0, 0, -1), path_follow_3d->get_transform().get_basis().get_column(2)));
324
325
path_follow_3d->set_progress_ratio(1.00);
326
CHECK(is_equal_approx(Vector3(-1, 0, 0), path_follow_3d->get_transform().get_basis().get_column(2)));
327
328
path_follow_3d->set_progress_ratio(0.125);
329
CHECK(is_equal_approx(Vector3(-0.688375, 0, 0.725355), path_follow_3d->get_transform().get_basis().get_column(2)));
330
331
path_follow_3d->set_progress_ratio(0.375);
332
CHECK(is_equal_approx(Vector3(0.688375, 0, 0.725355), path_follow_3d->get_transform().get_basis().get_column(2)));
333
334
path_follow_3d->set_progress_ratio(0.625);
335
CHECK(is_equal_approx(Vector3(0.688375, 0, -0.725355), path_follow_3d->get_transform().get_basis().get_column(2)));
336
337
path_follow_3d->set_progress_ratio(0.875);
338
CHECK(is_equal_approx(Vector3(-0.688375, 0, -0.725355), path_follow_3d->get_transform().get_basis().get_column(2)));
339
340
memdelete(path);
341
}
342
343
} // namespace TestPathFollow3D
344
345
#endif // _3D_DISABLED
346
347