Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice
  4. Dismiss Notice

Resolved 2D Rigidbody - Achieve linear "power curve" while setting velocity directly

Discussion in 'Physics' started by Calthies4, Feb 9, 2022.

  1. Calthies4

    Calthies4

    Joined:
    Jan 18, 2017
    Posts:
    12
    Hello all,

    I have a 2D golf game where you can rotate an arrow around the ball to specify the angle you want to shoot at, and then give it power (0-100%), and it hits the ball in that direction.

    This currently works pretty well by getting the angle of the arrow, and multiplying that by the default power amount (currently 30) and the amount of power (float between 0f and 1f, shown to the player as 0-100%).

    The problem I'm trying to solve is that the power doesn't work linearly. If I take a shot at 50% power, and compare it to a shot taken at 100% power, the 100% power shot will go a lot more than 2x further. It seems to me that a 2x increase in velocity tends to equal a roughly 3.7x increase in distance. I originally made a formula to tone this down, which worked for awhile, but it seems to be falling apart as I increase the power multiplier.

    Here's a simplified example of my code (without the previously mentioned formula for simplicity's sake):

    Code (CSharp):
    1. public Vector2 CalculateVelocity(float power)
    2. {
    3.     float ballPower = 30f;
    4.  
    5.     arrowAngle = arrow.transform.localEulerAngles.z;
    6.     Vector2 direction = (Vector2)(Quaternion.AngleAxis(arrowAngle, Vector3.forward) * Vector3.up);
    7.  
    8.     Vector2 velocity = (direction * (ballPower * power));
    9.  
    10.     return velocity;
    11. }
    I am calling CalculateVelocity() with a float value between 0f and 1f, and setting the Rigidbody2D's velocity directly with the return value.

    I have looked at dozens of tutorials on similar issues, but none of them quite seem to be running into the same issue I am. Most of them know the destination they want to arrive at or point they want to hit with the object. I don't really care about that, I just want the player to easily be able to rely on the power bar to be an accurate representation of how far the ball will travel.

    A few other notes:
    Gravity is set to default within Project settings: (0, -9.81)
    Gravity scale is set to .8 on my rigidbody
    Linear drag is 0 on my rigidbody

    Am I just completely barking up the wrong tree here? I feel like there has to be some way to achieve a linear power curve. Obviously, physics and advanced math are not my strong suit, so any help would be greatly appreciated.
     
  2. SimonJ9

    SimonJ9

    Joined:
    Feb 5, 2018
    Posts:
    17
    The maximum horizontal distance of a projectile would be something like:

    v^2 * sin(2a) / g

    where v is the (mod of) initial velocity, a is the angle between the initial velocity and the plane, and g is the gravity constant.

    In your case, the initial velocity is:
    Code (CSharp):
    1. Vector2 velocity = (direction * (ballPower * power));
    which means the relationship between the square of your power and the horizontal distance is linear.

    If you want a linear mapping between your power and the travel distance, you probably want to calculate your velocity as
    Code (CSharp):
    1. Vector2 velocity = direction * ballPower * Mathf.Sqrt(power);
    reference:
    https://en.wikipedia.org/wiki/Projectile_motion#Maximum_distance_of_projectile
     
    Calthies4 likes this.
  3. Calthies4

    Calthies4

    Joined:
    Jan 18, 2017
    Posts:
    12
    You're a legend. That works perfectly - thanks!