Skip to content

Commit

Permalink
Add move_toward_smooth helper
Browse files Browse the repository at this point in the history
  • Loading branch information
ubitux committed Oct 7, 2024
1 parent 007f3f8 commit 8f8fb4f
Show file tree
Hide file tree
Showing 17 changed files with 120 additions and 0 deletions.
7 changes: 7 additions & 0 deletions core/math/math_funcs.h
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,13 @@ class Math {
return abs(p_to - p_from) <= p_delta ? p_to : p_from + SIGN(p_to - p_from) * p_delta;
}

static _ALWAYS_INLINE_ double move_toward_smooth(double p_from, double p_to, double p_delta) {
return Math::lerp(p_from, p_to, -Math::expm1(-p_delta));
}
static _ALWAYS_INLINE_ float move_toward_smooth(float p_from, float p_to, float p_delta) {
return Math::lerp(p_from, p_to, -Math::expm1(-p_delta));
}

static _ALWAYS_INLINE_ double rotate_toward(double p_from, double p_to, double p_delta) {
double difference = Math::angle_difference(p_from, p_to);
double abs_difference = Math::abs(difference);
Expand Down
4 changes: 4 additions & 0 deletions core/math/vector2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,10 @@ Vector2 Vector2::move_toward(const Vector2 &p_to, real_t p_delta) const {
return len <= p_delta || len < (real_t)CMP_EPSILON ? p_to : v + vd / len * p_delta;
}

Vector2 Vector2::move_toward_smooth(const Vector2 &p_to, real_t p_delta) const {
return lerp(p_to, -Math::expm1(-p_delta));
}

// slide returns the component of the vector along the given plane, specified by its normal vector.
Vector2 Vector2::slide(const Vector2 &p_normal) const {
#ifdef MATH_CHECKS
Expand Down
1 change: 1 addition & 0 deletions core/math/vector2.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ struct [[nodiscard]] Vector2 {
_FORCE_INLINE_ Vector2 bezier_derivative(const Vector2 &p_control_1, const Vector2 &p_control_2, const Vector2 &p_end, real_t p_t) const;

Vector2 move_toward(const Vector2 &p_to, real_t p_delta) const;
Vector2 move_toward_smooth(const Vector2 &p_to, real_t p_delta) const;

Vector2 slide(const Vector2 &p_normal) const;
Vector2 bounce(const Vector2 &p_normal) const;
Expand Down
4 changes: 4 additions & 0 deletions core/math/vector3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ Vector3 Vector3::move_toward(const Vector3 &p_to, real_t p_delta) const {
return len <= p_delta || len < (real_t)CMP_EPSILON ? p_to : v + vd / len * p_delta;
}

Vector3 Vector3::move_toward_smooth(const Vector3 &p_to, real_t p_delta) const {
return lerp(p_to, -Math::expm1(-p_delta));
}

Vector2 Vector3::octahedron_encode() const {
Vector3 n = *this;
n /= Math::abs(n.x) + Math::abs(n.y) + Math::abs(n.z);
Expand Down
1 change: 1 addition & 0 deletions core/math/vector3.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ struct [[nodiscard]] Vector3 {
_FORCE_INLINE_ Vector3 bezier_derivative(const Vector3 &p_control_1, const Vector3 &p_control_2, const Vector3 &p_end, real_t p_t) const;

Vector3 move_toward(const Vector3 &p_to, real_t p_delta) const;
Vector3 move_toward_smooth(const Vector3 &p_to, real_t p_delta) const;

Vector2 octahedron_encode() const;
static Vector3 octahedron_decode(const Vector2 &p_oct);
Expand Down
2 changes: 2 additions & 0 deletions core/variant/variant_call.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1810,6 +1810,7 @@ static void _register_variant_builtin_methods_math() {
bind_method(Vector2, max_axis_index, sarray(), varray());
bind_method(Vector2, min_axis_index, sarray(), varray());
bind_method(Vector2, move_toward, sarray("to", "delta"), varray());
bind_method(Vector2, move_toward_smooth, sarray("to", "delta"), varray());
bind_method(Vector2, rotated, sarray("angle"), varray());
bind_method(Vector2, orthogonal, sarray(), varray());
bind_method(Vector2, floor, sarray(), varray());
Expand Down Expand Up @@ -1919,6 +1920,7 @@ static void _register_variant_builtin_methods_math() {
bind_method(Vector3, bezier_interpolate, sarray("control_1", "control_2", "end", "t"), varray());
bind_method(Vector3, bezier_derivative, sarray("control_1", "control_2", "end", "t"), varray());
bind_method(Vector3, move_toward, sarray("to", "delta"), varray());
bind_method(Vector3, move_toward_smooth, sarray("to", "delta"), varray());
bind_method(Vector3, dot, sarray("with"), varray());
bind_method(Vector3, cross, sarray("with"), varray());
bind_method(Vector3, outer, sarray("with"), varray());
Expand Down
5 changes: 5 additions & 0 deletions core/variant/variant_utility.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,10 @@ double VariantUtilityFunctions::move_toward(double from, double to, double delta
return Math::move_toward(from, to, delta);
}

double VariantUtilityFunctions::move_toward_smooth(double from, double to, double delta) {
return Math::move_toward_smooth(from, to, delta);
}

double VariantUtilityFunctions::rotate_toward(double from, double to, double delta) {
return Math::rotate_toward(from, to, delta);
}
Expand Down Expand Up @@ -1761,6 +1765,7 @@ void Variant::_register_variant_utility_functions() {

FUNCBINDR(smoothstep, sarray("from", "to", "x"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(move_toward, sarray("from", "to", "delta"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(move_toward_smooth, sarray("from", "to", "delta"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(rotate_toward, sarray("from", "to", "delta"), Variant::UTILITY_FUNC_TYPE_MATH);

FUNCBINDR(deg_to_rad, sarray("deg"), Variant::UTILITY_FUNC_TYPE_MATH);
Expand Down
1 change: 1 addition & 0 deletions core/variant/variant_utility.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ struct VariantUtilityFunctions {
static double remap(double value, double istart, double istop, double ostart, double ostop);
static double smoothstep(double from, double to, double val);
static double move_toward(double from, double to, double delta);
static double move_toward_smooth(double from, double to, double delta);
static double rotate_toward(double from, double to, double delta);
static double deg_to_rad(double angle_deg);
static double rad_to_deg(double angle_rad);
Expand Down
16 changes: 16 additions & 0 deletions doc/classes/@GlobalScope.xml
Original file line number Diff line number Diff line change
Expand Up @@ -770,6 +770,22 @@
[/codeblock]
</description>
</method>
<method name="move_toward_smooth">
<return type="float" />
<param index="0" name="from" type="float" />
<param index="1" name="to" type="float" />
<param index="2" name="delta" type="float" />
<description>
Moves [param from] toward [param to] smoothly (fast to slow) by the [param delta] amount. The function is defined as [code]lerp(from, to, 1 - exp(-delta))[/code]. Note that due to the nature of the exponential function, the return value will quickly get close to the target [param to] but may never reach it. It is recommended to rely on [method is_equal_approx] to test whether the target is reached.
[codeblock]
move_toward_smooth(1.0, 120.0, 0.7) # Returns 60.9
move_toward_smooth(60.9, 120.0, 0.7) # Returns 90.7
move_toward_smooth(90.7, 120.0, 0.7) # Returns 105.4
move_toward_smooth(105.4, 120.0, 0.7) # Returns 112.8
move_toward_smooth(112.8, 120.0, 0.7) # Returns 116.4
[/codeblock]
</description>
</method>
<method name="nearest_po2">
<return type="int" />
<param index="0" name="value" type="int" />
Expand Down
8 changes: 8 additions & 0 deletions doc/classes/Vector2.xml
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,14 @@
Returns a new vector moved toward [param to] by the fixed [param delta] amount. Will not go past the final value.
</description>
</method>
<method name="move_toward_smooth" qualifiers="const">
<return type="Vector2" />
<param index="0" name="to" type="Vector2" />
<param index="1" name="delta" type="float" />
<description>
Moves toward [param to] smoothly (fast to slow) by the [param delta] amount. The function is defined as [code]lerp(to, 1 - exp(-delta))[/code]. Note that due to the nature of the exponential function, the return value will quickly get close to the target [param to] but may never reach it. It is recommended to rely on [method is_equal_approx] to test whether the target is reached.
</description>
</method>
<method name="normalized" qualifiers="const">
<return type="Vector2" />
<description>
Expand Down
8 changes: 8 additions & 0 deletions doc/classes/Vector3.xml
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,14 @@
Returns a new vector moved toward [param to] by the fixed [param delta] amount. Will not go past the final value.
</description>
</method>
<method name="move_toward_smooth" qualifiers="const">
<return type="Vector3" />
<param index="0" name="to" type="Vector3" />
<param index="1" name="delta" type="float" />
<description>
Moves toward [param to] smoothly (fast to slow) by the [param delta] amount. The function is defined as [code]lerp(to, 1 - exp(-delta))[/code]. Note that due to the nature of the exponential function, the return value will quickly get close to the target [param to] but may never reach it. It is recommended to rely on [method is_equal_approx] to test whether the target is reached.
</description>
</method>
<method name="normalized" qualifiers="const">
<return type="Vector3" />
<description>
Expand Down
27 changes: 27 additions & 0 deletions modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1298,6 +1298,19 @@ public static float MoveToward(float from, float to, float delta)
return from + (Math.Sign(to - from) * delta);
}

/// <summary>
/// Moves <paramref name="from"/> toward <paramref name="to"/> smoothly (fast to slow) by the <paramref name="delta"/> amount. The function is defined as <code>lerp(from, to, 1 - exp(-delta))</code>.
/// Note that due to the nature of the exponential function, the return value will quickly get close to the target <paramref name="delta"/> but may never reach it. It is recommended to rely on <see cref="IsEqualApprox(float, float)"/> to test whether the target is reached.
/// </summary>
/// <param name="from">The start value.</param>
/// <param name="to">The value to move towards.</param>
/// <param name="delta">The amount to move by.</param>
/// <returns>The value after moving smoothly.</returns>
public static float MoveTowardSmooth(float from, float to, float delta)
{
return Lerp(from, to, -ExpM1(-delta));
}

/// <summary>
/// Moves <paramref name="from"/> toward <paramref name="to"/> by the <paramref name="delta"/> value.
///
Expand All @@ -1315,6 +1328,20 @@ public static double MoveToward(double from, double to, double delta)
return from + (Math.Sign(to - from) * delta);
}

/// <summary>
/// Moves <paramref name="from"/> toward <paramref name="to"/> smoothly (fast to slow) by the <paramref name="delta"/> amount. The function is defined as <code>lerp(from, to, 1 - exp(-delta))</code>.
/// Note that due to the nature of the exponential function, the return value will quickly get close to the target <paramref name="delta"/> but may never reach it. It is recommended to rely on <see cref="IsEqualApprox(double, double)"/> to test whether the target is reached.
/// </summary>
/// <param name="from">The start value.</param>
/// <param name="to">The value to move towards.</param>
/// <param name="delta">The amount to move by.</param>
/// <returns>The value after moving smoothly.</returns>
public static double MoveTowardSmooth(double from, double to, double delta)
{
return Lerp(from, to, -ExpM1(-delta));
}


/// <summary>
/// Returns the nearest larger power of 2 for the integer <paramref name="value"/>.
/// </summary>
Expand Down
12 changes: 12 additions & 0 deletions modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,18 @@ public readonly Vector2 MoveToward(Vector2 to, real_t delta)
return v + (vd / len * delta);
}

/// <summary>
/// Moves this vector toward <paramref name="to"/> smoothly (fast to slow) by the <paramref name="delta"/> amount. The function is defined as <code>lerp(this, to, 1 - exp(-delta))</code>.
/// Note that due to the nature of the exponential function, the return value will quickly get close to the target <paramref name="delta"/> but may never reach it. It is recommended to rely on <see cref="IsEqualApprox()"/> to test whether the target is reached.
/// </summary>
/// <param name="to">The vector to move towards.</param>
/// <param name="delta">The amount to move towards by.</param>
/// <returns>The resulting vector.</returns>
public readonly Vector2 MoveTowardSmooth(Vector2 to, real_t delta)
{
return Lerp(to, -Mathf.ExpM1(-delta));
}

/// <summary>
/// Returns the vector scaled to unit length. Equivalent to <c>v / v.Length()</c>.
/// </summary>
Expand Down
12 changes: 12 additions & 0 deletions modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,18 @@ public readonly Vector3 MoveToward(Vector3 to, real_t delta)
return v + (vd / len * delta);
}

/// <summary>
/// Moves this vector toward <paramref name="to"/> smoothly (fast to slow) by the <paramref name="delta"/> amount. The function is defined as <code>lerp(this, to, 1 - exp(-delta))</code>.
/// Note that due to the nature of the exponential function, the return value will quickly get close to the target <paramref name="delta"/> but may never reach it. It is recommended to rely on <see cref="IsEqualApprox()"/> to test whether the target is reached.
/// </summary>
/// <param name="to">The vector to move towards.</param>
/// <param name="delta">The amount to move towards by.</param>
/// <returns>The resulting vector.</returns>
public readonly Vector3 MoveTowardSmooth(Vector3 to, real_t delta)
{
return Lerp(to, -Mathf.ExpM1(-delta));
}

/// <summary>
/// Returns the vector scaled to unit length. Equivalent to <c>v / v.Length()</c>.
/// </summary>
Expand Down
6 changes: 6 additions & 0 deletions tests/core/math/test_math_funcs.h
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,12 @@ TEST_CASE_TEMPLATE("[Math] move_toward", T, float, double) {
CHECK(Math::move_toward(-2.0, -5.0, 4.0) == doctest::Approx((T)-5.0));
}

TEST_CASE_TEMPLATE("[Math] move_toward_smooth", T, float, double) {
CHECK(Math::move_toward_smooth(2.0, 5.0, 0.7) == doctest::Approx((T)3.51024));
CHECK(Math::move_toward_smooth(-2.0, 3.0, 0.8) == doctest::Approx((T)0.753355));
CHECK(Math::move_toward_smooth(-1.0, -4.0, 6.0) == doctest::Approx((T)-3.99256));
}

TEST_CASE_TEMPLATE("[Math] rotate_toward", T, float, double) {
// Rotate toward.
CHECK(Math::rotate_toward((T)0.0, (T)Math_PI * (T)0.75, (T)1.5) == doctest::Approx((T)1.5));
Expand Down
3 changes: 3 additions & 0 deletions tests/core/math/test_vector2.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,9 @@ TEST_CASE("[Vector2] Interpolation methods") {
CHECK_MESSAGE(
Vector2(1, 0).move_toward(Vector2(10, 0), 3) == Vector2(4, 0),
"Vector2 move_toward should work as expected.");
CHECK_MESSAGE(
Vector2(1, 2).move_toward_smooth(Vector2(10, 5), 0.7).is_equal_approx(Vector2(5.530732, 3.510244)),
"Vector2 move_toward_smooth should work as expected.");
}

TEST_CASE("[Vector2] Length methods") {
Expand Down
3 changes: 3 additions & 0 deletions tests/core/math/test_vector3.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,9 @@ TEST_CASE("[Vector3] Interpolation methods") {
CHECK_MESSAGE(
Vector3(1, 0, 0).move_toward(Vector3(10, 0, 0), 3) == Vector3(4, 0, 0),
"Vector3 move_toward should work as expected.");
CHECK_MESSAGE(
Vector3(1, 2, 3).move_toward_smooth(Vector3(10, 5, 7), 0.7).is_equal_approx(Vector3(5.530732, 3.510244, 5.013659)),
"Vector3 move_toward_smooth should work as expected.");
}

TEST_CASE("[Vector3] Length methods") {
Expand Down

0 comments on commit 8f8fb4f

Please sign in to comment.