Search Unity

Projectile prediction line?

Discussion in 'Scripting' started by RingOfStorms, Jul 14, 2012.

  1. RingOfStorms

    RingOfStorms

    Joined:
    Oct 23, 2010
    Posts:
    584
    Hey guys I've spent the day trying to make a projectile trajectory prediction line to no avail. When I searched I found this, http://answers.unity3d.com/questions/133315/how-to-plot-projectile-path-with-dotted-line.html. However, it uses Vectrocity which is something I do not have. I tried to do it with a linerenderer but have yet to get it to work yet. Remember I want this to be a line of prediction, so the projectile has not been shot yet, I've tried sending an invisible one and using it's position periodically but that has not worked. Is there a resource that I could not find that would get this done?
     
  2. xniinja

    xniinja

    Joined:
    Mar 12, 2011
    Posts:
    230
    Does the projectile use gravity? If it doesn't use gravity then you should be able to do a Raycast or Linecast straight out from where it will be shot.
     
  3. RingOfStorms

    RingOfStorms

    Joined:
    Oct 23, 2010
    Posts:
    584
    it does use gravity
     
  4. gfoot

    gfoot

    Joined:
    Jan 5, 2011
    Posts:
    550
    Is your problem with calculating the trajectory or drawing the lines?
     
  5. RingOfStorms

    RingOfStorms

    Joined:
    Oct 23, 2010
    Posts:
    584
    just about both, I need to be drawing lines and calculating trajectories drawing them in real time, since the user can move his mouse (or finger in the future).
     
  6. Vanamerax

    Vanamerax

    Joined:
    Jan 12, 2012
    Posts:
    938
  7. RingOfStorms

    RingOfStorms

    Joined:
    Oct 23, 2010
    Posts:
    584
    This mainly talks about the physics and such but nothing on how to do a prediction line, the formula does not plot any points on a trajectory for a line to be rendered on, so any other ways?
     
  8. RingOfStorms

    RingOfStorms

    Joined:
    Oct 23, 2010
    Posts:
    584
    Is there a way to use a formula to create 3D points that would enable you to draw A line through? (Using a prefabs mass and the force that it will be shot at etc).
     
  9. Bluntweapon

    Bluntweapon

    Joined:
    Feb 24, 2012
    Posts:
    158
    I think a LineRenderer is still your best bet. Exactly what is the problem with getting it to draw a line? As far as I know it only uses an array of Vector3, so you can just plug the points in.
     
  10. RingOfStorms

    RingOfStorms

    Joined:
    Oct 23, 2010
    Posts:
    584
    The problem is getting the array of points, they don't just magically appear unfortunately. I need a way to update the line of points in real time, that is the problem.
     
  11. Morning

    Morning

    Joined:
    Feb 4, 2012
    Posts:
    1,141
    Do you need to update the line(aka you already have the math to calculate it) or do you not have anything yet? Is the object using physics or do you just need to move it in a curve?
     
  12. RingOfStorms

    RingOfStorms

    Joined:
    Oct 23, 2010
    Posts:
    584
    I need to update the line and the ball is using physics, but there is no way to get points for a line to be rendered on.
     
  13. Vanamerax

    Vanamerax

    Joined:
    Jan 12, 2012
    Posts:
    938
    Can't you just use a "preview" ball which gets the same effect but doesnt collide with your objects?
     
  14. RingOfStorms

    RingOfStorms

    Joined:
    Oct 23, 2010
    Posts:
    584
    That would be extremely slow and update the line like every 5 seconds, meaning it would be completely useless because the ball doesn't move that fast, it needs to be real time.
     
  15. gfoot

    gfoot

    Joined:
    Jan 5, 2011
    Posts:
    550
    If you know the start point and initial velocity, then you can advance a virtual particle repeatedly by arbitrary time deltas and draw lines between the points. For every time T, the particle moves T * velocity.x in the X direction - that's the same throughout the motion. So if you want to evaluate a specific number of points along the line, over a certain X distance, you can use this relationship backwards to get a sensible time delta between points.

    Then the one-dimensional formulae for the iterations are:

    Code (csharp):
    1.  
    2. newPosition.x = oldPosition.x + velocity.x * timeDelta;
    3. newPosition.y = oldPosition.y + velocity.y * timeDelta - 0.5f * gravity * timeDelta * timeDelta;
    4. newVelocity.y = oldVelocity.y - gravity * timeDelta;
    5.  
    where 'gravity' is a positive downwards acceleration. You can collapse that down using vectors, if you like, to:

    Code (csharp):
    1.  
    2. position += velocity * timeDelta + 0.5f * gravity * timeDelta * timeDelta;
    3. velocity += gravity * timeDelta;
    4.  
    where gravity is now a vector, e.g. (0, -1). It all works fine in 3D too, and this calculation is cheap.

    So given this, you just need a way to draw lines between the points - e.g. a LineRenderer. It's really easy to set the number of points in the line and provide the coordinates for that.
     
  16. RingOfStorms

    RingOfStorms

    Joined:
    Oct 23, 2010
    Posts:
    584
    @gfoot, I looked at this for some time now and am completely clueless on how to use what you said.

    How do I get the velocity for those equations?

    I also don't really get how to use it so is there a better way to explain, and it needs to be 3 dimensional not just 1 dimensional.
     
  17. JoeGtake2

    JoeGtake2

    Joined:
    Apr 19, 2012
    Posts:
    29
    Just a thought...sort of a cheap way to do it (but pretty stupid simple) might be the 'invisible object' method leaving a particle trail? I only think of it because I often have created melee weapon trail which sort of decays over time and I could see it being a cool potential way to achieve the same effect. It might even be cool to produce a new 'invisible object' every second or so so that the trajectory prediction sort of 'pulses'.

    I have no idea if that will work for your needs, but it might be at least a cool looking temporary solution? Good luck!
     
  18. RingOfStorms

    RingOfStorms

    Joined:
    Oct 23, 2010
    Posts:
    584
    Someone already said that and again the ball shoots at a slower speed than I want the line to update, if it was with the ball it would take up to 10-20 seconds for a Real time line to update, in which case it would be useless, so I need to use a formula or sorts that can update real time.
     
  19. Marrrk

    Marrrk

    Joined:
    Mar 21, 2011
    Posts:
    1,032
    Assuming you use the LineRenderer you can do this:

    Code (csharp):
    1.  
    2. void UpdateTrajectory(Vector3 startPos, Vector3 direction, float speed, float timePerSegmentInSeconds, float maxTravelDistance)
    3. {
    4.     var positions = new List<Vector3>();
    5.     var lastPos = startPos;
    6.    
    7.     positions.Add(startPos);
    8.    
    9.     var traveledDistance = 0.0f;
    10.     while(traveledDistance < maxTravelDistance)
    11.     {
    12.         traveledDistance += speed * timePerSegmentInSeconds;
    13.         var hasHitSomething = TravelTrajectorySegment(currentPos, direction, speed, timePerSegmentInSeconds, positions);
    14.         if (hasHitSomething)
    15.         {
    16.             break;
    17.         }
    18.         var lastPos = currentPos;
    19.         currentPos = positions[positions.Count - 1];
    20.         direction = currentPos - lastPos;
    21.         direction.Normalize();
    22.     }
    23.    
    24.     BuildTrajectoryLine(positions);
    25. }
    26.  
    27. bool TravelTrajectorySegment(Vector3 startPos, Vector3 direction, float speed, float timePerSegmentInSeconds, List<Vector3> positions)
    28. {
    29.     var newPos = startPos + direction * speed * timePerSegmentInSeconds + Physics.gravity * timePerSegmentInSeconds;
    30.    
    31.     RaycastHit hitInfo;
    32.     var hasHitSomething = Physics.Linecast(startPos, newPos, out hitInfo);
    33.     if (hasHitSomething)
    34.     {
    35.         newPos = hitInfo.position;
    36.     }
    37.     positions.Add(newPos);
    38.    
    39.     return hasHitSomething;
    40. }
    41.  
    42. void BuildTrajectoryLine(List<Vector3> positions)
    43. {
    44.     lineRenderer.SetVertexCount(positions.Count);
    45.     for (var i = 0; i < positions.Count; ++i)
    46.     {
    47.         lineRenderer.SetPosition(i, positions[i]);
    48.     }
    49. }
    50.  
    You can also add, air friction and what not to make it more realistic, also you should add some checks to not hit yourself when building a trajectory segment.

    The code is not tested.

    You can use it like this:

    Code (csharp):
    1.  
    2. lineRenderer.useWorldSpace = true;
    3. ...
    4. void Update()
    5. {
    6.   UpdateTrajectory(transform.position, transform.forward, bulletSpeed, 0.1f, 100.0f);
    7. }
    8.  
    Be careful when changing the both last parameters as thos can greatly influence the performance needed. maybe its a good idea to not call it inside Update, but call it inside a repeating coroutine.

    You should also try to change the trajectory segment calculations according to your needs. As it does not make use of velocity or something like this.

    Greetings
     
    Malbers and wmadwand like this.
  20. gfoot

    gfoot

    Joined:
    Jan 5, 2011
    Posts:
    550
    You were about to shoot a projectile, right? How fast were you going to fire it, in which direction? That's the initial velocity.

    The one-dimensional version is perhaps easier to understand, but the vector version works in any dimensions.

    If you attach a properly-configured LineRenderer to the object that's doing the visualization, then you just need something like this, to update the LineRenderer with a new path:

    Code (csharp):
    1.  
    2. void UpdateTrajectory(Vector3 initialPosition, Vector3 initialVelocity, Vector3 gravity)
    3. {
    4.     int numSteps = 20; // for example
    5.     float timeDelta = 1.0f / initialVelocity.magnitude; // for example
    6.  
    7.     LineRenderer lineRenderer = GetComponent<LineRenderer>();
    8.     lineRenderer.SetVertexCount(numSteps);
    9.  
    10.     Vector3 position = initialPosition;
    11.     Vector3 velocity = initialVelocity;
    12.     for (int i = 0; i < numSteps; ++i)
    13.     {
    14.         lineRenderer.SetPosition(i, position);
    15.  
    16.         position += velocity * timeDelta + 0.5f * gravity * timeDelta * timeDelta;
    17.         velocity += gravity * timeDelta;
    18.     }
    19. }
    20.  
    That should be enough to draw a basic trajectory.
     
    cdr9042, IsaacPage, psromero6 and 6 others like this.
  21. RingOfStorms

    RingOfStorms

    Joined:
    Oct 23, 2010
    Posts:
    584
    @Marrrk, thanks your example has gotten me the closest! It isn't 100% accurate yet but it is now showing the line and it updates in real time! It looks really cool, I need to work out the numbers to make sure it works properly,

    Does this take in account for drag, and if it doesn't how would I add that in (I think that's what is wrong atm).?
     
  22. Marrrk

    Marrrk

    Joined:
    Mar 21, 2011
    Posts:
    1,032
    No my calculation is very basic, gfoots calculation is more advanced than mine. You can migrate it easily.
     
  23. RingOfStorms

    RingOfStorms

    Joined:
    Oct 23, 2010
    Posts:
    584
    Ok so for gfoot he has an Vi (initial velocity), atm I have two things which would be the speed and a Quaternion.Euler,

    How do I combine the Euler and the speed into a vector3 velocity?
     
  24. calebhc

    calebhc

    Joined:
    Feb 11, 2013
    Posts:
    13
    @gfoot Thanks for sharing this! Works perfect for showing the trajectory! :)
     
  25. Hash-Buoy

    Hash-Buoy

    Joined:
    Jan 4, 2014
    Posts:
    33
    @gfoot Thanx a Lot !!! It works liked like a charm.

    For those whose trajectory is still not 100% accurate , try the following things :-
    1) set the drag and friction to zero
    2) DONOT USE AddForce() , instead directly assign a velocity to the rigidBody as
    rigidbody.velocity = new vector3(0,10,10);
    3) As I was reusing the same rigid body several times , I had to go through some extra steps
    a) set velocity of the body to zero
    b) transform body to desired location
    c) again assign velocity to the body as discussed in the 2nd step.
    4) USE FixedUpdate() instead of Update().
     
    Last edited: Jan 4, 2014
  26. BjoUnity3d

    BjoUnity3d

    Joined:
    Jul 24, 2012
    Posts:
    60
    gfoot nailed it. I have been messing with this for a while. The code I found on other threads didn't have the physics right. Thanks for the extra tips Hash Buoy those are important to remember. I'm going to make a visible trajectory prediction path out of spheres like in later versions of Angry Birds. I've already tested gfoot's code and it predicts the path correctly so the rest will be really easy :)
     
  27. Rachan

    Rachan

    Joined:
    Dec 3, 2012
    Posts:
    781
    Thanks so much gfoot!!
    I follow Hash Buoy tips and testing by shooting riggidbody every update
    this is look so accurately!!!

    Screen Shot 2557-06-26 at 11.29.33 PM.png
     
  28. AndrewRyan

    AndrewRyan

    Joined:
    Apr 7, 2014
    Posts:
    19
    Thanks gfoot. This code is perfect.

     
  29. sadiqbasha

    sadiqbasha

    Joined:
    Jun 4, 2015
    Posts:
    1
    i have a error in this line UpdateTrajectory(transform.position, transform.forward, bulletSpeed, 0.1f, 100.0f); in update of this code..... pls help.......
     
  30. esnho

    esnho

    Joined:
    Dec 22, 2013
    Posts:
    2

    This is great! But, how can I add a constant force? I've tryed simply using a the "relative force" and adding it's vector value to gravity but it doesn't works.
     
  31. gfoot

    gfoot

    Joined:
    Jan 5, 2011
    Posts:
    550
    Divide your force by the mass of the object to get the acceleration, and add it on to gravity, then it should work.
     
  32. esnho

    esnho

    Joined:
    Dec 22, 2013
    Posts:
    2
    Works like a charm, here is the code

    Code (CSharp):
    1. void UpdateTrajectory ( Vector3 initialPosition, Vector3 initialVelocity, float mass, Vector3 gravity, Vector3 wind ) {
    2.         int numSteps = 100; // for example
    3.         float timeDelta = timeDeltaK / initialVelocity.magnitude; // for example
    4.  
    5.         Vector3 gravityWind = gravity + (wind / mass);
    6.  
    7.         LineRenderer lineRenderer = GetComponent<LineRenderer>();
    8.         lineRenderer.SetVertexCount( numSteps );
    9.  
    10.         Vector3 position = initialPosition;
    11.         Vector3 velocity = initialVelocity;
    12.         for ( int i = 0; i < numSteps; ++i ) {
    13.             lineRenderer.SetPosition( i, position );
    14.  
    15.             position += velocity * timeDelta + timeDeltaKADD * gravityWind * timeDelta * timeDelta;
    16.             velocity += gravityWind * timeDelta;
    17.         }
    18.     }
     
  33. Yapa

    Yapa

    Joined:
    Oct 24, 2014
    Posts:
    1
    Wow, cool, thanks for sharing!
     
  34. VermiVermi

    VermiVermi

    Joined:
    Nov 18, 2016
    Posts:
    1
    @Hash-Buoy hi, not sure I understood your p.2 about AddForce. I'm getting not that accurate trajectory after a couple of spins around a black hole that applies force to my projectile each FixedUpdate. I tried to change it to velocity in this way:
    var force = GetForce(_projectileCollider.transform.position);
    //rigidBody2D.AddForce(force, ForceMode2D.Force);
    rigidBody2D.velocity += (Vector2) force * Time.fixedDeltaTime / rigidBody2D.mass;

    But it didn't really fix the problem. I have linear drag and angular drag both set to 0. What else can it be?
     
  35. Gerto

    Gerto

    Joined:
    Apr 26, 2014
    Posts:
    1
    Great and very helpfull thread. In case anyone else finds this and wants to add drag this seems to work:
    When using the code from @gfoot , after velocity += gravity * timeDelta; add
    Code (CSharp):
    1. velocity *= Mathf.Clamp01(1f - drag * timeDelta);
    Disclaimer: I'm still trying to wrap my head around this so this may not be ideal, but it's what's working for me. Pretty sure you don't even need the Clamp01.
     
  36. MESSI007

    MESSI007

    Joined:
    Feb 18, 2017
    Posts:
    4
    here my code may help you
    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;

    public class projectilePathController:MonoBehaviour {
    [SerializeField]
    LineRenderer pathRendrer;
    Vector3 calculatedPosition;
    float Xstep, Ystep;
    private GameObject[] trajectoryPoints;
    [SerializeField]
    GameObject oneTrajectoryPoint;
    [SerializeField]
    int numberOfTrajectoryoPoint;
    Vector3 scaleInitial;
    void Awake()
    {
    scaleInitial = oneTrajectoryPoint.transform.localScale;
    trajectoryPoints = new GameObject[numberOfTrajectoryoPoint];
    for(int i=0;i< numberOfTrajectoryoPoint; i++)
    { trajectoryPoints =(GameObject) Instantiate(oneTrajectoryPoint);
    trajectoryPoints.transform.localScale = scaleInitial/(i*0.05f+1);
    }
    }
    public void drawPath(Vector3 pStartPosition, Vector3 pVelocity,float gravity)
    {
    //pVelocity,= velocity from force / mass of rigidbody

    float fTime = 0;
    print("velocity at path drawer =" + pVelocity);
    for (int i = 0; i < numberOfTrajectoryoPoint; i++)
    {
    float dx = pVelocity.x * fTime ;
    float dy = pVelocity.y * fTime - (Physics2D.gravity.magnitude * fTime * fTime / 2.0f);
    calculatedPosition = new Vector3(pStartPosition.x + dx, pStartPosition.y + dy, 2);

    trajectoryPoints.transform.position = calculatedPosition;
    fTime += 0.05f;
    }
    }
    public void showHide(bool toShow)
    {
    for (int i = 0; i < numberOfTrajectoryoPoint; i++)
    {
    trajectoryPoints.active = toShow;
    }
    }

    }
     
  37. Yiorgos

    Yiorgos

    Joined:
    Jun 5, 2013
    Posts:
    26
    Any chance to elaborate a bit on the "properly-configured LineRenderer"? I got my LineRenderer component, I added a material with a texture, the Positions array is filled with data on runtime but I don't see anything...
     
  38. Sproud346

    Sproud346

    Joined:
    Aug 3, 2017
    Posts:
    3
    @Rachan can you please share your exact code and any other useful information to obtain the output linerender image you shared? i cannot.
     
  39. Pawl

    Pawl

    Joined:
    Jun 23, 2013
    Posts:
    113
    If you're using Physics2D, don't forget to multiply Physics2D.gravity by your RigidBody2D's gravityScale property in the projectile prediction equation!
     
  40. liccarry

    liccarry

    Joined:
    Jul 25, 2019
    Posts:
    2