# Calculate mortar parabolic trajectory knowing the shot angle but not velocity

The problem is that when I set the y position of the mortar to a different one to 0 the tajectories dont work. But it does work if the bullet I shoot has to impact on different altitudes.

I have two scripts Mortar Script:

```
public class Projectile1: MonoBehaviour
{
// launch variables
[Range(20.0f, 75.0f)] public float LaunchAngle;
public float waitTime;
public GameObject Bullet;
public GameObject Canon;
public GameObject Mark;
// state
private bool bTouchingGround;
private bool Reloading = false;
// cache
public RaycastHit hit;
//-----------------------------------------------------------------------------------------------
// Use this for initialization
void Start()
{
}
// resets the projectile to its initial position
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonUp(0))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit, Mathf.Infinity))
{
Debug.DrawLine(Camera.main.transform.position, hit.point, Color.red);
//Debug.Log(hit.transform.position.x);
if (hit.transform != null & Reloading == false)
{
Instantiate(Mark, new Vector3(hit.point.x, hit.point.y+0.01f, hit.point.z), Quaternion.Euler(new Vector3(90,0,0)));
Instantiate(Bullet, Canon.transform.position, Quaternion.Euler(new Vector3(90, 0, 90)));
StartCoroutine(Reload(waitTime));
}
}
}
}
IEnumerator Reload(float waitTime)
{
Reloading = true;
yield return new WaitForSeconds(waitTime);
Reloading = false;
}
}
```

Bullet Script:

```
public class Bullet: MonoBehaviour
{
Rigidbody rigid;
public GameObject Mortar;
private Quaternion initialRotation;
// Start is called before the first frame update
void Start()
{
Mortar = GameObject.FindGameObjectWithTag("Arma");
//Debug.Log(Mortar.GetComponent<Projectile1>().hit.transform.position.x);
rigid = GetComponent<Rigidbody>();
initialRotation = transform.rotation;
Launch(Mortar.GetComponent<Projectile1>().hit.point, Mortar.GetComponent<Projectile1>().LaunchAngle);
}
private void Update()
{
transform.rotation = Quaternion.LookRotation(rigid.velocity) * initialRotation;
}
void Launch(Vector3 hit, float LaunchAngle)
{
//GameObject Disparo = Instantiate(Bullet, Canon.transform.position, Quaternion.identity);
// think of it as top-down view of vectors:
// we don't care about the y-component(height) of the initial and target position.
Vector3 projectileXZPos = new Vector3(transform.position.x, 0.0f, transform.position.z);
Vector3 targetXZPos = new Vector3(hit.x, 0.0f, hit.z);
// rotate the object to face the target
transform.LookAt(targetXZPos);
// shorthands for the formula
float R = Vector3.Distance(projectileXZPos, targetXZPos);
float G = Physics.gravity.y;
float tanAlpha = Mathf.Tan(LaunchAngle * Mathf.Deg2Rad);
float H = hit.y - transform.position.y;
// calculate the local space components of the velocity
// required to land the projectile on the target object
float Vz = Mathf.Sqrt(G * R * R / (2.0f * (H - R * tanAlpha)));
float Vy = tanAlpha * Vz;
// create the velocity vector in local space and get it in global space
Vector3 localVelocity = new Vector3(0f, Vy, Vz);
Vector3 globalVelocity = transform.TransformDirection(localVelocity);
// launch the object by setting its initial velocity and flipping its state
rigid.velocity = globalVelocity;
}
private void OnTriggerEnter(Collider other)
{
if(other.tag == "Mark")
{
Destroy(other.gameObject);
Destroy(this.gameObject);
}
}
}
```

**Answer** by lgarczyn
·
Jan 23 at 09:04 PM

A lot of code can be made a bit better

```
Instantiate(Mark, new Vector3(hit.point.x, hit.point.y+0.01f, hit.point.z), Quaternion.Euler(new Vector3(90,0,0)));
```

can be

```
Instantiate(Mark, hit.point + Vector3.up * 0.01f, Quaternion.Euler(-90, 0, 0));
```

You should also avoid using a rigidbody's transform, so

```
transform.rotation = Quaternion.LookRotation(rigid.velocity) * initialRotation;
```

should be

```
rigid.rotation = Quaternion.LookRotation(rigid.velocity) * initialRotation;
```

To avoid using FindObject, you can call Launch from the Mortar script:

```
GameObject bulletGO = Instantiate(Bullet, Canon.transform.position, Quaternion.Euler(new Vector3(90, 0, 90)));
bulletGO.GetComponent<Bullet>().Launch(hit.point + Vector3.up * 0.01f, LaunchAngle);
```

It's good to keep data transfer in one direction, usually from weapon to projectile

Now your math can be made a bit simpler. We know the shot direction, which can be calculated like so

```
Vector3 xzdir = (hit - rigid.position);
xzdir.y = 0f;
Vector3 shotDir = Quaternion.LookRotation(xzDir) * Quaternion.AngleAxis(LaunchAngle, Vector3.right) * Vector3.forward;
```

But the velocity is a bit more complicated, I decided to figure out my own equation for fun. We know

```
rigidbody.positon + shotDir * vel * time + Physics.gravity * time * time / 2 == hit;
```

or

```
shotDir * vel * time - Physics.gravity * time * time / 2 == deltaPos
```

We can extract two equations:

```
shotDir.y * vel * time + Physics.gravity.y * time * time / 2 == deltaPos.y
shotDir.x * vel * time == deltaPos.x
```

Using the second, we can find the confusing

```
vel * time == deltaPos.x / shotDir.x
```

And if we use it the first equation, we get

```
shotDir.y * deltaPos.x / shotDir.x + Physics.gravity.y * time * time / 2 == deltaPos.y
```

After further refining, we get a negative a positive solution for time (we discard the negative)

```
float time = Mathf.Sqrt((shotDir.y * deltaPos.x / shotDir.x - deltaPos.y) / -Physics.gravity.y * 2);
```

And by reversing the second equation we get:

```
float vel = deltaPos.x / shotDir.x / time;
```

And thus the code

```
void Launch(Vector3 hit, float LaunchAngle)
{
Vector3 deltaPos = hit - rigid.position;
Vector3 xzDelta = deltaPos;
xzDelta.y = 0f;
Vector3 shotDir = Quaternion.LookRotation(xzDelta) * Quaternion.AngleAxis(-LaunchAngle, Vector3.right) * Vector3.forward;
float time = Mathf.Sqrt((shotDir.y * deltaPos.x / shotDir.x - deltaPos.y) / -Physics.gravity.y * 2);
float vel = deltaPos.x / shotDir.x / time;
if (float.IsNaN(vel))
{
Debug.Log("Impossible Trajectory")
}
rigid.velocity = vel * shotDir;
}
```

First of all thanks for the help. Im gonna try to make the changes you recommend and lets see if it gets solved. Thanks again

Dude Thanks so much it works!!!

Now Ive gotta understand why yours works and mine doesnt. But thanks so much I was breaking my head trying to figure it out.

Honestly, I'm not sure exactly how mine works. The steps to get the formula make perfect sense, but the result is a bit absurd.

### Your answer

### Welcome to Unity Answers

The best place to ask and answer questions about development with Unity.

To help users navigate the site we have posted a site navigation guide.

If you are a new user to Unity Answers, check out our FAQ for more information.

Make sure to check out our Knowledge Base for commonly asked Unity questions.

If you are a moderator, see our Moderator Guidelines page.

We are making improvements to UA, see the list of changes.

### Follow this Question

### Related Questions

Can you point me in the direction of how to get space physics like the one in this video? 1 Answer

Health and Damage Script Not Working 2 Answers

Enemies shoot slower if the player is far away 1 Answer

How to make a ladder script 0 Answers

how to dostraight ball throwing objects from returning? 0 Answers