Advertisement
Guest User

ProjectileMath.cs

a guest
Feb 5th, 2019
1,138
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 6.86 KB | None | 0 0
  1. using UnityEngine;
  2. using UnityEngine.Assertions;
  3.  
  4. public static class ProjectileMath
  5. {
  6.     public static Vector2 Get2DVec(Vector3 vector)
  7.     {
  8.         var s = vector;
  9.         var sH = Mathf.Sqrt(s.x*s.x + s.z*s.z);
  10.         return new Vector2(sH, s.y);
  11.     }
  12.  
  13.     public static Vector3 Get3DVec(Vector2 vector, Vector3 targetDisplacement)
  14.     {
  15.         Vector3 horizontalNormal = targetDisplacement.GetZeroY().normalized;
  16.  
  17.         return new Vector3( vector.x * horizontalNormal.x,
  18.                             vector.y,
  19.                             vector.x * horizontalNormal.z);
  20.     }
  21.  
  22.     public static Vector2 GetLaunchVelocity(float speed, float angleRadians)
  23.     {
  24.         return new Vector2(Mathf.Cos(angleRadians), Mathf.Sin(angleRadians)) * speed;
  25.     }
  26.    
  27.     public static Vector3 GetLaunchVelocity(Vector3 targetDisplacement, float angleRadians, float speed)
  28.     {
  29.         Vector3 horizontalNormal = targetDisplacement.GetZeroY().normalized;
  30.        
  31.         float cosA = Mathf.Cos(angleRadians);
  32.         float sinA = Mathf.Sin(angleRadians);
  33.  
  34.         return new Vector3(horizontalNormal.x * cosA, sinA, horizontalNormal.z * cosA) * speed;
  35.     }
  36.    
  37.     public static void BreakLaunchVectorToAngleAndSpeed(Vector2 launchVelocity, out float elevationRadians, out float speedSq)
  38.     {
  39.         elevationRadians = Mathf.Atan2(launchVelocity.y, launchVelocity.x);
  40.         speedSq = Vector2.SqrMagnitude(launchVelocity);
  41.     }
  42.  
  43.     public static void BreakLaunchVectorToAngleAndSpeed(Vector3 launchVelocity, out float elevationRadians, out float speedSq)
  44.     {
  45.         float horizontal = Mathf.Sqrt(launchVelocity.x * launchVelocity.x + launchVelocity.z * launchVelocity.z);
  46.         BreakLaunchVectorToAngleAndSpeed(new Vector2(horizontal, launchVelocity.y), out elevationRadians, out speedSq);
  47.     }
  48.  
  49.     public static Vector3 GetDisplacementAtTime(Vector3 launchVelocity, float gravity, float time)
  50.     {
  51.         Vector3 ret = launchVelocity * time;
  52.         ret.y += 0.5f * gravity * time * time;
  53.         return ret;
  54.     }
  55.  
  56.     public static Vector2 GetDisplacementAtTime(Vector2 launchVelocity, float gravity, float time)
  57.     {
  58.         Vector2 ret = launchVelocity * time;
  59.         ret.y += 0.5f * gravity * time * time;
  60.         return ret;
  61.     }
  62.  
  63.     public static float GetPeakTime(float launchVelocityVertical, float gravity)
  64.     {
  65.         return -launchVelocityVertical / gravity;
  66.     }
  67.  
  68.     public static float GetTimeToHorizontal(float launchSpeedHorizontal, float distanceHorizontal)
  69.     {
  70.         return distanceHorizontal / launchSpeedHorizontal;
  71.     }
  72.  
  73.     public static bool ComputeProjectileSpeedSq(Vector3 displacement, float elevationRadians, float gravity, out float speedSq)
  74.     {
  75.         return ComputeProjectileSpeedSq(Get2DVec(displacement), elevationRadians, gravity, out speedSq);
  76.     }
  77.  
  78.     public static bool ComputeProjectileSpeedSq(Vector2 displacement, float elevationRadians, float gravity, out float speedSq)
  79.     {
  80.         speedSq = 0.0f;
  81.         var a = elevationRadians;
  82.         var s = displacement;
  83.  
  84.         // don't throw backwards - also avoids รท0 errors for cos(pi)=0
  85.         if(a >= Mathf.PI || a <= -Mathf.PI)
  86.             return false;
  87.  
  88.         float tanA = Mathf.Tan(a);
  89.         float cosA = Mathf.Cos(a);
  90.  
  91.         // Angle is too low to hit with -ve gravity - also avoids 0 errors for Sy=Sx*tA
  92.         if(s.x * tanA <= s.y)
  93.             return false;
  94.  
  95.         speedSq = ((gravity * s.x * s.x) / (2.0f * cosA * cosA))  /  (s.y - s.x * tanA);
  96.  
  97.         return true;
  98.     }
  99.  
  100.     public static bool ComputeProjectileMinEffort(Vector3 displacement, float minElevationRads, float maxElevationRads, float searchStep, float gravity, out float outRadians, out float speedSq)
  101.     {
  102.         return ComputeProjectileMinEffort(Get2DVec(displacement), minElevationRads, maxElevationRads, searchStep, gravity, out outRadians, out speedSq);
  103.     }
  104.  
  105.     public static bool ComputeProjectileMinEffort(Vector2 displacement, float minElevationRads, float maxElevationRads, float searchStep, float gravity, out float outRadians, out float speedSq)
  106.     {
  107.         float targetRads = Mathf.Atan2(displacement.y, displacement.x);
  108.         minElevationRads = Mathf.Max(minElevationRads, targetRads);
  109.         maxElevationRads = Mathf.Min(maxElevationRads, 0.5f*Mathf.PI);
  110.  
  111.         speedSq = float.MaxValue;
  112.         outRadians = minElevationRads;
  113.  
  114.         for(float r=minElevationRads+searchStep; r < maxElevationRads; r += searchStep)
  115.         {
  116.             float candidateSpeedSq = 0.0f;
  117.  
  118.             if(ComputeProjectileSpeedSq(displacement, r, gravity, out candidateSpeedSq) && candidateSpeedSq < speedSq)
  119.             {
  120.                 speedSq = candidateSpeedSq;
  121.                 outRadians = r;
  122.             }
  123.             else if (outRadians < float.MaxValue)
  124.             {
  125.                 // if we fail to get better, then we've gone past optimal
  126.                 return true;
  127.             }
  128.         }
  129.  
  130.         return outRadians < float.MaxValue;
  131.     }
  132.  
  133.     public static bool ComputeProjectileWithPeakHeight(Vector2 displacement, float peakHeight, float gravity, out Vector2 launchVelocity, out float peakTime, out float targetTime)
  134.     {
  135.         launchVelocity = Vector2.zero;
  136.  
  137.         Assert.IsTrue(peakHeight > displacement.y, "peakHeight must be higher than the target");
  138.  
  139.         launchVelocity.y = Mathf.Sqrt(-2.0f * gravity * peakHeight);
  140.  
  141.         float fallDisp = displacement.y - peakHeight;
  142.         float invG = 1.0f / gravity;
  143.  
  144.         float tPeak = -launchVelocity.y * invG;
  145.         float tFall = Mathf.Sqrt(2 * fallDisp * invG);
  146.         float tTotal = tPeak + tFall;
  147.  
  148.         launchVelocity.x = displacement.x / tTotal;
  149.  
  150.         peakTime = tPeak;
  151.         targetTime = tTotal;
  152.         return true;
  153.     }
  154.  
  155.     public static bool ComputeProjectileWithFixedHorizonalSpeed(Vector3 displacement, float horizontalSpeed, float gravity, out Vector2 launchVelocity)
  156.     {
  157.         return ComputeProjectileWithFixedHorizonalSpeed(Get2DVec(displacement), horizontalSpeed, gravity, out launchVelocity);
  158.     }
  159.  
  160.     public static bool ComputeProjectileWithFixedHorizonalSpeed(Vector2 displacement, float horizontalSpeed, float gravity, out Vector2 launchVelocity)
  161.     {
  162.         float t = displacement.x / horizontalSpeed;
  163.         launchVelocity.x = horizontalSpeed;
  164.         launchVelocity.y = (displacement.y / t) - (0.5f*gravity*t);
  165.  
  166.         return true;
  167.     }
  168.  
  169.     public static bool ComputeProjectileWithFixedLinearSpeed(Vector3 displacement, float linearSpeed, float gravity, out Vector2 launchVelocity)
  170.     {
  171.         return ComputeProjectileWithFixedLinearSpeed(Get2DVec(displacement), linearSpeed, gravity, out launchVelocity);
  172.     }
  173.  
  174.     public static bool ComputeProjectileWithFixedLinearSpeed(Vector2 displacement, float linearSpeed, float gravity, out Vector2 launchVelocity)
  175.     {
  176.         float horizontalSpeed = linearSpeed * displacement.x / displacement.magnitude;
  177.         return ComputeProjectileWithFixedHorizonalSpeed(displacement, horizontalSpeed, gravity, out launchVelocity);
  178.     }
  179.  
  180.     public static bool IsUnderParabola(Vector2 targetDisplacement, Vector2 launchVelocity, float gravity)
  181.     {
  182.         Assert.IsTrue(launchVelocity.x > 0.0f, "Parabola needs a positive X in the launch velocity");
  183.  
  184.         float t = targetDisplacement.x / launchVelocity.x;
  185.         float yt = (launchVelocity.y * t) + (0.5f * gravity * t*t);
  186.  
  187.         return targetDisplacement.y < yt;
  188.     }
  189.  
  190.     public static bool IsUnderParabola(Vector3 targetDisplacement, Vector2 launchVelocity, float gravity)
  191.     {
  192.         return IsUnderParabola(Get2DVec(targetDisplacement), launchVelocity, gravity);
  193.     }
  194. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement