Saturday, October 29, 2016

2d - Can I jump from A to B?


I'm making some rudimentary AI for my side-scroller and I need to know whether an AI unit can reach point B from point A simply by taking a jump.


Flight trajectory of my characters is a bit unusal as they can apply force in mid-air (like in Jazz Jackrabbit 2 for example), so unlike the classic trajectory of a projectile which is about...



path that a thrown or launched projectile will take (...) without propulsion.




... I suppose that my problem is more about a projectile with propulsion (e.g. rocket).


To illustrate this, this is how the flight curve looks like for my character if I jump and continually press the "left button" (it looks different at the left end, this is where I was making some manuevers in mid-air): enter image description here


The force applied during flight is always parallel to the X axis, so it is F = (-f, 0) if I hold "left" and it is F = (f, 0) if I hold "right".


He can move very much like a ski jumper:


enter image description here


So it differs a lot from the classic trajectory which is simply a parabola (source: wikipedia):


enter image description here


To make it more difficult, I am simulating simple air resistance so my characters can accelerate only up to some maximum speed value.


This is done by applying a small force in the opposite direction of travel:


b2Vec2 vel = body->GetLinearVelocity();

float speed = vel.Normalize(); //normalizes vector and returns length
body->ApplyForce( AIR_RESISTANCE_MULT * speed * speed * -vel, body->GetWorldCenter() );

The AIR_RESISTANCE_MULT is a constant that in my case equals 0.1.


Let's assume that my character is an infinitely small point.


And I'm NOT taking obstructions into consideration, so my question goes like this...


How to determine (at least reliably guess), given initial velocity V, an impulse J = (0, -j) that I apply to the character upon jump, gravity G = (0, g), force F = (+-f, 0) continually applied during flight and AIR_RESISTANCE_MULT if we really decide to take air resistance into account (this is optional) , whether a point lies below the curve drawn by the path my character will take?


I have literally no idea where to start with the calculations and in fact, I am not necessarily interested in an exact answer; a well working hack/approximation would be great as the AI by no means needs to act perfectly.


edit: I've decided to solve this using simulation as Jason suggests, but how to handle such a case? enter image description here


Should I draw a segment from C to D and check whether the desired point lies below this segment?



Or should I binary search the timesteps between C and D to look for the point that is close enough in horizontal distance to the desired point, and only then check the vertical difference? (seems a bit overkill to me)



Answer



As you state, the best choice is to approximate, in this case using a numerical scheme. Divide time into large timesteps (say 100-300ms), and use the parabolic approximation for each timestep. The forces are the same throughout except air resistance. The parabolic path is basically for constant acceleration, but with air resistance the acceleration changes because the force depends on speed. A reasonable approximation is to treat air resistance as constant over each timestep. But using a quadratic (i.e. parabolic) approximation when integrating allows you to handle much larger timesteps. Then you just compute until a parabola crosses the desired point in the horizontal direction, and then compare the heights.


EDIT: A little more detail about the comparison. You know that over the timestep (which could be many in game frames), that the player crosses the target . Their path is described by the position where:


ax = 1/2 * accel.x
bx = velocity.x
cx = position.x

t is the time through the timestep (0 <= t <= dt) and similarly for y. So when t=0 the character is at the previous position, and when t=dt, they are at the next position. Note that this is basically the Euler update with dt replaced by t so that we can calculate anywhere along the trajectory. Now we know the x-position is a quadratic function, so we can solve ax*t^2 + bx*t + cx = targetx and get (up to) two times during the step in which the character is directly above or below the target. Then we throw out any solutions that aren't in the range [0, dt], as these aren't in the current timestep. (For robustness, add a small constant to the ends of the range so you don't have round off problems). Now we could have no solutions (after filtering), in which case we don't hit the target this timestep. Otherwise, we evaluate ay*t^2 + by*t + cy at the solutions, and compare this y with targety. Note that you could be above the target at one point in your trajectory, and below it later (or vice-versa). You'll need to interpret such situations according to what you want to do.


Considering a bunch of timesteps is much easier than finding an analytic solution to the original problem, and far more flexible as you can change the motion model and this will still roughly work.



Bonus points for using variable steps, for example, 100ms for the first second (ten points), 200ms for the next two (ten more points), 400ms over 4 seconds, etc. In fact, as your character approaches terminal velocity the variation in the resistance goes down, and you don't need larger timesteps anyway. This way you can handle really long jumps without too much processing, as the complexity for T seconds is O(log T) rather than O(T).


You can also simulate what happens when the character stops boosting partway through their jump, or starts boosting the other way. With the above trick the complexity is O((log T)^2), which isn't too bad.


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...