forked from FreyaHolmer/Mathfs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Trajectory.cs
119 lines (103 loc) · 4.96 KB
/
Trajectory.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// collected and expended upon by Freya Holmér (https://github.com/FreyaHolmer/Mathfs)
using UnityEngine;
using static Freya.Mathfs;
namespace Freya {
// Trajectory math
public static class Trajectory {
/// <summary>
/// Outputs the launch speed required to traverse a given lateral distance when launched at a given angle, if one exists
/// </summary>
/// <param name="gravity">Gravitational acceleration in meters per second</param>
/// <param name="lateralDistance">Target lateral distance in meters</param>
/// <param name="angle">Launch angle in radians (0 = flat)</param>
/// <param name="speed">Launch speed in meters per second</param>
/// <returns>Whether or not there is a valid launch speed</returns>
public static bool TryGetLaunchSpeed( float gravity, float lateralDistance, float angle, out float speed ) {
float num = lateralDistance * gravity;
float den = Sin( 2 * angle );
if( Abs( den ) < 0.00001f ) {
speed = default;
return false; // direction is parallel, no speed would get you there
}
float speedSquared = num / den;
if( speedSquared < 0 ) {
speed = 0;
return false; // can't reach destination because you're going the wrong way
}
speed = Sqrt( speedSquared );
return true;
}
/// <summary>
/// Outputs the two launch angles given a lateral distance and launch speed, if they exist
/// </summary>
/// <param name="gravity">Gravitational acceleration in meters per second</param>
/// <param name="lateralDistance">Target lateral distance in meters</param>
/// <param name="speed">Launch speed in meters per second</param>
/// <param name="angleLow">The low launch angle in radians</param>
/// <param name="angleHigh">The high launch angle in radians</param>
/// <returns>Whether or not valid launch angles exist</returns>
public static bool TryGetLaunchAngles( float gravity, float lateralDistance, float speed, out float angleLow, out float angleHigh ) {
if( speed == 0 ) {
angleLow = angleHigh = default;
return false; // can't reach anything without speed
}
float asinContent = ( lateralDistance * gravity ) / ( speed * speed );
if( asinContent.Within( -1, 1 ) == false ) {
angleLow = angleHigh = default;
return false; // can't reach no matter what angle is used
}
angleLow = Asin( asinContent ) / 2;
angleHigh = ( -angleLow + TAU / 4 );
return true;
}
/// <summary>
/// Returns the maximum lateral range a trajectory could reach, when launched at the optimal angle of 45°
/// </summary>
/// <param name="gravity">Gravitational acceleration in meters per second</param>
/// <param name="speed">Launch speed in meters per second</param>
/// <returns>Maximum lateral range in meters per second</returns>
public static float GetMaxRange( float gravity, float speed ) {
return speed * speed / gravity;
}
/// <summary>
/// Returns the displacement given a launch speed, launch angle and a traversal time
/// </summary>
/// <param name="gravity">Gravitational acceleration in meters per second</param>
/// <param name="speed">Launch speed in meters per second</param>
/// <param name="angle">Launch angle in radians (0 = flat)</param>
/// <param name="time">Traversal time in seconds</param>
/// <returns>Displacement, where x = lateral displacement and y = vertical displacement</returns>
public static Vector2 GetDisplacement( float gravity, float speed, float angle, float time ) {
float xDisp = speed * time * Cos( angle );
float yDisp = speed * time * Sin( angle ) - .5f * gravity * time * time;
return new Vector2( xDisp, yDisp );
}
/// <summary>
/// Returns the maximum height that can possibly be reached if speed was redirected upwards, given a current height and speed
/// </summary>
/// <param name="gravity">Gravitational acceleration in meters per second</param>
/// <param name="currentHeight">Current height in meters</param>
/// <param name="speed">Launch speed in meters per second</param>
/// <returns>Potential height in meters</returns>
public static float GetHeightPotential( float gravity, float currentHeight, float speed ) {
return currentHeight + ( speed * speed ) / ( 2 * -gravity );
}
/// <summary>
/// Outputs the speed of an object with a given height potential and current height, if it exists
/// </summary>
/// <param name="gravity">Gravitational acceleration in meters per second</param>
/// <param name="currentHeight">Current height in meters</param>
/// <param name="heightPotential">Potential height in meters</param>
/// <param name="speed">Speed in meters per second</param>
/// <returns>Whether or not there is a valid speed</returns>
public static bool TryGetSpeedFromHeightPotential( float gravity, float currentHeight, float heightPotential, out float speed ) {
float speedSq = ( heightPotential - currentHeight ) * -2 * gravity;
if( speedSq <= 0 ) {
speed = default; // Imaginary speed :sparkles:
return false;
}
speed = Sqrt( speedSq );
return true;
}
}
}