test_path_follow_3d.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  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. #ifndef TEST_PATH_FOLLOW_3D_H
  31. #define TEST_PATH_FOLLOW_3D_H
  32. #include "scene/3d/path_3d.h"
  33. #include "scene/main/window.h"
  34. #include "tests/test_macros.h"
  35. namespace TestPathFollow3D {
  36. bool is_equal_approx(const Vector3 &p_a, const Vector3 &p_b) {
  37. const real_t tolerance = 0.001;
  38. return Math::is_equal_approx(p_a.x, p_b.x, tolerance) &&
  39. Math::is_equal_approx(p_a.y, p_b.y, tolerance) &&
  40. Math::is_equal_approx(p_a.z, p_b.z, tolerance);
  41. }
  42. TEST_CASE("[SceneTree][PathFollow3D] Sampling with progress ratio") {
  43. Ref<Curve3D> curve = memnew(Curve3D);
  44. curve->add_point(Vector3(0, 0, 0));
  45. curve->add_point(Vector3(100, 0, 0));
  46. curve->add_point(Vector3(100, 100, 0));
  47. curve->add_point(Vector3(100, 100, 100));
  48. curve->add_point(Vector3(100, 0, 100));
  49. Path3D *path = memnew(Path3D);
  50. path->set_curve(curve);
  51. PathFollow3D *path_follow_3d = memnew(PathFollow3D);
  52. path_follow_3d->set_loop(false);
  53. path->add_child(path_follow_3d);
  54. SceneTree::get_singleton()->get_root()->add_child(path);
  55. path_follow_3d->set_progress_ratio(0);
  56. CHECK(is_equal_approx(Vector3(0, 0, 0), path_follow_3d->get_transform().get_origin()));
  57. path_follow_3d->set_progress_ratio(0.125);
  58. CHECK(is_equal_approx(Vector3(50, 0, 0), path_follow_3d->get_transform().get_origin()));
  59. path_follow_3d->set_progress_ratio(0.25);
  60. CHECK(is_equal_approx(Vector3(100, 0, 0), path_follow_3d->get_transform().get_origin()));
  61. path_follow_3d->set_progress_ratio(0.375);
  62. CHECK(is_equal_approx(Vector3(100, 50, 0), path_follow_3d->get_transform().get_origin()));
  63. path_follow_3d->set_progress_ratio(0.5);
  64. CHECK(is_equal_approx(Vector3(100, 100, 0), path_follow_3d->get_transform().get_origin()));
  65. path_follow_3d->set_progress_ratio(0.625);
  66. CHECK(is_equal_approx(Vector3(100, 100, 50), path_follow_3d->get_transform().get_origin()));
  67. path_follow_3d->set_progress_ratio(0.75);
  68. CHECK(is_equal_approx(Vector3(100, 100, 100), path_follow_3d->get_transform().get_origin()));
  69. path_follow_3d->set_progress_ratio(0.875);
  70. CHECK(is_equal_approx(Vector3(100, 50, 100), path_follow_3d->get_transform().get_origin()));
  71. path_follow_3d->set_progress_ratio(1);
  72. CHECK(is_equal_approx(Vector3(100, 0, 100), path_follow_3d->get_transform().get_origin()));
  73. memdelete(path);
  74. }
  75. TEST_CASE("[SceneTree][PathFollow3D] Sampling with progress") {
  76. Ref<Curve3D> curve = memnew(Curve3D);
  77. curve->add_point(Vector3(0, 0, 0));
  78. curve->add_point(Vector3(100, 0, 0));
  79. curve->add_point(Vector3(100, 100, 0));
  80. curve->add_point(Vector3(100, 100, 100));
  81. curve->add_point(Vector3(100, 0, 100));
  82. Path3D *path = memnew(Path3D);
  83. path->set_curve(curve);
  84. PathFollow3D *path_follow_3d = memnew(PathFollow3D);
  85. path_follow_3d->set_loop(false);
  86. path->add_child(path_follow_3d);
  87. SceneTree::get_singleton()->get_root()->add_child(path);
  88. path_follow_3d->set_progress(0);
  89. CHECK(is_equal_approx(Vector3(0, 0, 0), path_follow_3d->get_transform().get_origin()));
  90. path_follow_3d->set_progress(50);
  91. CHECK(is_equal_approx(Vector3(50, 0, 0), path_follow_3d->get_transform().get_origin()));
  92. path_follow_3d->set_progress(100);
  93. CHECK(is_equal_approx(Vector3(100, 0, 0), path_follow_3d->get_transform().get_origin()));
  94. path_follow_3d->set_progress(150);
  95. CHECK(is_equal_approx(Vector3(100, 50, 0), path_follow_3d->get_transform().get_origin()));
  96. path_follow_3d->set_progress(200);
  97. CHECK(is_equal_approx(Vector3(100, 100, 0), path_follow_3d->get_transform().get_origin()));
  98. path_follow_3d->set_progress(250);
  99. CHECK(is_equal_approx(Vector3(100, 100, 50), path_follow_3d->get_transform().get_origin()));
  100. path_follow_3d->set_progress(300);
  101. CHECK(is_equal_approx(Vector3(100, 100, 100), path_follow_3d->get_transform().get_origin()));
  102. path_follow_3d->set_progress(350);
  103. CHECK(is_equal_approx(Vector3(100, 50, 100), path_follow_3d->get_transform().get_origin()));
  104. path_follow_3d->set_progress(400);
  105. CHECK(is_equal_approx(Vector3(100, 0, 100), path_follow_3d->get_transform().get_origin()));
  106. memdelete(path);
  107. }
  108. TEST_CASE("[SceneTree][PathFollow3D] Removal of a point in curve") {
  109. Ref<Curve3D> curve = memnew(Curve3D);
  110. curve->add_point(Vector3(0, 0, 0));
  111. curve->add_point(Vector3(100, 0, 0));
  112. curve->add_point(Vector3(100, 100, 0));
  113. Path3D *path = memnew(Path3D);
  114. path->set_curve(curve);
  115. PathFollow3D *path_follow_3d = memnew(PathFollow3D);
  116. path->add_child(path_follow_3d);
  117. SceneTree::get_singleton()->get_root()->add_child(path);
  118. path_follow_3d->set_progress_ratio(0.5);
  119. CHECK(is_equal_approx(Vector3(100, 0, 0), path_follow_3d->get_transform().get_origin()));
  120. curve->remove_point(1);
  121. path_follow_3d->set_progress_ratio(0.5);
  122. CHECK_MESSAGE(
  123. is_equal_approx(Vector3(50, 50, 0), path_follow_3d->get_transform().get_origin()),
  124. "Path follow's position should be updated after removing a point from the curve");
  125. memdelete(path);
  126. }
  127. TEST_CASE("[SceneTree][PathFollow3D] Progress ratio out of range") {
  128. Ref<Curve3D> curve = memnew(Curve3D);
  129. curve->add_point(Vector3(0, 0, 0));
  130. curve->add_point(Vector3(100, 0, 0));
  131. Path3D *path = memnew(Path3D);
  132. path->set_curve(curve);
  133. PathFollow3D *path_follow_3d = memnew(PathFollow3D);
  134. path->add_child(path_follow_3d);
  135. SceneTree::get_singleton()->get_root()->add_child(path);
  136. path_follow_3d->set_loop(true);
  137. path_follow_3d->set_progress_ratio(-0.3);
  138. CHECK_MESSAGE(
  139. Math::is_equal_approx(path_follow_3d->get_progress_ratio(), (real_t)0.7),
  140. "Progress Ratio should loop back from the end in the opposite direction");
  141. path_follow_3d->set_progress_ratio(1.3);
  142. CHECK_MESSAGE(
  143. Math::is_equal_approx(path_follow_3d->get_progress_ratio(), (real_t)0.3),
  144. "Progress Ratio should loop back from the end in the opposite direction");
  145. path_follow_3d->set_loop(false);
  146. path_follow_3d->set_progress_ratio(-0.3);
  147. CHECK_MESSAGE(
  148. Math::is_equal_approx(path_follow_3d->get_progress_ratio(), 0),
  149. "Progress Ratio should be clamped at 0");
  150. path_follow_3d->set_progress_ratio(1.3);
  151. CHECK_MESSAGE(
  152. Math::is_equal_approx(path_follow_3d->get_progress_ratio(), 1),
  153. "Progress Ratio should be clamped at 1");
  154. memdelete(path);
  155. }
  156. TEST_CASE("[SceneTree][PathFollow3D] Progress out of range") {
  157. Ref<Curve3D> curve = memnew(Curve3D);
  158. curve->add_point(Vector3(0, 0, 0));
  159. curve->add_point(Vector3(100, 0, 0));
  160. Path3D *path = memnew(Path3D);
  161. path->set_curve(curve);
  162. PathFollow3D *path_follow_3d = memnew(PathFollow3D);
  163. path->add_child(path_follow_3d);
  164. SceneTree::get_singleton()->get_root()->add_child(path);
  165. path_follow_3d->set_loop(true);
  166. path_follow_3d->set_progress(-50);
  167. CHECK_MESSAGE(
  168. Math::is_equal_approx(path_follow_3d->get_progress(), 50),
  169. "Progress should loop back from the end in the opposite direction");
  170. path_follow_3d->set_progress(150);
  171. CHECK_MESSAGE(
  172. Math::is_equal_approx(path_follow_3d->get_progress(), 50),
  173. "Progress should loop back from the end in the opposite direction");
  174. path_follow_3d->set_loop(false);
  175. path_follow_3d->set_progress(-50);
  176. CHECK_MESSAGE(
  177. Math::is_equal_approx(path_follow_3d->get_progress(), 0),
  178. "Progress should be clamped at 0");
  179. path_follow_3d->set_progress(150);
  180. CHECK_MESSAGE(
  181. Math::is_equal_approx(path_follow_3d->get_progress(), 100),
  182. "Progress should be clamped at max value of curve");
  183. memdelete(path);
  184. }
  185. TEST_CASE("[SceneTree][PathFollow3D] Calculate forward vector") {
  186. const real_t dist_cube_100 = 100 * Math::sqrt(3.0);
  187. Ref<Curve3D> curve = memnew(Curve3D);
  188. curve->add_point(Vector3(0, 0, 0));
  189. curve->add_point(Vector3(100, 0, 0));
  190. curve->add_point(Vector3(200, 100, -100));
  191. curve->add_point(Vector3(200, 100, 200));
  192. curve->add_point(Vector3(100, 0, 100));
  193. curve->add_point(Vector3(0, 0, 100));
  194. Path3D *path = memnew(Path3D);
  195. path->set_curve(curve);
  196. PathFollow3D *path_follow_3d = memnew(PathFollow3D);
  197. path->add_child(path_follow_3d);
  198. SceneTree::get_singleton()->get_root()->add_child(path);
  199. path_follow_3d->set_loop(false);
  200. path_follow_3d->set_rotation_mode(PathFollow3D::RotationMode::ROTATION_ORIENTED);
  201. path_follow_3d->set_progress(-50);
  202. CHECK(is_equal_approx(Vector3(-1, 0, 0), path_follow_3d->get_transform().get_basis().get_column(2)));
  203. path_follow_3d->set_progress(0);
  204. CHECK(is_equal_approx(Vector3(-1, 0, 0), path_follow_3d->get_transform().get_basis().get_column(2)));
  205. path_follow_3d->set_progress(50);
  206. CHECK(is_equal_approx(Vector3(-1, 0, 0), path_follow_3d->get_transform().get_basis().get_column(2)));
  207. path_follow_3d->set_progress(100);
  208. CHECK(is_equal_approx(Vector3(-1, 0, 0), path_follow_3d->get_transform().get_basis().get_column(2)));
  209. path_follow_3d->set_progress(100 + dist_cube_100 / 2);
  210. CHECK(is_equal_approx(Vector3(-0.577348, -0.577348, 0.577348), path_follow_3d->get_transform().get_basis().get_column(2)));
  211. path_follow_3d->set_progress(100 + dist_cube_100 - 0.01);
  212. CHECK(is_equal_approx(Vector3(-0.577348, -0.577348, 0.577348), path_follow_3d->get_transform().get_basis().get_column(2)));
  213. path_follow_3d->set_progress(250 + dist_cube_100);
  214. CHECK(is_equal_approx(Vector3(0, 0, -1), path_follow_3d->get_transform().get_basis().get_column(2)));
  215. path_follow_3d->set_progress(400 + dist_cube_100 - 0.01);
  216. CHECK(is_equal_approx(Vector3(0, 0, -1), path_follow_3d->get_transform().get_basis().get_column(2)));
  217. path_follow_3d->set_progress(400 + 1.5 * dist_cube_100);
  218. CHECK(is_equal_approx(Vector3(0.577348, 0.577348, 0.577348), path_follow_3d->get_transform().get_basis().get_column(2)));
  219. path_follow_3d->set_progress(400 + 2 * dist_cube_100 - 0.01);
  220. CHECK(is_equal_approx(Vector3(0.577348, 0.577348, 0.577348), path_follow_3d->get_transform().get_basis().get_column(2)));
  221. path_follow_3d->set_progress(500 + 2 * dist_cube_100);
  222. CHECK(is_equal_approx(Vector3(1, 0, 0), path_follow_3d->get_transform().get_basis().get_column(2)));
  223. memdelete(path);
  224. }
  225. } // namespace TestPathFollow3D
  226. #endif // TEST_PATH_FOLLOW_3D_H