Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/tests/scene/test_path_follow_3d.h
10277 views
1
/**************************************************************************/
2
/* test_path_follow_3d.h */
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
#pragma once
32
33
#include "scene/3d/path_3d.h"
34
#include "scene/main/window.h"
35
36
#include "tests/test_macros.h"
37
38
namespace TestPathFollow3D {
39
40
bool is_equal_approx(const Vector3 &p_a, const Vector3 &p_b) {
41
const real_t tolerance = 0.001;
42
return Math::is_equal_approx(p_a.x, p_b.x, tolerance) &&
43
Math::is_equal_approx(p_a.y, p_b.y, tolerance) &&
44
Math::is_equal_approx(p_a.z, p_b.z, tolerance);
45
}
46
47
TEST_CASE("[SceneTree][PathFollow3D] Sampling with progress ratio") {
48
Ref<Curve3D> curve;
49
curve.instantiate();
50
curve->add_point(Vector3(0, 0, 0));
51
curve->add_point(Vector3(100, 0, 0));
52
curve->add_point(Vector3(100, 100, 0));
53
curve->add_point(Vector3(100, 100, 100));
54
curve->add_point(Vector3(100, 0, 100));
55
Path3D *path = memnew(Path3D);
56
path->set_curve(curve);
57
PathFollow3D *path_follow_3d = memnew(PathFollow3D);
58
path_follow_3d->set_loop(false);
59
path->add_child(path_follow_3d);
60
SceneTree::get_singleton()->get_root()->add_child(path);
61
62
path_follow_3d->set_progress_ratio(0);
63
CHECK(is_equal_approx(Vector3(0, 0, 0), path_follow_3d->get_transform().get_origin()));
64
65
path_follow_3d->set_progress_ratio(0.125);
66
CHECK(is_equal_approx(Vector3(50, 0, 0), path_follow_3d->get_transform().get_origin()));
67
68
path_follow_3d->set_progress_ratio(0.25);
69
CHECK(is_equal_approx(Vector3(100, 0, 0), path_follow_3d->get_transform().get_origin()));
70
71
path_follow_3d->set_progress_ratio(0.375);
72
CHECK(is_equal_approx(Vector3(100, 50, 0), path_follow_3d->get_transform().get_origin()));
73
74
path_follow_3d->set_progress_ratio(0.5);
75
CHECK(is_equal_approx(Vector3(100, 100, 0), path_follow_3d->get_transform().get_origin()));
76
77
path_follow_3d->set_progress_ratio(0.625);
78
CHECK(is_equal_approx(Vector3(100, 100, 50), path_follow_3d->get_transform().get_origin()));
79
80
path_follow_3d->set_progress_ratio(0.75);
81
CHECK(is_equal_approx(Vector3(100, 100, 100), path_follow_3d->get_transform().get_origin()));
82
83
path_follow_3d->set_progress_ratio(0.875);
84
CHECK(is_equal_approx(Vector3(100, 50, 100), path_follow_3d->get_transform().get_origin()));
85
86
path_follow_3d->set_progress_ratio(1);
87
CHECK(is_equal_approx(Vector3(100, 0, 100), path_follow_3d->get_transform().get_origin()));
88
89
memdelete(path);
90
}
91
92
TEST_CASE("[SceneTree][PathFollow3D] Sampling with progress") {
93
Ref<Curve3D> curve;
94
curve.instantiate();
95
curve->add_point(Vector3(0, 0, 0));
96
curve->add_point(Vector3(100, 0, 0));
97
curve->add_point(Vector3(100, 100, 0));
98
curve->add_point(Vector3(100, 100, 100));
99
curve->add_point(Vector3(100, 0, 100));
100
Path3D *path = memnew(Path3D);
101
path->set_curve(curve);
102
PathFollow3D *path_follow_3d = memnew(PathFollow3D);
103
path_follow_3d->set_loop(false);
104
path->add_child(path_follow_3d);
105
SceneTree::get_singleton()->get_root()->add_child(path);
106
107
path_follow_3d->set_progress(0);
108
CHECK(is_equal_approx(Vector3(0, 0, 0), path_follow_3d->get_transform().get_origin()));
109
110
path_follow_3d->set_progress(50);
111
CHECK(is_equal_approx(Vector3(50, 0, 0), path_follow_3d->get_transform().get_origin()));
112
113
path_follow_3d->set_progress(100);
114
CHECK(is_equal_approx(Vector3(100, 0, 0), path_follow_3d->get_transform().get_origin()));
115
116
path_follow_3d->set_progress(150);
117
CHECK(is_equal_approx(Vector3(100, 50, 0), path_follow_3d->get_transform().get_origin()));
118
119
path_follow_3d->set_progress(200);
120
CHECK(is_equal_approx(Vector3(100, 100, 0), path_follow_3d->get_transform().get_origin()));
121
122
path_follow_3d->set_progress(250);
123
CHECK(is_equal_approx(Vector3(100, 100, 50), path_follow_3d->get_transform().get_origin()));
124
125
path_follow_3d->set_progress(300);
126
CHECK(is_equal_approx(Vector3(100, 100, 100), path_follow_3d->get_transform().get_origin()));
127
128
path_follow_3d->set_progress(350);
129
CHECK(is_equal_approx(Vector3(100, 50, 100), path_follow_3d->get_transform().get_origin()));
130
131
path_follow_3d->set_progress(400);
132
CHECK(is_equal_approx(Vector3(100, 0, 100), path_follow_3d->get_transform().get_origin()));
133
134
memdelete(path);
135
}
136
137
TEST_CASE("[SceneTree][PathFollow3D] Removal of a point in curve") {
138
Ref<Curve3D> curve;
139
curve.instantiate();
140
curve->add_point(Vector3(0, 0, 0));
141
curve->add_point(Vector3(100, 0, 0));
142
curve->add_point(Vector3(100, 100, 0));
143
Path3D *path = memnew(Path3D);
144
path->set_curve(curve);
145
PathFollow3D *path_follow_3d = memnew(PathFollow3D);
146
path->add_child(path_follow_3d);
147
SceneTree::get_singleton()->get_root()->add_child(path);
148
149
path_follow_3d->set_progress_ratio(0.5);
150
CHECK(is_equal_approx(Vector3(100, 0, 0), path_follow_3d->get_transform().get_origin()));
151
152
curve->remove_point(1);
153
154
path_follow_3d->set_progress_ratio(0.5);
155
CHECK_MESSAGE(
156
is_equal_approx(Vector3(50, 50, 0), path_follow_3d->get_transform().get_origin()),
157
"Path follow's position should be updated after removing a point from the curve");
158
159
memdelete(path);
160
}
161
162
TEST_CASE("[SceneTree][PathFollow3D] Progress ratio out of range") {
163
Ref<Curve3D> curve;
164
curve.instantiate();
165
curve->add_point(Vector3(0, 0, 0));
166
curve->add_point(Vector3(100, 0, 0));
167
Path3D *path = memnew(Path3D);
168
path->set_curve(curve);
169
PathFollow3D *path_follow_3d = memnew(PathFollow3D);
170
path->add_child(path_follow_3d);
171
SceneTree::get_singleton()->get_root()->add_child(path);
172
173
path_follow_3d->set_loop(true);
174
175
path_follow_3d->set_progress_ratio(-0.3);
176
CHECK_MESSAGE(
177
Math::is_equal_approx(path_follow_3d->get_progress_ratio(), (real_t)0.7),
178
"Progress Ratio should loop back from the end in the opposite direction");
179
180
path_follow_3d->set_progress_ratio(1.3);
181
CHECK_MESSAGE(
182
Math::is_equal_approx(path_follow_3d->get_progress_ratio(), (real_t)0.3),
183
"Progress Ratio should loop back from the end in the opposite direction");
184
185
path_follow_3d->set_loop(false);
186
187
path_follow_3d->set_progress_ratio(-0.3);
188
CHECK_MESSAGE(
189
Math::is_equal_approx(path_follow_3d->get_progress_ratio(), 0),
190
"Progress Ratio should be clamped at 0");
191
192
path_follow_3d->set_progress_ratio(1.3);
193
CHECK_MESSAGE(
194
Math::is_equal_approx(path_follow_3d->get_progress_ratio(), 1),
195
"Progress Ratio should be clamped at 1");
196
197
memdelete(path);
198
}
199
200
TEST_CASE("[SceneTree][PathFollow3D] Progress out of range") {
201
Ref<Curve3D> curve;
202
curve.instantiate();
203
curve->add_point(Vector3(0, 0, 0));
204
curve->add_point(Vector3(100, 0, 0));
205
Path3D *path = memnew(Path3D);
206
path->set_curve(curve);
207
PathFollow3D *path_follow_3d = memnew(PathFollow3D);
208
path->add_child(path_follow_3d);
209
SceneTree::get_singleton()->get_root()->add_child(path);
210
211
path_follow_3d->set_loop(true);
212
213
path_follow_3d->set_progress(-50);
214
CHECK_MESSAGE(
215
Math::is_equal_approx(path_follow_3d->get_progress(), 50),
216
"Progress should loop back from the end in the opposite direction");
217
218
path_follow_3d->set_progress(150);
219
CHECK_MESSAGE(
220
Math::is_equal_approx(path_follow_3d->get_progress(), 50),
221
"Progress should loop back from the end in the opposite direction");
222
223
path_follow_3d->set_loop(false);
224
225
path_follow_3d->set_progress(-50);
226
CHECK_MESSAGE(
227
Math::is_equal_approx(path_follow_3d->get_progress(), 0),
228
"Progress should be clamped at 0");
229
230
path_follow_3d->set_progress(150);
231
CHECK_MESSAGE(
232
Math::is_equal_approx(path_follow_3d->get_progress(), 100),
233
"Progress should be clamped at max value of curve");
234
235
memdelete(path);
236
}
237
238
TEST_CASE("[SceneTree][PathFollow3D] Calculate forward vector") {
239
const real_t dist_cube_100 = 100 * Math::sqrt(3.0);
240
Ref<Curve3D> curve;
241
curve.instantiate();
242
curve->add_point(Vector3(0, 0, 0));
243
curve->add_point(Vector3(100, 0, 0));
244
curve->add_point(Vector3(200, 100, -100));
245
curve->add_point(Vector3(200, 100, 200));
246
curve->add_point(Vector3(100, 0, 100));
247
curve->add_point(Vector3(0, 0, 100));
248
Path3D *path = memnew(Path3D);
249
path->set_curve(curve);
250
PathFollow3D *path_follow_3d = memnew(PathFollow3D);
251
path->add_child(path_follow_3d);
252
SceneTree::get_singleton()->get_root()->add_child(path);
253
254
path_follow_3d->set_loop(false);
255
path_follow_3d->set_rotation_mode(PathFollow3D::RotationMode::ROTATION_ORIENTED);
256
257
path_follow_3d->set_progress(-50);
258
CHECK(is_equal_approx(Vector3(-1, 0, 0), path_follow_3d->get_transform().get_basis().get_column(2)));
259
260
path_follow_3d->set_progress(0);
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(50);
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(100);
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 + dist_cube_100 / 2);
270
CHECK(is_equal_approx(Vector3(-0.577348, -0.577348, 0.577348), path_follow_3d->get_transform().get_basis().get_column(2)));
271
272
path_follow_3d->set_progress(100 + dist_cube_100 - 0.01);
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(250 + dist_cube_100);
276
CHECK(is_equal_approx(Vector3(0, 0, -1), path_follow_3d->get_transform().get_basis().get_column(2)));
277
278
path_follow_3d->set_progress(400 + dist_cube_100 - 0.01);
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 + 1.5 * dist_cube_100);
282
CHECK(is_equal_approx(Vector3(0.577348, 0.577348, 0.577348), path_follow_3d->get_transform().get_basis().get_column(2)));
283
284
path_follow_3d->set_progress(400 + 2 * dist_cube_100 - 0.01);
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(500 + 2 * dist_cube_100);
288
CHECK(is_equal_approx(Vector3(1, 0, 0), path_follow_3d->get_transform().get_basis().get_column(2)));
289
290
memdelete(path);
291
}
292
293
TEST_CASE("[SceneTree][PathFollow3D] Calculate forward vector with degenerate curves") {
294
Ref<Curve3D> curve;
295
curve.instantiate();
296
curve->add_point(Vector3(0, 0, 1), Vector3(), Vector3(1, 0, 0));
297
curve->add_point(Vector3(1, 0, 0), Vector3(0, 0, 0), Vector3(0, 0, 0));
298
curve->add_point(Vector3(0, 0, -1), Vector3(1, 0, 0), Vector3(-1, 0, 0));
299
curve->add_point(Vector3(-1, 0, 0), Vector3(0, 0, 0), Vector3(0, 0, 0));
300
curve->add_point(Vector3(0, 0, 1), Vector3(-1, 0, 0), Vector3());
301
Path3D *path = memnew(Path3D);
302
path->set_curve(curve);
303
PathFollow3D *path_follow_3d = memnew(PathFollow3D);
304
path->add_child(path_follow_3d);
305
SceneTree::get_singleton()->get_root()->add_child(path);
306
307
path_follow_3d->set_loop(false);
308
path_follow_3d->set_rotation_mode(PathFollow3D::RotationMode::ROTATION_ORIENTED);
309
310
path_follow_3d->set_progress_ratio(0.00);
311
CHECK(is_equal_approx(Vector3(-1, 0, 0), path_follow_3d->get_transform().get_basis().get_column(2)));
312
313
path_follow_3d->set_progress_ratio(0.25);
314
CHECK(is_equal_approx(Vector3(0, 0, 1), path_follow_3d->get_transform().get_basis().get_column(2)));
315
316
path_follow_3d->set_progress_ratio(0.50);
317
CHECK(is_equal_approx(Vector3(1, 0, 0), path_follow_3d->get_transform().get_basis().get_column(2)));
318
319
path_follow_3d->set_progress_ratio(0.75);
320
CHECK(is_equal_approx(Vector3(0, 0, -1), path_follow_3d->get_transform().get_basis().get_column(2)));
321
322
path_follow_3d->set_progress_ratio(1.00);
323
CHECK(is_equal_approx(Vector3(-1, 0, 0), path_follow_3d->get_transform().get_basis().get_column(2)));
324
325
path_follow_3d->set_progress_ratio(0.125);
326
CHECK(is_equal_approx(Vector3(-0.688375, 0, 0.725355), path_follow_3d->get_transform().get_basis().get_column(2)));
327
328
path_follow_3d->set_progress_ratio(0.375);
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.625);
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.875);
335
CHECK(is_equal_approx(Vector3(-0.688375, 0, -0.725355), path_follow_3d->get_transform().get_basis().get_column(2)));
336
337
memdelete(path);
338
}
339
340
} // namespace TestPathFollow3D
341
342