Throw an object along a parabola?

Hey there,

I’m trying to get my main character to be able to throw objects. Currently I’m just applying a force to the object, which works, but is wildly unpredictable if the player is trying to throw at a very specific point.

What I would LIKE to do is for the thrown object to always follow the same parabola from the player, so the player can better gauge when to throw an object. Something like the throwing seen here in Ocarina of Time:

I COULD transform the thrown object along a curve, but that would ignore obstacles. How can I best implement throwing this way?

There are several ways to achieve this.

  1. You could use a cubic spline to define the curve of the throw. The first point would be the location of the player, 2nd (control point) the height of the throw and last point the target. To learn more about this, check out this website Bézier Curves for your Games: A Tutorial – Dev.Mag

  2. You could use projectile motion to calculate how much force is needed to apply force to a Rigidbody to throw it a certain distance at a certain angle to reach a target.

  3. You could still use projectile motion but simulate gravity and bypass physics to have better control over projectile speed and simulation. Below is sample code for this. Here is a short video showing the results of this script http://www.youtube.com/watch?v=3B5NV4bAkoE

using UnityEngine;
using System.Collections;

public class ThrowSimulation : MonoBehaviour
{
    public Transform Target;
    public float firingAngle = 45.0f;
    public float gravity = 9.8f;

    public Transform Projectile;      
    private Transform myTransform;
   
    void Awake()
    {
        myTransform = transform;      
    }

    void Start()
    {           
        StartCoroutine(SimulateProjectile());
    }


    IEnumerator SimulateProjectile()
    {
        // Short delay added before Projectile is thrown
        yield return new WaitForSeconds(1.5f);
        
        // Move projectile to the position of throwing object + add some offset if needed.
        Projectile.position = myTransform.position + new Vector3(0, 0.0f, 0);
        
        // Calculate distance to target
        float target_Distance = Vector3.Distance(Projectile.position, Target.position);

        // Calculate the velocity needed to throw the object to the target at specified angle.
        float projectile_Velocity = target_Distance / (Mathf.Sin(2 * firingAngle * Mathf.Deg2Rad) / gravity);

        // Extract the X  Y componenent of the velocity
        float Vx = Mathf.Sqrt(projectile_Velocity) * Mathf.Cos(firingAngle * Mathf.Deg2Rad);
        float Vy = Mathf.Sqrt(projectile_Velocity) * Mathf.Sin(firingAngle * Mathf.Deg2Rad);

        // Calculate flight time.
        float flightDuration = target_Distance / Vx;
   
        // Rotate projectile to face the target.
        Projectile.rotation = Quaternion.LookRotation(Target.position - Projectile.position);
        
        float elapse_time = 0;

        while (elapse_time < flightDuration)
        {
            Projectile.Translate(0, (Vy - (gravity * elapse_time)) * Time.deltaTime, Vx * Time.deltaTime);
           
            elapse_time += Time.deltaTime;

            yield return null;
        }
    }   
}

P.S. Tweaking gravity allows you to fire the projectile at a much higher velocity with the much stronger fake gravity pulling it down that much faster.

34 Likes

how do you use or tweak this code if i have to throw the projectile at the click of the mouse ?? and my projectile is not iterating. it is not throwing at a regular interval when it is supposed to iterate. and what if i have multiple targets to hit???

Hi,
Thank for the script. I would like to use your script. My requirement is kind of different. I don’t want to use launch angle. Instead I want to use how much time it should take to reach the target. How I can reuse above script? Could you help me on the same please…

Wow thanks for excellent script working neatly.I have one query,my enemy is moving only one direction i.e., Z,I want to throw granade at enemy,how can I calculate enemy’s future position based on speed and throw granade which will accurately hit moving enemy?

@Stephan-B
i really appreciate your generous help , it saved me a lot of trouble and time.

Hi, guys. Tried using this method for a game I’m making, but I couldn’t find a way to increase the speed of the ball? Whenever I change velocity (or anything else), the object just goes to a different location that’s not the target. Anyone know how to increase the speed?

Try increasing Gravity

Thanks man, helped me to single out the issue. Turns out I was increasing the gravity in the script, but it was overriding that gravity because it’s a public member that can be set within Unity.

Glad your problem got solved

Excellent!! Thanks alot.

I am doing this on a 2d platformer. My problem is the opposite of @KidNova
My projectile moves too fast that I cn barely see it. I tried REDUCING the gravity to insane amounts (0.000000000 something) but still its too fast. Its fo fast that I blink and miss it. Is there a way to modify this code to work in a 2d platformer over short distances?

when i call StartCoroutine(SimulateProjectile()); in void OnCollisionEnter(Collision col) object does’nt go to target position

It seems there might be something about the way Unity calculates things that has changed since this code was written. This is the second code I’ve found online that clearly worked for others years ago, but when I use it now, the projectile always overshoots the target position. Please can anyone confirm that this code still works for them right now?

Fixed it! I just had to change
if(input.GetButton(“Fire1”))
to
if(input.GetButtonUp(“Fire1”))
so that the coroutine wasn’t triggered multiple times

Thank you Stephan-B for the codes. I was able to tweak Stephan-B’s code and make it so that the projectile reaches the target as intended. I also used another code to determine the target’s position from the firing position using:
Distance = 2s^2*sin(theta)*cos(theta)/g

My problem is I have no idea how to increase the speed of the projectile. I need the target to be calculated the same way but with faster projectile speed. Anyone have any idea on how this can be achieved?

P/s: I tried increasing the gravity but then the projectile won’t land in the target’s position correctly.

Also, any ideas on how to make the projectile to face the target when falling?

Try this demo
https://www.desmos.com/calculator/gm3scd9uij

ay - gravity
T - time
R - range (distance)

Try altering gravity and click play button at “T” to visualize speed.
Range (distance) remains constant, no matter what the gravity is.

Hi Everyone, i like this code and it achieve what I wanted to achieve which is to throw an object in an arc towards a target. How can I get the velocity after it hits the target ? at the moment it just fall straight down as the previous velocity from rigidbody is 0.

It looks unrealistic to fall straight instead of continue from the previous velocity.

Appreciate your help

Thanks for this enlightenment Aldo-V. I realised that I need to rescale my result if I increase the gravity. I was using gravity to measure distance as well. So increasing gravity alone before this would skew the distance produced by the formula. I just needed to make sure I multiply where needed to get the same result for distance.

I added animation to achieve that effect.Basically after object hit ground start animation which does that job.