7
\$\begingroup\$

I am creating a jump'n'run game using the Box2D physics engine. The main character should be a robot like creature without legs, floating over the ground powered by a jet engine.

The motion should look like that of a flying saucer: The creature never touches the ground, but also never gets too far from it. What construction of joints, shapes and bodies can do that nicely?

I started by trying to make a kind of pendulum:

     O        <-- head
     |
    +-+
    |X|       <-- creature's body
    +-+
 ----+-----   <-- ground (pendulum crossing)
     |
     O        <-- heavy body, weld joined to the creature, it does
                  collides with nothing, just pulling the creature
                  down to keep it upright

However, that isn't working smoothly and the creature bounces around too much. Besides, how can I simulate the jet engine nicely?

\$\endgroup\$
14
+50
\$\begingroup\$

UPDATE: over the years I've become a bit more knowledgeable, and I realized Setup 2 can be modeled in a simpler way. I've added Setup 3, which I believe is the best solution.

Your question inspired me to play around with the RUBE editor to find a nice solution. Here's what I came up with:

Setup 1

RUBE UFO 1

Let's start with the simpler one on the left. It has the following setup (from the bottom up):

  1. A wheel body that can roll back and forth
  2. A small box (chassis) attached to the wheel via a b2RevoluteJoint. The chassis body is not allowed to rotate.
  3. A main UFO body (no rotation)
  4. A b2PrismaticJoint connecting the centers chassis and UFO body (this makes sure the UFO is always upright)
  5. A b2DistanceJoint connecting the centers of the chassis and the UFO body. This allows the UFO to bob up and down and eventually settle on a set distance from the chassis (how fast this happens depends on the frequency and damping ratio).

The result:

UFO1 gif

The idea would be to only render the ufo part, and use collision filtering so the rest of the physics in your game (with the exception of the ground) does not interact with the wheel part. In the gif you can see that the wheel doesn't climb over other bodies (as it shouldn't), so if you want to include steps in your game then you need to add hidden ramps and/or change the shape of the physics ground so that the wheel can climb up the steps.

Setup 2

If you want more than just vertical motion, then I recommend the second setup: enter image description here

This case is the same as the first, with the following ammendments:

  1. b2Distance and b2PrismaticJoints from before are now connected to a small, intermediate body which still has rotation disallowed.
  2. The new intermediate body is connected via b2RevoluteJoint to the main UFO body. The UFO body is now allowed to rotate.
  3. In order to constrain the UFO body from freewheeling, we need to stabilize it. Fortunately the method for doing so was already determined in this answer. The four distance joints are attached to the main UFO body and the new intermediate body. However, when playing around with the UFO in RUBE, I noticed that the parallel distance joint configuration as suggested in that answer was unstable, and it kept 'snapping' into the cross configuration seen in the above image. Since that was much more stable, I decided to go with it.

The result:

UFO2 gif

Setup 3

Setup 2 is a little bit complicated, and a slightly better setup can be achieved with fewer bodies and joints:

UFO 3

  1. Wheel, same as before.
  2. This time around, the wheel is connected to body 3 using a b2WheelJoint. This negates the need for the chassis body from the first two setups. The PrismaticJoint is also no longer needed, as its behavior is built in to the b2WheelJoint.
  3. A small intermediate body is still needed to connect the wheel to the main body. This body has the fixed rotation flag set for two reasons: it keeps the UFO upright (by fixing the vertical axis between the wheel and itself) and it provides the constant reference angle for the main body.
  4. The small body at position 3 is connected to the main body through a b2WeldJoint. The b2WeldJoint is primarily used to 'glue to bodies together', but here the constraint can be made soft by selecting the frequency and damping in a similar manner to the b2DistanceJoint.
  5. The main UFO body.

UFO 3 gif

This setup has done away with 3 joints and 1 body compared to Setup 2. All of the joint anchors are now placed in logical locations on the model, as opposed to those floating b2DistanceJoint anchor positions in Setup 2, which should be much simpler to construct and debug in actual game code. Finally, Setup 3 also has the bonus of not over shooting when the wheel runs into a barrier; notice how in the Setup 2 the UFO body overshoots the wheel position an snaps back when the wheel runs into an obstacle at high speed? The bottom b2RevoluteJoint is separating under the load. This doesn't happen to the b2WheelJoint in Setup 3.

Whatever you end up doing, I highly recommend trying it out in RUBE, its a great way to try and find fun feeling physics solutions.

\$\endgroup\$
  • \$\begingroup\$ Thanks for that cool answer, I gonna check that out! BTW.: I already have RUBE and I already played with it… \$\endgroup\$ – philipp Mar 23 '14 at 7:54
  • \$\begingroup\$ That's cool, works really nice! \$\endgroup\$ – philipp Mar 23 '14 at 17:33
  • \$\begingroup\$ No problem, glad I could help :) \$\endgroup\$ – NauticalMile Mar 23 '14 at 18:37
3
\$\begingroup\$

NauticalMile's answer is great (and bonus points for the killer animated diagrams). To give an alternate suggestion that doesn't suffer from the same problems (the wheel collision stopping you from moving past objects that a floating body should be able to traverse effortlessly, I suggest modelling something more closely matched to the reality of your situation. I.e. don't use rigid body collision and springs.

Model your character as a rigid box as normal, but every update do a raycast directly downwards (in the direction of your jet thrust) and measure the distance from the character to the nearest collidable object. Then, apply an upward impulse to your character's body, inversely proportional to the distance from the ground. So the closer you are to the ground, the larger the impulse. That can be a linear proportion, or an exponential proportion, but you don't want it to be too large (i.e. shooting off into the sky) so you'll want to damp it beyond a certain range. But basically it should achieve equilibrium against the effects of gravity, to give the effect of a spring - the closer you get to the ground, the more energy the spring imparts, the further away the less it boosts you. Combined with a damping factor on the motion, you should achieve a balance point some height off the 'ground'.

NB: this force should be constrained to only act vertically on your body, otherwise you start getting into real-world issues where your character is unstable and wants to lurch forwards or backwards depending on what's underneath or what angle the character is at.

Jumping is then simply adding an extra vertical factor to that force - you can't jump infinitely high, but it does have the extra nuance that if you time the jump right (say just after dropping down from a height), you can get extra height on the jump by taking advantage of the bounce effect.

This should have the effect of allowing smooth motion over small obstacles without taking anything away from your horizontal velocity. As the obstacle comes under the jet raycast, the character will shift upwards, but not slow down at all.

Actually, a single raycast may be unstable, especially if you're moving over rough terrain. I'd perhaps do two or three raycasts and take an average of the distance; weighting it if you want to maybe, or discarding measurements outwith a certain deviation from the average. What you're don't want a case where the character moves over a very slim gap in an otherwise flat surface in the world and drops downward sharply because the ray happened to pierce right into that gap.

\$\endgroup\$
  • 1
    \$\begingroup\$ +1 I am also a big fan of modelling game mechanics closely based on their physical behaviour. This is another good way to do it. The trade-off however is the determinism of the behaviour. For example, what happens if the ship manages to get flipped upside-down? There are always going to be little issues like this that we need to predict and contend with. \$\endgroup\$ – NauticalMile Mar 25 '14 at 13:54
  • 1
    \$\begingroup\$ Now that I think about it, there could be an even better way: what if, instead of the wheel joint, you do 3 raycasts from the ufo like you said, but instead of a single UFO body, you use the distance joints from my answer attached to a non-rotating core. That way you could have (almost) certain stability, allow the ufo to wobble, and avoid the terrain climbing issues from my answer. Thoughts? \$\endgroup\$ – NauticalMile Mar 25 '14 at 14:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.