Path: blob/master/tests/scene/test_path_follow_3d.cpp
45993 views
/**************************************************************************/1/* test_path_follow_3d.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "tests/test_macros.h"3132TEST_FORCE_LINK(test_path_follow_3d)3334#ifndef _3D_DISABLED3536#include "scene/3d/path_3d.h"37#include "scene/main/scene_tree.h"38#include "scene/main/window.h"3940namespace TestPathFollow3D {4142bool is_equal_approx(const Vector3 &p_a, const Vector3 &p_b) {43const real_t tolerance = 0.001;44return Math::is_equal_approx(p_a.x, p_b.x, tolerance) &&45Math::is_equal_approx(p_a.y, p_b.y, tolerance) &&46Math::is_equal_approx(p_a.z, p_b.z, tolerance);47}4849TEST_CASE("[SceneTree][PathFollow3D] Sampling with progress ratio") {50Ref<Curve3D> curve;51curve.instantiate();52curve->add_point(Vector3(0, 0, 0));53curve->add_point(Vector3(100, 0, 0));54curve->add_point(Vector3(100, 100, 0));55curve->add_point(Vector3(100, 100, 100));56curve->add_point(Vector3(100, 0, 100));57Path3D *path = memnew(Path3D);58path->set_curve(curve);59PathFollow3D *path_follow_3d = memnew(PathFollow3D);60path_follow_3d->set_loop(false);61path->add_child(path_follow_3d);62SceneTree::get_singleton()->get_root()->add_child(path);6364path_follow_3d->set_progress_ratio(0);65CHECK(is_equal_approx(Vector3(0, 0, 0), path_follow_3d->get_transform().get_origin()));6667path_follow_3d->set_progress_ratio(0.125);68CHECK(is_equal_approx(Vector3(50, 0, 0), path_follow_3d->get_transform().get_origin()));6970path_follow_3d->set_progress_ratio(0.25);71CHECK(is_equal_approx(Vector3(100, 0, 0), path_follow_3d->get_transform().get_origin()));7273path_follow_3d->set_progress_ratio(0.375);74CHECK(is_equal_approx(Vector3(100, 50, 0), path_follow_3d->get_transform().get_origin()));7576path_follow_3d->set_progress_ratio(0.5);77CHECK(is_equal_approx(Vector3(100, 100, 0), path_follow_3d->get_transform().get_origin()));7879path_follow_3d->set_progress_ratio(0.625);80CHECK(is_equal_approx(Vector3(100, 100, 50), path_follow_3d->get_transform().get_origin()));8182path_follow_3d->set_progress_ratio(0.75);83CHECK(is_equal_approx(Vector3(100, 100, 100), path_follow_3d->get_transform().get_origin()));8485path_follow_3d->set_progress_ratio(0.875);86CHECK(is_equal_approx(Vector3(100, 50, 100), path_follow_3d->get_transform().get_origin()));8788path_follow_3d->set_progress_ratio(1);89CHECK(is_equal_approx(Vector3(100, 0, 100), path_follow_3d->get_transform().get_origin()));9091memdelete(path);92}9394TEST_CASE("[SceneTree][PathFollow3D] Sampling with progress") {95Ref<Curve3D> curve;96curve.instantiate();97curve->add_point(Vector3(0, 0, 0));98curve->add_point(Vector3(100, 0, 0));99curve->add_point(Vector3(100, 100, 0));100curve->add_point(Vector3(100, 100, 100));101curve->add_point(Vector3(100, 0, 100));102Path3D *path = memnew(Path3D);103path->set_curve(curve);104PathFollow3D *path_follow_3d = memnew(PathFollow3D);105path_follow_3d->set_loop(false);106path->add_child(path_follow_3d);107SceneTree::get_singleton()->get_root()->add_child(path);108109path_follow_3d->set_progress(0);110CHECK(is_equal_approx(Vector3(0, 0, 0), path_follow_3d->get_transform().get_origin()));111112path_follow_3d->set_progress(50);113CHECK(is_equal_approx(Vector3(50, 0, 0), path_follow_3d->get_transform().get_origin()));114115path_follow_3d->set_progress(100);116CHECK(is_equal_approx(Vector3(100, 0, 0), path_follow_3d->get_transform().get_origin()));117118path_follow_3d->set_progress(150);119CHECK(is_equal_approx(Vector3(100, 50, 0), path_follow_3d->get_transform().get_origin()));120121path_follow_3d->set_progress(200);122CHECK(is_equal_approx(Vector3(100, 100, 0), path_follow_3d->get_transform().get_origin()));123124path_follow_3d->set_progress(250);125CHECK(is_equal_approx(Vector3(100, 100, 50), path_follow_3d->get_transform().get_origin()));126127path_follow_3d->set_progress(300);128CHECK(is_equal_approx(Vector3(100, 100, 100), path_follow_3d->get_transform().get_origin()));129130path_follow_3d->set_progress(350);131CHECK(is_equal_approx(Vector3(100, 50, 100), path_follow_3d->get_transform().get_origin()));132133path_follow_3d->set_progress(400);134CHECK(is_equal_approx(Vector3(100, 0, 100), path_follow_3d->get_transform().get_origin()));135136memdelete(path);137}138139TEST_CASE("[SceneTree][PathFollow3D] Removal of a point in curve") {140Ref<Curve3D> curve;141curve.instantiate();142curve->add_point(Vector3(0, 0, 0));143curve->add_point(Vector3(100, 0, 0));144curve->add_point(Vector3(100, 100, 0));145Path3D *path = memnew(Path3D);146path->set_curve(curve);147PathFollow3D *path_follow_3d = memnew(PathFollow3D);148path->add_child(path_follow_3d);149SceneTree::get_singleton()->get_root()->add_child(path);150151path_follow_3d->set_progress_ratio(0.5);152CHECK(is_equal_approx(Vector3(100, 0, 0), path_follow_3d->get_transform().get_origin()));153154curve->remove_point(1);155156path_follow_3d->set_progress_ratio(0.5);157CHECK_MESSAGE(158is_equal_approx(Vector3(50, 50, 0), path_follow_3d->get_transform().get_origin()),159"Path follow's position should be updated after removing a point from the curve");160161memdelete(path);162}163164TEST_CASE("[SceneTree][PathFollow3D] Progress ratio out of range") {165Ref<Curve3D> curve;166curve.instantiate();167curve->add_point(Vector3(0, 0, 0));168curve->add_point(Vector3(100, 0, 0));169Path3D *path = memnew(Path3D);170path->set_curve(curve);171PathFollow3D *path_follow_3d = memnew(PathFollow3D);172path->add_child(path_follow_3d);173SceneTree::get_singleton()->get_root()->add_child(path);174175path_follow_3d->set_loop(true);176177path_follow_3d->set_progress_ratio(-0.3);178CHECK_MESSAGE(179Math::is_equal_approx(path_follow_3d->get_progress_ratio(), (real_t)0.7),180"Progress Ratio should loop back from the end in the opposite direction");181182path_follow_3d->set_progress_ratio(1.3);183CHECK_MESSAGE(184Math::is_equal_approx(path_follow_3d->get_progress_ratio(), (real_t)0.3),185"Progress Ratio should loop back from the end in the opposite direction");186187path_follow_3d->set_loop(false);188189path_follow_3d->set_progress_ratio(-0.3);190CHECK_MESSAGE(191Math::is_equal_approx(path_follow_3d->get_progress_ratio(), 0),192"Progress Ratio should be clamped at 0");193194path_follow_3d->set_progress_ratio(1.3);195CHECK_MESSAGE(196Math::is_equal_approx(path_follow_3d->get_progress_ratio(), 1),197"Progress Ratio should be clamped at 1");198199memdelete(path);200}201202TEST_CASE("[SceneTree][PathFollow3D] Progress out of range") {203Ref<Curve3D> curve;204curve.instantiate();205curve->add_point(Vector3(0, 0, 0));206curve->add_point(Vector3(100, 0, 0));207Path3D *path = memnew(Path3D);208path->set_curve(curve);209PathFollow3D *path_follow_3d = memnew(PathFollow3D);210path->add_child(path_follow_3d);211SceneTree::get_singleton()->get_root()->add_child(path);212213path_follow_3d->set_loop(true);214215path_follow_3d->set_progress(-50);216CHECK_MESSAGE(217Math::is_equal_approx(path_follow_3d->get_progress(), 50),218"Progress should loop back from the end in the opposite direction");219220path_follow_3d->set_progress(150);221CHECK_MESSAGE(222Math::is_equal_approx(path_follow_3d->get_progress(), 50),223"Progress should loop back from the end in the opposite direction");224225path_follow_3d->set_loop(false);226227path_follow_3d->set_progress(-50);228CHECK_MESSAGE(229Math::is_equal_approx(path_follow_3d->get_progress(), 0),230"Progress should be clamped at 0");231232path_follow_3d->set_progress(150);233CHECK_MESSAGE(234Math::is_equal_approx(path_follow_3d->get_progress(), 100),235"Progress should be clamped at max value of curve");236237memdelete(path);238}239240TEST_CASE("[SceneTree][PathFollow3D] Calculate forward vector") {241const real_t dist_cube_100 = 100 * Math::sqrt(3.0);242Ref<Curve3D> curve;243curve.instantiate();244curve->add_point(Vector3(0, 0, 0));245curve->add_point(Vector3(100, 0, 0));246curve->add_point(Vector3(200, 100, -100));247curve->add_point(Vector3(200, 100, 200));248curve->add_point(Vector3(100, 0, 100));249curve->add_point(Vector3(0, 0, 100));250Path3D *path = memnew(Path3D);251path->set_curve(curve);252PathFollow3D *path_follow_3d = memnew(PathFollow3D);253path->add_child(path_follow_3d);254SceneTree::get_singleton()->get_root()->add_child(path);255256path_follow_3d->set_loop(false);257path_follow_3d->set_rotation_mode(PathFollow3D::RotationMode::ROTATION_ORIENTED);258259path_follow_3d->set_progress(-50);260CHECK(is_equal_approx(Vector3(-1, 0, 0), path_follow_3d->get_transform().get_basis().get_column(2)));261262path_follow_3d->set_progress(0);263CHECK(is_equal_approx(Vector3(-1, 0, 0), path_follow_3d->get_transform().get_basis().get_column(2)));264265path_follow_3d->set_progress(50);266CHECK(is_equal_approx(Vector3(-1, 0, 0), path_follow_3d->get_transform().get_basis().get_column(2)));267268path_follow_3d->set_progress(100);269CHECK(is_equal_approx(Vector3(-1, 0, 0), path_follow_3d->get_transform().get_basis().get_column(2)));270271path_follow_3d->set_progress(100 + dist_cube_100 / 2);272CHECK(is_equal_approx(Vector3(-0.577348, -0.577348, 0.577348), path_follow_3d->get_transform().get_basis().get_column(2)));273274path_follow_3d->set_progress(100 + dist_cube_100 - 0.01);275CHECK(is_equal_approx(Vector3(-0.577348, -0.577348, 0.577348), path_follow_3d->get_transform().get_basis().get_column(2)));276277path_follow_3d->set_progress(250 + dist_cube_100);278CHECK(is_equal_approx(Vector3(0, 0, -1), path_follow_3d->get_transform().get_basis().get_column(2)));279280path_follow_3d->set_progress(400 + dist_cube_100 - 0.01);281CHECK(is_equal_approx(Vector3(0, 0, -1), path_follow_3d->get_transform().get_basis().get_column(2)));282283path_follow_3d->set_progress(400 + 1.5 * dist_cube_100);284CHECK(is_equal_approx(Vector3(0.577348, 0.577348, 0.577348), path_follow_3d->get_transform().get_basis().get_column(2)));285286path_follow_3d->set_progress(400 + 2 * dist_cube_100 - 0.01);287CHECK(is_equal_approx(Vector3(0.577348, 0.577348, 0.577348), path_follow_3d->get_transform().get_basis().get_column(2)));288289path_follow_3d->set_progress(500 + 2 * dist_cube_100);290CHECK(is_equal_approx(Vector3(1, 0, 0), path_follow_3d->get_transform().get_basis().get_column(2)));291292memdelete(path);293}294295TEST_CASE("[SceneTree][PathFollow3D] Calculate forward vector with degenerate curves") {296Ref<Curve3D> curve;297curve.instantiate();298curve->add_point(Vector3(0, 0, 1), Vector3(), Vector3(1, 0, 0));299curve->add_point(Vector3(1, 0, 0), Vector3(0, 0, 0), Vector3(0, 0, 0));300curve->add_point(Vector3(0, 0, -1), Vector3(1, 0, 0), Vector3(-1, 0, 0));301curve->add_point(Vector3(-1, 0, 0), Vector3(0, 0, 0), Vector3(0, 0, 0));302curve->add_point(Vector3(0, 0, 1), Vector3(-1, 0, 0), Vector3());303Path3D *path = memnew(Path3D);304path->set_curve(curve);305PathFollow3D *path_follow_3d = memnew(PathFollow3D);306path->add_child(path_follow_3d);307SceneTree::get_singleton()->get_root()->add_child(path);308309path_follow_3d->set_loop(false);310path_follow_3d->set_rotation_mode(PathFollow3D::RotationMode::ROTATION_ORIENTED);311312path_follow_3d->set_progress_ratio(0.00);313CHECK(is_equal_approx(Vector3(-1, 0, 0), path_follow_3d->get_transform().get_basis().get_column(2)));314315path_follow_3d->set_progress_ratio(0.25);316CHECK(is_equal_approx(Vector3(0, 0, 1), path_follow_3d->get_transform().get_basis().get_column(2)));317318path_follow_3d->set_progress_ratio(0.50);319CHECK(is_equal_approx(Vector3(1, 0, 0), path_follow_3d->get_transform().get_basis().get_column(2)));320321path_follow_3d->set_progress_ratio(0.75);322CHECK(is_equal_approx(Vector3(0, 0, -1), path_follow_3d->get_transform().get_basis().get_column(2)));323324path_follow_3d->set_progress_ratio(1.00);325CHECK(is_equal_approx(Vector3(-1, 0, 0), path_follow_3d->get_transform().get_basis().get_column(2)));326327path_follow_3d->set_progress_ratio(0.125);328CHECK(is_equal_approx(Vector3(-0.688375, 0, 0.725355), path_follow_3d->get_transform().get_basis().get_column(2)));329330path_follow_3d->set_progress_ratio(0.375);331CHECK(is_equal_approx(Vector3(0.688375, 0, 0.725355), path_follow_3d->get_transform().get_basis().get_column(2)));332333path_follow_3d->set_progress_ratio(0.625);334CHECK(is_equal_approx(Vector3(0.688375, 0, -0.725355), path_follow_3d->get_transform().get_basis().get_column(2)));335336path_follow_3d->set_progress_ratio(0.875);337CHECK(is_equal_approx(Vector3(-0.688375, 0, -0.725355), path_follow_3d->get_transform().get_basis().get_column(2)));338339memdelete(path);340}341342} // namespace TestPathFollow3D343344#endif // _3D_DISABLED345346347