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?
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.
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).
I've read a blog about something similar a while ago. It can be found here: http://www.sauropodstudio.com/dev-diary-number-eight/ I hope this can be some help to you
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?
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).
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.
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.
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?
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.
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.
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): newPosition.x = oldPosition.x + velocity.x * timeDelta; newPosition.y = oldPosition.y + velocity.y * timeDelta - 0.5f * gravity * timeDelta * timeDelta; newVelocity.y = oldVelocity.y - gravity * timeDelta; where 'gravity' is a positive downwards acceleration. You can collapse that down using vectors, if you like, to: Code (csharp): position += velocity * timeDelta + 0.5f * gravity * timeDelta * timeDelta; velocity += gravity * timeDelta; 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.
@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.
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!
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.
Assuming you use the LineRenderer you can do this: Code (csharp): void UpdateTrajectory(Vector3 startPos, Vector3 direction, float speed, float timePerSegmentInSeconds, float maxTravelDistance) { var positions = new List<Vector3>(); var lastPos = startPos; positions.Add(startPos); var traveledDistance = 0.0f; while(traveledDistance < maxTravelDistance) { traveledDistance += speed * timePerSegmentInSeconds; var hasHitSomething = TravelTrajectorySegment(currentPos, direction, speed, timePerSegmentInSeconds, positions); if (hasHitSomething) { break; } var lastPos = currentPos; currentPos = positions[positions.Count - 1]; direction = currentPos - lastPos; direction.Normalize(); } BuildTrajectoryLine(positions); } bool TravelTrajectorySegment(Vector3 startPos, Vector3 direction, float speed, float timePerSegmentInSeconds, List<Vector3> positions) { var newPos = startPos + direction * speed * timePerSegmentInSeconds + Physics.gravity * timePerSegmentInSeconds; RaycastHit hitInfo; var hasHitSomething = Physics.Linecast(startPos, newPos, out hitInfo); if (hasHitSomething) { newPos = hitInfo.position; } positions.Add(newPos); return hasHitSomething; } void BuildTrajectoryLine(List<Vector3> positions) { lineRenderer.SetVertexCount(positions.Count); for (var i = 0; i < positions.Count; ++i) { lineRenderer.SetPosition(i, positions[i]); } } 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): lineRenderer.useWorldSpace = true; ... void Update() { UpdateTrajectory(transform.position, transform.forward, bulletSpeed, 0.1f, 100.0f); } 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
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): void UpdateTrajectory(Vector3 initialPosition, Vector3 initialVelocity, Vector3 gravity) { int numSteps = 20; // for example float timeDelta = 1.0f / initialVelocity.magnitude; // for example LineRenderer lineRenderer = GetComponent<LineRenderer>(); lineRenderer.SetVertexCount(numSteps); Vector3 position = initialPosition; Vector3 velocity = initialVelocity; for (int i = 0; i < numSteps; ++i) { lineRenderer.SetPosition(i, position); position += velocity * timeDelta + 0.5f * gravity * timeDelta * timeDelta; velocity += gravity * timeDelta; } } That should be enough to draw a basic trajectory.
@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).?
No my calculation is very basic, gfoots calculation is more advanced than mine. You can migrate it easily.
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?
@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().
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
Thanks so much gfoot!! I follow Hash Buoy tips and testing by shooting riggidbody every update this is look so accurately!!!
i have a error in this line UpdateTrajectory(transform.position, transform.forward, bulletSpeed, 0.1f, 100.0f); in update of this code..... pls help.......
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.
Divide your force by the mass of the object to get the acceleration, and add it on to gravity, then it should work.
Works like a charm, here is the code Code (CSharp): void UpdateTrajectory ( Vector3 initialPosition, Vector3 initialVelocity, float mass, Vector3 gravity, Vector3 wind ) { int numSteps = 100; // for example float timeDelta = timeDeltaK / initialVelocity.magnitude; // for example Vector3 gravityWind = gravity + (wind / mass); LineRenderer lineRenderer = GetComponent<LineRenderer>(); lineRenderer.SetVertexCount( numSteps ); Vector3 position = initialPosition; Vector3 velocity = initialVelocity; for ( int i = 0; i < numSteps; ++i ) { lineRenderer.SetPosition( i, position ); position += velocity * timeDelta + timeDeltaKADD * gravityWind * timeDelta * timeDelta; velocity += gravityWind * timeDelta; } }
@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?
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): 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.
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; } } }
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...
@Rachan can you please share your exact code and any other useful information to obtain the output linerender image you shared? i cannot.
If you're using Physics2D, don't forget to multiply Physics2D.gravity by your RigidBody2D's gravityScale property in the projectile prediction equation!