# Sharing a Projectile / Arc / Kinematic Motion Arc script

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

1. ### 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 {
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

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

3. ### bruntos

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

4. ### 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

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.

Joined:
Apr 17, 2017
Posts:
48
7. ### 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.