I am trying to create an enemy for a 2D platformer that launches a projectile in an arc at the player position (think throwing a grenade, launching an arrow style parabola).

Everything works as expected if the player and enemy are more or less on the same y-axis (or similar, within a few units), but the further the difference on the y axis, the faster the projectile moves. This also happens the closer the target gets on the x-axis (but only if there is a difference in the y-axis).

I've included the code in the script that's attached to the projectile that moves it as everything else (the collision, the actual launching of the projectile, etc) works as it should.

GameObject target; // The player is the target
float velX = 10; // Initial x velocity is known
float velY; 

private void Start()
    // Initialize the target object
    target = GameObject.FindGameObjectWithTag("Player");
    // Reverse the x velocity depending on player position
    velX = target.transform.position.x > transform.position.x ? velX : -velX;
    // Calculate the time to impact
    float timeToImpact = (target.transform.position.x - transform.position.x) / velX;
    // Calculate the initial y velocity
    // Add 2 to the target position to aim at the top of the player - it's 2 units tall
    velY = (target.transform.position.y + 2f - transform.position.y + 0.5f * -Physics2D.gravity.y * (timeToImpact * timeToImpact)) / timeToImpact;

private void Update()
    // Set the rigidbody velocity
    Vector2 vel = new Vector2(velX, velY);
    GetComponent<Rigidbody2D>().velocity = vel;
    // Gravity alters the y velocity over time
    velY += Physics2D.gravity.y * Time.deltaTime;

I'm sure that there's just some value that I need to divide or multiply one of the velocities or time by but I can't quite wrap my head around it.


1 Answer 1


The way you've written this code, you've fixed the horizontal velocity to be 10. That means the projectile's time-of-flight will be directly proportional to the horizontal distance to the target: the farther it is horizontally, the longer it will take to reach it. That means the projectile needs more upward velocity to counter the pull of gravity over that longer duration. Since you've fixed your horizontal velocity, the vertical can't take away from that component, it can only add on - resulting in a greater total speed the farther away your target is.

If you want to launch your projectile with [up to] a fixed speed instead, consult one of the existing answers that shows how to do this.

As an aside, your Update() method in this code looks very strange. You should not need to apply gravity yourself - the Rigidbody will integrate that for you. You can use the gravityScale property to adjust the amount of gravity each object gets if you want to apply more or less (or no) gravity to some objects, without extra scripts. If you do find you need to make custom scripted changes to physics behaviour, you should generally do that in FixedUpdate(), not Update() - especially for continuous effects like gravity - this will give you more consistent behaviour even under varying framerates.

  • \$\begingroup\$ Thank, that really helped a lot - both in fixing it and understanding a little more about how this all works. \$\endgroup\$
    – Delagore
    Commented Jul 14, 2022 at 21:05
  • \$\begingroup\$ If this solved your problem, click the checkmark icon in the top-left to mark the answer as "Accepted". \$\endgroup\$
    – DMGregory
    Commented Jul 14, 2022 at 21:10

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .