- Home /
Simulating a trajectory that takes collisions into account
Hi everyone,
I'm looking for a way to simulate (and later render) a shot trajectory that takes collisions into account. Imagine the trajectory arcs shown in Peggle or in pool games - you see how the shot is going to behave and interact with the world around it before you take it. This is relatively straightforward in an environment where you can create a clone of your physics world and step it X times every frame (or whenever you need to). However, I've yet to find a way to do something like this with the native box2d implementation of Unity - it seems like there is no way to create you own world object, much less step it on your own. Is there any way I can do this with Unity? If not, why?
Thanks! :)
Edit - To clarify, I'm working with the new Box2d engine on a 2d game.
If necessary you can always make your own physics. (Also there may be some existing physics code; try looking on the asset store.)
While that's theoretically true I'd really rather use a tried and tested physics engine like box2d or Chipmunk over writing my own physics code.
There is a feature request for it. If you want to vote for it: http://feedback.unity3d.com/suggestions/function-for-manually-simulating
I read your question again. Since in unity with physX it's not possible yet but with box2d for unity it is. I'm not sure if your question is about simulating physics in unitys physic engine or box2d. Do you need advice with that in b2d?
Answer by Josh707 · Dec 06, 2013 at 07:44 AM
There's nothing wrong with using your own physics code, I mean if it does what you want without looking bad or screwing up then it should be useable right? I spent some time yesterday figuring this out with linecasting and a line renderer to visualize it, and it turned out pretty good:
I noticed you meant in 2D after I took the time to figure it out, but the calculations will be pretty much identical just minus an axis. Currently the linecast is a single point so the projectile will appear to bounce from the center of the object, but I'm sure you can simulate a sphere somehow with a bit of math.
The concept is pretty simple, if you have constant values like initial velocity, position, and gravity you can predict the trajectory as long as you move the projectile with the same math. I have a vector for velocity, then a loop depend on an integer of steps like you were talking about, and every step of the loop, add gravity to the velocity as well as linecast ahead with the velocity to check for collisions. I use Vector3.reflect to mirror the velocity and dampen it with a value between 0 & 1 so it doesn't bounce indefinitely. If it doesn't hit anything, simply move the position by it's velocity. The line is constantly redrawn and each step of the loop adds a vertex to the line renderer so you can animate the line's progression by slowly incrementing the steps.
Here's a snippet of how I'm predicting it:
void FixedUpdate () {
if(predict){
last_pos = muzzle.position;
velocity = muzzle.forward * fire_velocity;
line.SetVertexCount(1);
line.SetPosition(0, last_pos);
int i = 1;
while(i < physics_steps){
velocity += gravity * Time.fixedDeltaTime;
RaycastHit hit;
if(Physics.Linecast(last_pos, (last_pos + (velocity * Time.fixedDeltaTime)), out hit)){
velocity = Vector3.Reflect(velocity * bounce_damping, hit.normal);
last_pos = hit.point;
}
line.SetVertexCount(i+1);
line.SetPosition(i, last_pos);
last_pos += velocity * Time.fixedDeltaTime;
i++;
}
}
}
And here's how I'm moving the projectile (instantiated at the muzzle position, and it's velocity is set to the same as the prediction):
void Update () {
play_speed = Time.deltaTime;
velocity += gravity * play_speed;
RaycastHit hit;
last_pos = transform.position;
if(Physics.Linecast(last_pos, (last_pos + (velocity * play_speed)), out hit)){
velocity = Vector3.Reflect(velocity * bounce_damping, hit.normal);
transform.position = hit.point;
}
transform.position += velocity * play_speed;
}
If you'd like to check out the project let me know and I'll upload it somewhere
Thanks for taking the time Josh, I'll give this a go and see if it works for me. A big potential downside I see with this approach is that it will most likely not work well with the built in box2d engine (which gives me a lot of very useful features like joints, triggers and materials).
No problem, I had fun making it. But yeah, this is better for bullets or similar that won't be colliding/rolling like a billiard ball or something. I'm sure you could get it to behave properly if it hits a rigidbody but there's probably a better approach in your situation.
Perhaps if you can find out how your 2D framework calculates rigidbody movement (gravity/drag) you could use that method to calculate the trajectory until it hits something, and just use a traditional rigidbody with forces. I'd give it a go but I don't have 2D framework and I'm waiting to update Unity. Good luck figuring this out though!
@Josh707 first, sorry to my poor english skill. i seen u'r code sniper. i have been u'r code apply to my Example code. btw, i cant understand u'r code
using UnityEngine; using System.Collections;
public class Behavior_Trajectory : $$anonymous$$onoBehaviour {
public Transform _turret;
public Transform _muzzle;
float _fireVelocity = 0f;
float _physics_steps = 0f;
Vector3 _gravity;
LineRenderer _line;
// Use this for initialization
void Start () {
_line = GetComponent<LineRenderer>();
_gravity = Physics.gravity;
}
// Update is called once per frame
void Update () {
}
void FixedUpdate()
{
Vector3 last_pos = _muzzle.position;
Vector3 velocity = _muzzle.forward * _fireVelocity;
_line.SetVertexCount(1);
_line.SetPosition(0, last_pos);
int i = 1;
while (i < physics_steps) ///<<<<< Here, how to get physics_steps?
{
velocity += _gravity * Time.fixedDeltaTime;
RaycastHit hit;
if (Physics.Linecast(last_pos, (last_pos + (velocity * Time.fixedDeltaTime)), out hit))
{
velocity = Vector3.Reflect(velocity * bounce_damping, hit.normal); //<<<<<< here, how to get bounce_damping?
last_pos = hit.point;
}
_line.SetVertexCount(i + 1);
_line.SetPosition(i, last_pos);
last_pos += velocity * Time.fixedDeltaTime;
i++;
}
}
}
summary. how to get physics_steps and bounce_damping in u'r code? thanx for read. and i wish to u read it.
Sorry for the late reply, but physics_steps
is an integer and bounce_damping
is a float which should only be between 0 and 1. Larger than 1 will cause it to increase velocity when it bounces.
Answer by robhuhn · Dec 09, 2013 at 11:19 AM
That's a bit confusing because I was talking about a box2d plugin for Unity, not about the built-in box2d engine in 4.3. If you want to use a plugin I would recommend Farseer (Asset Store). In Farseer it's possible to setup and control the world(s):
world = new World(new FVector2(Physics2D.gravity.x, Physics2D.gravity.y));
...
void FixedUpdate ()
{
world.Step(Time.fixedDeltaTime);
}
Unfortunately you would need to map the farseer positions to your sprites manually.
Sorry for any misunderstandings.
Your answer
Follow this Question
Related Questions
Problem with a ballistic trajectory simulation (rigidbody.velocity) 0 Answers
Help with orbits 1 Answer
2D projectile trajectory prediction 2 Answers
Drawing projectile trajectory 5 Answers
How to calculate the angle of a trajectory to hit the target 1 Answer