Search Unity

Sharing a Projectile / Arc / Kinematic Motion Arc script

Discussion in 'Scripting' started by asperatology, Jul 29, 2018.

  1. asperatology

    asperatology

    Joined:
    Mar 10, 2015
    Posts:
    966
    I sort of improved a script for calculating the trajectory path of a ball, with the aim of using Unity Physics to shoot the ball towards the target position.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. [ExecuteInEditMode]
    6. [RequireComponent(typeof(Rigidbody), typeof(LineRenderer))]
    7. public class LaunchArc : MonoBehaviour {
    8.     /**
    9.         Kinematic equations:
    10.         1. s = ((u + v) * t) / 2
    11.         2. v = u + a * t
    12.         3. s = u * t + (a * t * t) / 2
    13.         4. s = v * t - (a * t * t) / 2
    14.         5. v * v = u * u + 2 * a * s
    15.  
    16.         v = final velocity
    17.         u = initial velocity
    18.         a = acceleration (gravity)
    19.         s = displacement
    20.         t = duration time
    21.      */
    22.  
    23.     public Rigidbody rigidbody;
    24.     public Transform target;
    25.     public Vector3 InitialVelocity;
    26.     public LineRenderer lineRenderer;
    27.  
    28.     public float maximumHeightOfArc;
    29.     public float gravity;
    30.     public int pathResolution;
    31.     public bool showDebugPath;
    32.  
    33.     private bool isLaunching;
    34.     private Vector3 savedPosition;
    35.  
    36.     struct LaunchData {
    37.         public readonly Vector3 initialVelocity;
    38.         public readonly float durationTime;
    39.  
    40.         public LaunchData(Vector3 velocity, float time) {
    41.             this.initialVelocity = velocity;
    42.             this.durationTime = time;
    43.         }
    44.     }
    45.  
    46.     LaunchData CalculateLaunchData() {
    47.         float displacementY = target.position.y - rigidbody.position.y;
    48.         Vector3 displacementXZ = new Vector3(target.position.x - rigidbody.position.x, 0, target.position.z - rigidbody.position.z);
    49.  
    50.         Vector3 velocityY = Vector3.up * Mathf.Sqrt(-2 * gravity * maximumHeightOfArc);
    51.         Vector3 velocityXZ = displacementXZ / (Mathf.Sqrt(-2 * maximumHeightOfArc / gravity) + Mathf.Sqrt(2 * (displacementY - maximumHeightOfArc)/gravity));
    52.  
    53.         float time = Mathf.Sqrt(-2 * maximumHeightOfArc / gravity) + Mathf.Sqrt(2 * (displacementY - maximumHeightOfArc) / gravity);
    54.  
    55.         return new LaunchData(velocityXZ + velocityY * -Mathf.Sign(gravity), time);
    56.     }
    57.  
    58.     void Launch() {
    59.         this.isLaunching = true;
    60.         this.savedPosition = rigidbody.position;
    61.         Physics.gravity = Vector3.up * this.gravity;
    62.         rigidbody.useGravity = true;
    63.  
    64.         LaunchData data = CalculateLaunchData();
    65.         if (!float.IsNaN(data.initialVelocity.y) && !float.IsInfinity(data.initialVelocity.y))
    66.             rigidbody.velocity = data.initialVelocity;
    67.         else {
    68.             this.isLaunching = false;
    69.             rigidbody.useGravity = false;
    70.             rigidbody.position = new Vector3(Random.insideUnitCircle.x * Random.Range(-100, 100), 0, Random.insideUnitCircle.y * Random.Range(-100, 100));
    71.             this.maximumHeightOfArc = Random.Range(this.target.position.y + 1, this.target.position.y + 30);
    72.             rigidbody.velocity = Vector3.zero;
    73.         }
    74.     }
    75.  
    76.     void DrawPath() {
    77.         LaunchData launchData = CalculateLaunchData();
    78.         if (float.IsNaN(launchData.initialVelocity.y) || float.IsInfinity(launchData.initialVelocity.y)) {
    79.             return;
    80.         }
    81.         Vector3 originalPosition = rigidbody.position;
    82.  
    83.         Vector3[] positions = new Vector3[this.pathResolution + 1];
    84.         for (int i = 0; i <= this.pathResolution; i++) {
    85.             float simulationTime = (i / (float) this.pathResolution) * launchData.durationTime;
    86.             Vector3 displacement = launchData.initialVelocity * simulationTime + (Vector3.up * gravity) * simulationTime * simulationTime / 2f;
    87.             positions[i] = originalPosition + displacement;
    88.         }
    89.         this.lineRenderer.positionCount = positions.Length;
    90.         this.lineRenderer.SetPositions(positions);
    91.  
    92.         this.InitialVelocity = launchData.initialVelocity;
    93.     }
    94.  
    95.     void Awake() {
    96.         this.rigidbody = GetComponent<Rigidbody>();
    97.         this.lineRenderer = GetComponent<LineRenderer>();
    98.     }
    99.  
    100.     void Start() {
    101.         rigidbody.useGravity = false;
    102.         this.isLaunching = false;
    103.     }
    104.  
    105.     void Update () {
    106.         if (Input.GetKeyDown(KeyCode.Space)) {
    107.             DrawPath();
    108.             Launch();
    109.         }
    110.         if (showDebugPath && !this.isLaunching) {
    111.             DrawPath();
    112.         }  
    113.     }
    114.  
    115.     void OnValidate() {
    116.         if (showDebugPath && !this.isLaunching) {
    117.             DrawPath();
    118.         }  
    119.     }
    120. }
    121.  
    Found this video here that helps you out even better.



    Yep, just sharing knowledge.
     
  2. johne5

    johne5

    Joined:
    Dec 4, 2011
    Posts:
    1,091
    nice man, thanks
     
  3. bruntos

    bruntos

    Joined:
    Jun 3, 2014
    Posts:
    2
    Thanks so much. I almost understood it all (which is really good going for me!)
     
  4. h00man

    h00man

    Joined:
    Apr 17, 2017
    Posts:
    48
    hey man , thanks for your work but there is an issue with this script.when you move the target gameobject somewhere above the starting point the curve will be freezed.
     
  5. asperatology

    asperatology

    Joined:
    Mar 10, 2015
    Posts:
    966
    Maybe someone else might know how to improve my script. After all, the original script wasn't made with PhysX in mind.

    I'm assuming what you may experienced is probably somewhere in Launch() method, where I did make some hardcoded calculations there.
     
  6. h00man

    h00man

    Joined:
    Apr 17, 2017
    Posts:
    48
  7. asperatology

    asperatology

    Joined:
    Mar 10, 2015
    Posts:
    966
    Ok, so it has to do with the "displacementY" variable being larger than gravity, thus creating a negative value for the Math.sqrt() function.