Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

How to calculate force needed to jump towards target point?

Discussion in 'Physics' started by TaurusSilver, Dec 7, 2015.

  1. TaurusSilver

    TaurusSilver

    Joined:
    Sep 1, 2015
    Posts:
    10
    Hi all,

    So things that I know/got:
    - my object's position (start position) and the target position (end position)
    - direction (target - my object position ?)

    What I need to know is the force that is required to get/jump to the target position (rigidbody.AddForce ( requiredForce * direction, ForceMode.Impulse);

    I have already tried to look around and found the following threads:
    http://answers.unity3d.com/questions/148399/shooting-a-cannonball.html
    http://answers.unity3d.com/questions/145972/how-to-make-enemy-canon-ball-fall-on-mooving-targe.html

    They calculate the arc but that is not exactly what I need.

    It would be great if someone knows the calculation for this and can explain if it is a difficult formula (I'm not that good with physics calculation).

    Thanks.
     
  2. Iron-Warrior

    Iron-Warrior

    Joined:
    Nov 3, 2009
    Posts:
    838
    I don't use rigidbodies, but the same principles should apply in the code below:

    Code (csharp):
    1. // Calculate the initial velocity of a jump based off gravity and desired maximum height attained
    2. private float CalculateJumpSpeed(float jumpHeight, float gravity)
    3. {
    4.     return Mathf.Sqrt(2 * jumpHeight * gravity);
    5. }
    ...and you plug in the height you want to hit with your jump, and your current gravity magnitude.
     
    Rokkr_0 likes this.
  3. TaurusSilver

    TaurusSilver

    Joined:
    Sep 1, 2015
    Posts:
    10
    I tested it, but I could guess that this is not exactly what I need.
    Code (CSharp):
    1.    void JumpTowardPoint()
    2.     {
    3.         float gravity = Physics.gravity.magnitude;
    4.         float initialVelocity = CalculateJumpSpeed(jumpHeight, gravity);
    5.  
    6.         Vector3 direction = target.transform.position - transform.position;
    7.  
    8.         rigidbody.AddForce(initialVelocity * direction, ForceMode.Impulse);
    9.     }
    10.  
    11.     private float CalculateJumpSpeed(float jumpHeight, float gravity)
    12.     {
    13.         return Mathf.Sqrt(2 * jumpHeight * gravity);
    14.     }
    This will shoot just shoot my object in the direction of the target and just fly over it. What I actually want is that it 'jump'/go to that target spot.
     
    Last edited: Dec 8, 2015
    Rokkr_0 and NeonGoose like this.
  4. Iron-Warrior

    Iron-Warrior

    Joined:
    Nov 3, 2009
    Posts:
    838
    Hey! Sorry if I didn't understand right. So what you're looking for is essentially a "cannon-ball" type problem, where you are firing launching your player (the cannonball) at the target...like this?



    It's pretty late but if that's the idea, I'll write up a more detailed answer tomorrow.
     
    Rokkr_0, glenneroo and beuz like this.
  5. TaurusSilver

    TaurusSilver

    Joined:
    Sep 1, 2015
    Posts:
    10
    Yes, that's what I mean. Sorry if I wasn't all too clear with my explanation.
     
  6. Iron-Warrior

    Iron-Warrior

    Joined:
    Nov 3, 2009
    Posts:
    838
    Okay, so the first thing to bear in mind is that the goal to solving this is to treat the object's motion along the two axes separately, which we'll call x and y. Although the results of this can be used in 3d space, this problem only concerns two axes, which is nice. Our given values (the ones we have) are the position of our object, position of the target, and the angle that we want to fire at. From this, we know the planar distance between the object (d) as well as the offset on the y axis between the two. We want the initial velocity to fire the object at to strike the target t.



    As stated above, we'll find the velocity of the components, x and y. vX (velocity x) is constant (there's no air resistance or anything) and so is the following:

    Code (csharp):
    1. v0 * cos(angle)
    ...where v0 is our initial velocity. We know that the distance an object travels is equal to it's velocity*time, so the distance x travels is vX*t, or how long our object is in the air.

    vY is just as easy to solve for, giving us:

    Code (csharp):
    1. v0 * sin(angle)
    However, y is not a constant velocity, but rather has the acceleration of gravity on it throughout it's time in the air. So the velocity of y is equal to the initial velocity, PLUS however much acceleration has acted on it over the course of the time in the air.

    Code (csharp):
    1. vY = -gt + v0 * sin(angle)
    So as you can see, at t=0, y's velocity is just the initial velocity, but over time more acceleration is added. Our y position is then:

    Code (csharp):
    1. -1/2*g*t^2 + v0 * sin(angle)*t + y0
    Now that we can calculate the position of our object on either two axes at any time, we can create a formula to solve for initial velocity. Our initial position is equal to x0 = 0, and y0 = yOffset. We also know that the final x position we want is just equal to distance, and the final y position is equal to 0. We can insert all these into the above two equations, and solve for the both of them (which eliminates t) to get the following:

    Code (csharp):
    1. v0 = (1 / Mathf.Cos(angle)) * Mathf.Sqrt((0.5f * gravity * Mathf.Pow(distance, 2)) / (distance * Mathf.Tan(angle) + yOffset));
    It's a bit to take in! I had to figure this our a few years back for a project, and I got most of the info from this physics exchange post. Implementing the above in Unity looks like this:

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class ProjectileFire : MonoBehaviour {
    6.  
    7.     [SerializeField]
    8.     Transform target;
    9.  
    10.     [SerializeField]
    11.     float initialAngle;
    12.  
    13.     void Start () {
    14.         var rigid = GetComponent<Rigidbody>();
    15.  
    16.         Vector3 p = target.position;
    17.  
    18.         float gravity = Physics.gravity.magnitude;
    19.         // Selected angle in radians
    20.         float angle = initialAngle * Mathf.Deg2Rad;
    21.  
    22.         // Positions of this object and the target on the same plane
    23.         Vector3 planarTarget = new Vector3(p.x, 0, p.z);
    24.         Vector3 planarPostion = new Vector3(transform.position.x, 0, transform.position.z);
    25.  
    26.         // Planar distance between objects
    27.         float distance = Vector3.Distance(planarTarget, planarPostion);
    28.         // Distance along the y axis between objects
    29.         float yOffset = transform.position.y - p.y;
    30.  
    31.         float initialVelocity = (1 / Mathf.Cos(angle)) * Mathf.Sqrt((0.5f * gravity * Mathf.Pow(distance, 2)) / (distance * Mathf.Tan(angle) + yOffset));
    32.  
    33.         Vector3 velocity = new Vector3(0, initialVelocity * Mathf.Sin(angle), initialVelocity * Mathf.Cos(angle));
    34.  
    35.         // Rotate our velocity to match the direction between the two objects
    36.         float angleBetweenObjects = Vector3.Angle(Vector3.forward, planarTarget - planarPostion);
    37.         Vector3 finalVelocity = Quaternion.AngleAxis(angleBetweenObjects, Vector3.up) * velocity;
    38.  
    39.         // Fire!
    40.         rigid.velocity = finalVelocity;
    41.  
    42.         // Alternative way:
    43.         // rigid.AddForce(finalVelocity * rigid.mass, ForceMode.Impulse);
    44.     }
    45. }
    46.  
    Which also rotates our velocity so you can fire in any direction, since we only solve it for the x and y plane.
     
  7. TaurusSilver

    TaurusSilver

    Joined:
    Sep 1, 2015
    Posts:
    10

    Thanks for the explanation and how to implement. I tested it out but I encountered the following 2 scenarios:
    - by using rigidbody.velocity, after the projectile object fires and the x and z are equal to the x and y of the target, the object will slowly goes down (which isn't what we want because of physics)
    -by using the addforce, the projectile object will shoots up and keeps the force applied to it(?). So it will never hit the target?

    I think that I need a way to find when the projectile has reached the max height of the trajectory and set the velocity back to 0 or make it decrease? I'm not really confident with my physics knowledge but because of gravity, after reaching the max height, shouldn't the gravity stop the acceleration of the force and bring it back to 0 and make the object fall down again?

    My object did not 'look' in the direction of the target (instead of the blue arrow in unity, the red arrow was pointing towards the target). Do I have to set the rotation myself like this?
    Code (CSharp):
    1. Vector3 rotateValue = target.transform.position - transform.position;
    2.         Quaternion lookRotation = Quaternion.LookRotation(rotateValue);
    3.         transform.rotation = lookRotation;
     
    Last edited: Dec 10, 2015
    Rokkr_0 and siddharth3322 like this.
  8. Iron-Warrior

    Iron-Warrior

    Joined:
    Nov 3, 2009
    Posts:
    838
    Hmm, not entirely sure what you're asking. The ball is "pushed" back down to zero by Unity's built in gravity (since you're using a rigidbody). Here's a gif of the function being run, with three different initial values. Was the script not working?

     
  9. TaurusSilver

    TaurusSilver

    Joined:
    Sep 1, 2015
    Posts:
    10
    No idea what I did wrong yesterday but it works now. Thanks for the help.
     
  10. Pawl

    Pawl

    Joined:
    Jun 23, 2013
    Posts:
    113
    @Iron-Warrior Thanks for the in-depth explanation, it worked like a charm! =)



     
    Rokkr_0 likes this.
  11. rafaelferrari1

    rafaelferrari1

    Joined:
    Jan 6, 2014
    Posts:
    8
    @Iron-Warrior Thanks for the code and the explanation. I just have one question: was supposed to work all directions? When I use here, if the object is on the rigth of the target, for example, the force is inverse, and the object go to rigth, instead go to left, where is the target.
     
  12. Zethros

    Zethros

    Joined:
    Jan 11, 2013
    Posts:
    12
    While his code is very helpful, it wasn't perfect. To be a bit more specific, when the velocity needs to push the object along the world space X axis, is was unable to apply a negative X velocity, resulting in the vector never being able to go left (relative to world space).

    To fix this, check if the object position x is greater than the target position x (i.e. check if going in a negative X direction is required to reach the target) and, if so, inverse the angleBetweenObjects (i.e. mulltiple by -1).

    Before

    Code Change
    Code (csharp):
    1. // From
    2. float angleBetweenObjects = Vector3.Angle(Vector3.forward, planarTarget - planarPostion);
    3. // To (added "* (p.x > transform.position.x ? 1 : -1)")
    4. float angleBetweenObjects = Vector3.Angle(Vector3.forward, planarTarget - planarPostion) * (p.x > transform.position.x ? 1 : -1);
    After
     
    Last edited: Nov 13, 2016
  13. Jip1912

    Jip1912

    Joined:
    Mar 13, 2015
    Posts:
    314
    This thread is pretty old, but does someone know how to increase the speed of the jump using the script from Iron-Warrior without changing the destination. If you increase the addforce, it won't go to the desired destination, but I want the time of the jump to be shorter. I can't use timeScale because the other objects shouldn't go faster.
     
    SergeyVolik and siddharth3322 like this.
  14. jmjd

    jmjd

    Joined:
    Nov 14, 2012
    Posts:
    50
    Iron-Warrior's script calculates the velocity of the projectile based on an initial angle and the target destination. The only physical way for it to get their faster is to use a smaller (flatter) angle.

    But you could try using an alternate gravity force. If you use a stronger gravity it will get there faster. If you don't want to adjust the global gravity you could specify the gravity force in the script, but you'd have to disable gravity on the rigidbody and do your own gravity in fixed update.

    Edit:
    Or maybe you're looking to start with an initial velocity and want to figure out the angle need to hit a target? I think I've done that before but I can't remember how to do it at the moment.
     
    Last edited: Jan 23, 2017
    awsapps and siddharth3322 like this.
  15. Jip1912

    Jip1912

    Joined:
    Mar 13, 2015
    Posts:
    314
    Thnx. I changed the global gravity to -100 and the speed is okay now. I don't know if this gravity is bad?
     
  16. atpkewl

    atpkewl

    Joined:
    Jun 30, 2015
    Posts:
    17
    Hi @Zethros & @Iron-Warrior , thank you very much for sharing the codes.
    Just wondering how do I draw the dotted line that sort of predicts where the ball will travel before shots ?
    similar to Angry birds before you release the catapult.
     
  17. Zethros

    Zethros

    Joined:
    Jan 11, 2013
    Posts:
    12
    Sorry, but I never coded something like that before. I'll leave that answer to someone else

    (Sorry for the delayed response. I didn't get a notification from you mentioning me for some reason.)
    (Also sorry for replying without an answer. I just didn't want people who could answer to think they shouldn't because you asked Iron-Warrior and I so specifically)
     
  18. Jip1912

    Jip1912

    Joined:
    Mar 13, 2015
    Posts:
    314
    Maybe let a gameobject automatically jump to the destination with a trail behind it?
     
  19. Iron-Warrior

    Iron-Warrior

    Joined:
    Nov 3, 2009
    Posts:
    838
    If anyone is interested, I was planning on writing an article about projectile trajectories but it's kind of fell on the wayside due to other obligations. Anyways, I made an example project for the article that allows you to fire a projectile at either a fixed angle or a fixed velocity and draws out that trajectory.



    Bang bang. Anyways, it mostly boils down to this ProjectileMath class I wrote:

    Code (csharp):
    1.  
    2. using UnityEngine;
    3.  
    4. public static class ProjectileMath
    5. {
    6.     public static bool LaunchAngle(float speed, float distance, float yOffset, float gravity, out float angle0, out float angle1)
    7.     {
    8.         angle0 = angle1 = 0;
    9.  
    10.         float speedSquared = speed * speed;
    11.  
    12.         float operandA = Mathf.Pow(speed, 4);
    13.         float operandB = gravity * (gravity * (distance * distance) + (2 * yOffset * speedSquared));
    14.  
    15.         // Target is not in range
    16.         if (operandB > operandA)
    17.             return false;
    18.  
    19.         float root = Mathf.Sqrt(operandA - operandB);
    20.  
    21.         angle0 = Mathf.Atan((speedSquared + root) / (gravity * distance));
    22.         angle1 = Mathf.Atan((speedSquared - root) / (gravity * distance));
    23.  
    24.         return true;
    25.     }
    26.  
    27.     /// <summary>
    28.     /// Calculates the initial launch speed required to hit a target at distance with elevation yOffset.
    29.     /// </summary>
    30.     /// <param name="distance">Planar distance from origin to the target</param>
    31.     /// <param name="yOffset">Elevation of the origin with respect to the target</param>
    32.     /// <param name="gravity">Downwards force of gravity in m/s^2</param>
    33.     /// <param name="angle">Initial launch angle in radians</param>
    34.     public static float LaunchSpeed(float distance, float yOffset, float gravity, float angle)
    35.     {
    36.         float speed = (distance * Mathf.Sqrt(gravity) * Mathf.Sqrt(1 / Mathf.Cos(angle))) / Mathf.Sqrt(2 * distance * Mathf.Sin(angle) + 2 * yOffset * Mathf.Cos(angle));
    37.  
    38.         return speed;
    39.     }
    40.  
    41.     public static Vector2[] ProjectileArcPoints(int iterations, float speed, float distance, float gravity, float angle)
    42.     {
    43.         float iterationSize = distance / iterations;
    44.  
    45.         float radians = angle;
    46.  
    47.         Vector2[] points = new Vector2[iterations + 1];
    48.  
    49.         for (int i = 0; i <= iterations; i++)
    50.         {
    51.             float x = iterationSize * i;
    52.             float t = x / (speed * Mathf.Cos(radians));
    53.             float y = -0.5f * gravity * (t * t) + speed * Mathf.Sin(radians) * t;
    54.  
    55.             Vector2 p = new Vector2(x, y);
    56.  
    57.             points[i] = p;
    58.         }
    59.  
    60.         return points;
    61.     }
    62. }
    63.  

    You can get the full project at the GitHub repo here.
     
  20. EnokV

    EnokV

    Joined:
    Apr 14, 2016
    Posts:
    56
    Sebastian Lague have some good videos on kinematic equations, where one of them is related to this specific problem.

     
    wickedwaring, Rokkr_0 and zngb like this.
  21. InfinityFleck

    InfinityFleck

    Joined:
    Apr 23, 2016
    Posts:
    1
    Hi!! I have downloaded this GitHub repo, really helped for me. But I want to adjust Cannon's angle (and projectile also) using drag on Cannon (like angry Bird, but in 3D world).plz help, to convert it.....
     
  22. PedroTalespin

    PedroTalespin

    Joined:
    Jan 23, 2018
    Posts:
    1
    This is awesome! Thanks for the project Iron-Warrior. Now to make it more complicated, how would one go about accounting for drag in the projectile's rigidbody?
     
    globichopf likes this.
  23. tonimarquez84

    tonimarquez84

    Joined:
    Feb 23, 2015
    Posts:
    17
    I've realized you use Quaternion.AngleAxis but you must use Quaternion.SignedAngle to avoid it returns only positive angles.
     
  24. neoneper

    neoneper

    Joined:
    Nov 14, 2013
    Posts:
    48
    Hello everyone!

    I'm trying to use this part of the warior script.
    But my project is 2D. I adapted the script to work in 2D but im having difficulty with YOffset. I can not make it work..

    My changed script is this!

    Code (CSharp):
    1.  
    2.  private Vector2 GetIntentPower(Vector2 target, float initialAngle)
    3.         {
    4.  
    5.             float gravity = Physics.gravity.magnitude;
    6.             // Selected angle in radians
    7.  
    8.             // Planar distance between objects
    9.             Vector2 p1 = new Vector2(transform.position.x,transform.position.y);
    10.             Vector2 p2 = new Vector2(target.x,transform.position.y);
    11.             float Xdistance = Vector2.Distance(p1, p2);
    12.  
    13.             // Distance along the y axis between objects
    14.             float yOffset = transform.position.y-target.y; //Its not work
    15.  
    16.  
    17.             float angle = initialAngle * Mathf.Deg2Rad;
    18.  
    19.             float initialVelocity = (1 / Mathf.Cos(angle)) * Mathf.Sqrt((0.5f * gravity * Mathf.Pow(Xdistance, 2)) / (Xdistance * Mathf.Tan(angle) + yOffset));
    20.  
    21.             Vector2 velocity = new Vector2(initialVelocity * Mathf.Sin(angle), initialVelocity * Mathf.Cos(angle));
    22.  
    23.             // Rotate our velocity to match the direction between the two objects
    24.             float angleBetweenObjects = Vector2.Angle(Vector2.right, p2 - p1);
    25.             Vector2 finalVelocity = Quaternion.AngleAxis(angleBetweenObjects, Vector2.right) * velocity;
    26.  
    27.             // Fire!
    28.             //rigid.velocity = finalVelocity;
    29.             return finalVelocity;
    30.  
    31.             // Alternative way:
    32.             // rigid.AddForce(finalVelocity * rigid.mass, ForceMode.Impulse);
    33.         }
    34.  

    It works perfectly when the PLAYER is on the same Y Position as the Target Y Position. But if the Player Y is elsewhere, then it does not work.

    Could you help with this (^.~) Thankx !
     
  25. toomasio

    toomasio

    Joined:
    Nov 19, 2013
    Posts:
    198
    @atpkewl Here's a script I whipped up to draw a line based on velocity and direction...angry birds style

    Code (CSharp):
    1. Vector3[] GetTrajectoryPredictionPoints(Vector3 _startPos, Vector3 _velocity, float _drag, int _steps, float _time)
    2.     {
    3.         var pos = _startPos;
    4.         var vel = _velocity;
    5.         var acc = Physics.gravity;
    6.         var dt = Time.fixedDeltaTime / Physics.defaultSolverVelocityIterations;
    7.         var drag = 1 - (_drag * dt);
    8.         var points = new Vector3[_steps];
    9.         points[0] = _startPos;
    10.         for (int i = 1; i < _steps; i++)
    11.         {
    12.             float t = 0;
    13.             while (t < _time)
    14.             {
    15.                 vel += acc * dt;
    16.                 pos += vel * dt;
    17.                 pos *= drag;
    18.                 t += dt;
    19.             }
    20.             points[i] = pos;
    21.         }
    22.         return points;
    23.     }
     
    ml785 likes this.
  26. iftah

    iftah

    Joined:
    Feb 25, 2014
    Posts:
    16
    Hi,
    I am working on a project where the gravity is set to Vector3.Right * 9.81f, and I need the player to jump to a specific position on the Y axis at a custom Speed. I tried to adapt the scrips in this thread but I couldn't understand the Math involved.
    Can someone please help adapt @Iron-Warrior script to work with this custom gravity?
    Thank you. Jump Help.jpg
     
  27. YannigSmagghe

    YannigSmagghe

    Joined:
    Nov 14, 2018
    Posts:
    6
    I wanted to use iron warrior project with angle settings and up speed of projectile.

    You can increase gravity to do this.

    My way was to multiply physic settings on method and add constant force down to simulate new gravity

    Code (CSharp):
    1.     public void SetTargetWithAngle(Vector3 point, float angle)
    2.     {
    3.         currentAngle = angle;
    4.         ImpactPoint = point;
    5.         Vector3 direction = point - FirePoint.position;
    6.         float yOffset = -direction.y;
    7.         direction = Math3d.ProjectVectorOnPlane(Vector3.up, direction);
    8.         float distance = direction.magnitude;
    9.  
    10.         currentSpeed = ProjectileMath.LaunchSpeed(distance, yOffset, Physics.gravity.magnitude * 3f, angle * Mathf.Deg2Rad);
    11.         Debug.Log(Physics.gravity.magnitude);
    12.      
    13.         SetTurret(direction, currentAngle);
    14.  
    15.         currentTimeOfFlight = ProjectileMath.TimeOfFlight(currentSpeed, currentAngle * Mathf.Deg2Rad, yOffset, Physics.gravity.magnitude* 3f);
    16.     }
     
  28. AK_5002

    AK_5002

    Joined:
    Feb 5, 2020
    Posts:
    1
    Hi, @Iron-Warrior, what changes should I apply to make this work in a 2D game?
     
  29. huangyunfeng

    huangyunfeng

    Joined:
    Apr 5, 2019
    Posts:
    5
    Hi, @Iron-Warrior, I know how to derive a formula of LaunchSpeed function, but I can't find how to derive LaunchAngle , can you explain it ? Very thanks!!
     
  30. qguardg2876

    qguardg2876

    Joined:
    Oct 21, 2016
    Posts:
    1
    replace Vector3.Angle with Vector3.SignedAngle
     
  31. awsapps

    awsapps

    Joined:
    Jun 15, 2021
    Posts:
    74
    Given a fixed _timeToTarget,

    Code (CSharp):
    1.         float xVelocity = Vector3.Distance(transform.position, target.transform.position) / _timeToTarget;
    2.         float angle = Mathf.Atan((1f / 2f * gravity * _timeToTarget + p.y) / xVelocity);
    3. float initialVelocity = xVelocity / Mathf.Cos(angle);
    4.  
    5.  
     
  32. CC_YN

    CC_YN

    Joined:
    Jul 30, 2021
    Posts:
    14
    I used Sebastian Lague method to achieve a target jump in my 2D project. For those of you want to change the velocity to get to the target, you can simply increase the gravity apply to the launch object.
    I don't want to change the whole Physics2D setting, so I make Rigidbody2D.gravityScale = gravity(in this video) / Physics2D.gravity.y;

    Here is my code:
    Code (CSharp):
    1. Transform jumpTarget;
    2. float jumpMaxHeight;
    3. float gravity;
    4. TargetJumpData TargetJump()
    5. {
    6.     //Get the diff
    7.     float yDiff = jumpTarget.Value.transform.position.y - Owner.transform.position.y;
    8.     Vector3 xDiff = new Vector3(jumpTarget.Value.transform.position.x - Owner.transform.position.x, 0, 0);
    9.     //Calculate the time to the target
    10.     float time = Mathf.Sqrt(-2 * jumpMaxHeight / gravity)+ Mathf.Sqrt(2 * (yDiff - jumpMaxHeight)/ gravity);
    11.     //Calculate the velocity
    12.     Vector3 yVelocity = Vector3.up * Mathf.Sqrt(-2 * gravity * jumpMaxHeight);
    13.     Vector3 xVelocity = xDiff / (Mathf.Sqrt(-2 * jumpMaxHeight / gravity) + Mathf.Sqrt(2 * (yDiff - jumpMaxHeight)/ gravity));
    14.  
    15.     Vector3 finalV = xVelocity + yVelocity;
    16.  
    17.     //Debug.Log(time);
    18.  
    19.     return new TargetJumpData(xVelocity + yVelocity * -Mathf.Sign(gravity), time);
    20.  
    21. }
    22.  
    23. private void DrawGraph(){
    24.     TargetJumpData jumpData = TargetJump();
    25.     Vector3 previousDrawPoint = Owner.transform.position;
    26.  
    27.     int resolution = 30;
    28.     for(int i = 1; i < resolution; i++){
    29.         float simulationTime = i / (float)resolution * jumpData.timeToTarget;
    30.         Vector3 displacement = jumpData.initialVelocity * simulationTime + Vector3.up * gravity * simulationTime * simulationTime / 2f;
    31.         Vector3 drawPoint = Owner.transform.position + displacement;
    32.         Debug.DrawLine(previousDrawPoint, drawPoint, Color.green);
    33.         previousDrawPoint = drawPoint;
    34.  
    35.     }
    36. }
    37.  
    38. struct TargetJumpData{
    39.     public readonly Vector3 initialVelocity;
    40.     public readonly float timeToTarget;
    41.  
    42.     public TargetJumpData(Vector3 initialVelocity, float timeToTarget){
    43.         this.initialVelocity = initialVelocity;
    44.         this.timeToTarget = timeToTarget;
    45.     }
    46. }
     
    Last edited: Aug 22, 2022
    toomasio likes this.
  33. LEGENDARY_L

    LEGENDARY_L

    Joined:
    Dec 31, 2015
    Posts:
    7
    The way I do Trajectory Visualizing is using the formula for Projectile Motion, with some twists.

    I have the code at the end, but read through this first to try and understand.

    To find how much an object has to move towards a target, first we need the Y of the object.

    EX: Starting at (0, 0, 0), target at (10, 8, 0)

    Once we have that, we then arrange the kinematic equation shown earlier as a reply, and calculate the force needed to reach that height.

    upload_2022-9-11_2-45-21.png

    For the sake of the work later, vy is velocity on the y axis, and g is the absolute value of acceleration due to gravity. "h" is the height difference between the start and target. Using the equation above, we find the force needed.

    To find x, we just need to take the difference of the x coordinates. This will be our x velocity.

    Once we have x and y, we can find 2 important variables: The angle of trajectory, and velocity as a single value.
    upload_2022-9-11_2-49-7.png

    Angle of trajectory is equal to the inverse tangent of y velocity / x velocity. Velocity as a single variable is equal to the square root of x velocity squared, plus y velocity squared.

    Now that we have all the variables, we can find the Trajectory Path using the equation for Projectile Motion.

    upload_2022-9-11_2-51-22.png

    x in this case is NOT velocity of x. X in this case is how many units the object travels.

    You can run a loop on a line renderer, and use an increment value to determine how many times x scrubs is scrubbed against the curve.

    You can have a set number to draw the line, OR you can find the roots (0's) of the equation to have a base start and end point.

    To find where y is 0 again on the x axis, the equation needs to be rearranged to solve only for x. To save the trouble, I already did this.

    upload_2022-9-11_2-53-27.png

    You can have the loop stop once x is >= the root.

    This is all you need to have basic trajectory visualization. As to how it looks in code, here it is:

    Code (CSharp):
    1. float CalculateProjectileMotion(float x, Transform start, Transform target)
    2. {
    3.     float a = Physics.gravity.y;
    4.     float velocityX = start.position.x - target.position.x;
    5.     float velocityY = Mathf.Sqrt(2 * (a * (start.position.y - target.position.y) ));
    6.  
    7.     float projectileVelocity = Mathf.Sqrt(velocityX  * velocityX  + velocityY  * velocityY );
    8.     float trajectoryAngle = Mathf.Atan(velocityY/velocityX );
    9.  
    10.     return x * Mathf.Tan(trajectoryAngle) - ( (a * x * x) / (2 * (projectileVelocity * projectileVelocity) * (Mathf.Cos(trajectoryAngle) * Mathf.Cos(trajectoryAngle) ) ) );
    11. }
    Note: This is only the projectile code, you'll have to make the line projection loop yourself. If you want the target to be a wall hit, then you need to multiply the x difference by 2 as the highest point will be at the midway.

    P.S. I didn't include the roots, I'll leave that up to you to figure out how to translate into code.
     
    Last edited: Sep 11, 2022
    wickedwaring likes this.
  34. ETGgames

    ETGgames

    Joined:
    Jul 10, 2015
    Posts:
    101
    I get a NaN error if the horizontal distance is too close
     
  35. LEGENDARY_L

    LEGENDARY_L

    Joined:
    Dec 31, 2015
    Posts:
    7
    That happens when horizontal is 0. The reason why is because of division of velocityY/velocityX for getting the angle of trajectory. n / 0 returns NaN since it's undefined so make sure velocityX is never 0.