Saturday, July 9, 2011

You're grounded!

I spent time last night working on the motion of the player body in my game last night.  I wanted the effect of moving him around to be that when he is grounded, he moves at a certain speed.  If he jumps and is moving, he continues at that speed in the x-direction and if the player tries to move him while airborne, it's possible but the motion is minimal.  I also wanted quick left / right motions if the body was on the ground.

To achieve this, I have a sensor fixture in the form of a circle on the bodies lower half.  I got this idea from Mario Z.'s physics demo doing something similar.  I use the contact listener and a counter to detect when the sensor is touching or not touching something.  In other words, when a beginContact event occurs for the sensor, it ratchets up a counter.  When an endContact event occurs, it ratchets the counter down.  When the counter reaches 0, the body is considered to be airborne.  This works out pretty well.

Body motion is checked every iteration and its velocity is adjusted if the user is pressing the left or right button.  If the body is airborne, the amount of the velocity is reduced.  If the user is not pressing a motion button and the body is grounded, it immediately stops.  Else, if it is airborne, no change to the velocity is made.  This is working out pretty well. 

Oh yeah, the player presses a button to jump.  This causes an upward impulse to be applied to the body.  If the body is in the air, then the jump button is ignored.  Easy peasy.

This is working out really well, but I need to do some adjustment to the friction when the character flies across the screen at a high rate (such as leaping off a high ledge).  I'm going to attempt to adjust the amount of friction as a persistence from being grounded -- the first short bit after coming down from being airborne will have a low friction then friction will be increased back to normal levels.  I need to play with things to see how that looks and feels.

Friday, July 8, 2011

Slow but steady

I've been making slow but steady progress on the game.  Since I've got a good chunk of the components defined and the majority of operations working, I decided to commit some time to making levels.  The levels range from easy / introductory type stuff to more complicated / tricky solutions.  After about two hours of effort last night, I now have  20 levels defined.  Ideally like to come up with about a hundred (if not more).

Today's main accomplishment was refactoring.  Since things are going to be level based, I needed a frameworks supporting this as well as the capability to have various menus.  The frameworks I created was derived after studying how Mario Zechner (libgdx guru) implemented his SuperJumper.  The concept is fairly simple.  You have two primary objects: the game object and screen objects.  The game object is the ApplicationListener of libgdx and kicks off the very first screen.  The screen objects are really simplified ApplicationListeners themselves, but controlled from the context of the game object.  They have a lot of the same methods that you find in the ApplicationListener.  Rather than having a single render() method, each screen has an update() and present() method, which are called from the game object's render() method.  The update() is for game engine operations while present is for doing all your graphical work.

In this way, you have a separate screen for each activity you want to implement: main screen, help screen, splash screen, game play screen, and so on.  At the moment, I only have a PlayScreen, but at least I have the frameworks in place to allow for the multiple screens you see in your typical games.

Thursday, July 7, 2011

Grapple gun & raycasting

Grapple gun

I implemented the grapple gun as mentioned below and it works semi-perfectly.  I discovered that joint lists are independent, whereas I assumed they'd be inter-related.  Iterating through the player body only gives me the joint for the gun.  For some reason, I expected to see the joint between the gun and the grappled object.  Not so!

I don't limit the gun's range of motion (it runs from 0..360) and have given it a HUUGE torque.  Much hilarity ensues when you grapple an object and then try to move the object through the player body.  Jumps and leaps of enormous proportions!

Raycasting

The raycasting took a little while to figure out -- I had to break out the code for the Ray-Tracing that is in the Box2D testbed demo.  First off, I had to implement this via a callback giving the start and end points of a ray projected out from the gun.  Easy enough.  Just have to do some rotations and transforms to get the ray to start where the gun is situated.  The next part was a learning experience... I was able to grapple through walls which didn't make sense.

The reason behind this is that the callback you supply is not guaranteed to return the nearest object the ray encounters.  You have to set it up to return a fractional amount as an indicator to the caller.  This clips the ray to that point.  If there is an object further out that hasn't been reported, it will not be reported.  If there is an object closer that hasn't been reported, the callback should iterate again with that object, at which point you again return a fractional amount to clip things.  Note -- this is only if you want to locate the nearest object.  Other return values will get you different results.

See below for the player / gun body grappling a circle body.

Box2D contact listener vs solver: The Showdown

I noticed something unusual as I was testing out my map today.  I was debugging my contact listener's beginContact() method, displaying the velocity that was being reported as an object struck a pad object.  If you've been following this blog, you'll know that I take the contacts and place them in an array for later processing.  I then displayed the velocity of the object during the array processing step. THE VELOCITIES FOR THAT SAME OBJECT WERE VERY DIFFERENT.

This was not expected.  I knew that the object may have been traveling fast enough where it may have contacted the ground below the pad and attribute the difference to that.  However, the net effect I wanted was for the velocity to remain unchanged.  Upon further investigation of the Box2D physics, I saw that its Collide() method (which calls the contact listener), executes BEFORE the Solve() method.  In other words, the contact is detected and the object's speed is valid at that point of impact.  However, the solver comes along and adjusst the velocity of the object before my game engine's processing step is able to do anything about it.  Oh yeah?!  We'll see ABOUT THAT!  Heh.

To get around this, I added a velocity vector to my processing array so that I could record what the velocity was at the point of impact.  Things are now happening the way I want them too.  Woot!

Grapple gun and other stuff

Grapple Gun:

The next thing on the list to do is to make a grapple gun that can move objects around in my world.  The idea I have in mind is to take the angle of the 'gun' object, shoot a ray out from it and determine if it hits an object.  If it hits a dynamic object that is 'grapple-able' (value configured via user data settings), project it out a certain distance away from the grapple gun to serve as an anchor point and then create a revolute joint between it and the gun.  When the user decides to drop it, simply destroy the joint.  The object should stay with the facing of the gun due to the joint. 

There are a couple of unknowns -- whether the libgdx Box2D port supports raycasting (if it didn't, that would suck) and whether I need to have a joint as part of a fixture or if it's okay to let it hang in the air (I think it should be ok, but I need to experiment.)

Other stuff:

I learned yesterday that the libgdx Box2D does NOT support contacts based on bodies (see section 9.3 of the Box2d manual.)  You cannot do a myBody.getContactList().  The closest you can get is iterating over all of the world's contacts via myWorld.getContactList().  That sucks.  To work around this, I implemented some contact array lists associated with specific objects whose elements either get removed from the list when acted upon or the endContact() method gets executed, otherwise they get re-checked on the next update iteration of the game step.

Wednesday, July 6, 2011

A door has been opened on the Box2D project

I spent the day messing around with prismatic joints and have created a button, a door, and a wire control.  The button is a simple prismatic joint that is jointed with the bottom edge of my world's arena (hence the joint line you see in the debug rendering).  I give it a vector that indicates you need to push down on it to activate.  I made this as a class that contains some hysteresis and other modifiers that can potentially be affected by other elements in the game.  It has a small motor defined to act as the 'spring' up (ie. button not pushed).  Also included is a method that updates the button state -- it checks the translation to see if the button is pressed or not.

The door is very similar, but instead contains the 'openSesame' and 'closeSesame' methods.  The motor in this case is always pushing out initially.  When the openSesame method is invoked, the motor speed is reversed and the door opens up.  When the closeSesame method is invoked, the motor speed is positive and the door closes.  The graphics below demonstrate a retractable ledge in the upper left corner using this concept (button is in the mid-right portion).

The final component is the wire control.  It's the "go between" for the button and the door.  It is created and passed references to controlling buttons and controlled doors.  Its update() method is invoked on a periodic basis.  If it detects that its button is pressed, the corresponding door is then opened.  Pretty straightforward.  The screenshots below also show a couple of objects I made to kick around in the world: a box and a ball.


Today's Box2D fun will be Prismatic Joints

Did some reading on the Box2D site and discovered that a good way to get a pressure plate / push button effect is to use prismatic joints.  I added a quick prismatic joint (via a custom push button class) to my test arena and it worked great -- just needs some tweaking to prevent bouncing, etc.  The next step will be to tie the opening / closing of a door to the button being depressed.

With all of the experimentation and exploring I've been doing lately, I've thought about maintaining all my finds / tips / tricks in a cookbook format to act as a companion to the Box2D manual.  Sure, there's the demos that are included, but it would be nice to have some written text so you don't have to work at deciphering how to implement a particular activity.