Saturday, March 13, 2010

Character Physics

When I first started using a physics library to do collision detection/response I realized that character control wasn't really just handed to you on a plate.  I looked at how one would go about adding normal platformer controls using a physics set up and was a bit overwhelmed.  So instead of attempt it I took an easy route and made my characters rolling circles.  Granted that works for some game types but sometimes you need something a little more interesting.  I've been working on adding some platform-y controls to one of my games and figured I'd share what I learned.

The following assumes you are creating controls for a 2D game with some physics library (I recommend Box2D or Chipmunk).


Body Setup
For most games it is important to be able to detect what portion of your character's body is receiving physics callbacks, for this reason we will need to set up a few shapes to attach to our body.

  • Torso
    • main collision shape (in my case a rectangle encompassing shoulders down to bottom of the feet)
  • Head
    • for movement purposes I just want a circle to help the character shrug off his cranial injuries (not get stuck on his head when falling)
  • Feet
    • a sensor shape simple to detect when the feet are touching something
  • Bounding
    • another sensor shape to help correct orientation when fallen over (not needed if fixed orientation)




From the picture we can see these four shapes.  I have colored the physically interacting shapes as green and the sensor shapes as blue.  It is important that the foot sensing shape go beyond the interactive portion of the character so that jump detection can work smoothly.  If you'd rather your character not be able to fall over, you can always lock the orientation and the bounding box I create here is no longer needed.  The next section will detail how I use this box to help orient my character.


Standing Up
If you can get away with locking your orientation you do not need to worry about re-orienting the character.  However, if you do want your character flipping about then please read on!

Without any orientation correction, it is inevitable that your controllable character will fall over and potentially start walking with his belly or get stuck forever.  Neither of these are all that desirable for most games so we will work on helping the character stand back up.  The general idea here is that we know what orientation the body should be in and what orientation the body is in and we want to adjust the orientation to the desired one without breaking the physics simulation.  Let's look at some code.

// desired angle
 float ang_desire = std::fmod( std::atan2(m_Gravity.y, m_Gravity.x), (float)Gosu::pi * 2.0f);
 //Current angle of body
 float ang = std::fmod(m_Body->GetAngle(), 2.f * (float)Gosu::pi);
 //find difference to upright (-gravity)
 float spin = ang_desire - ang;
 if (spin > Gosu::pi) { // Angle wrapping stuff
  spin = ang_desire - (ang + 2.0 * Gosu::pi);
 }
 if (spin < -Gosu::pi) {
  spin = ang_desire - (ang - 2.0 * Gosu::pi);
 }
 //apply torque to correct
 spin = spin * m_SpinAccel; // Get our force
 spin = Gosu::clamp(spin, -m_MaxSpinVel, m_MaxSpinVel); // Clamp to min/max
 m_Body->ApplyTorque(spin);

Here I wish to orient my character to my dynamic gravity vector, so I compute the angle and normalize it to be between 0 and 2*pi;.  I then find the difference angle and normalize that to be between -pi and pi.  Now I should have the closest difference angle to my desired orientation (no rotating over 180 degrees).  I then apply an acceleration magnitude to get a force out of the difference.  Here you may want to note that we want a time-sliced force so you might want to choose an acceleration and divide it by your tick speed.  Of course if you don't mind having your acceleration in terms of 1/20th of a second or whatever your update rate is, don't worry about it.  We then clamp this to some minimum and maximum force so that the character doesn't try and spin wildly about.  Finally we apply the force to our body through the ApplyTorque method.

This can be run constantly, or maybe you want to fire it off only when necessary.  Either approach is fine, it will just affect how much torque you want to apply.  I have a little of both running in my version.  As you run around the character will try and orient himself automatically, but if you do fall over the bounding sensor is used to detect such a situation and allow the player to prop themselves up.  This is done by checking if the character is not touching the ground (foot sensor) but the bounding sensor is touching something.  The player can then press jump to apply a small impulse to the character allowing the re-orientation to take control.

Walking
Walking is fairly simple compared to re-orientation.  We simply want to push our character in some direction. Now if we want to only walk while on the ground we need to implement callbacks and keep track of contacts between the character's foot and the ground.  I will probably cover this in a later post as doing this using Box2D's current stable interface is a bit involved.  For now we can just assume we know when the character is on the ground and move accordingly.

Running
Sometimes walking just isn't fast enough and we need to get places faster but we don't have a car/airplane/trained ostrich.  So we make due with running.  For character control this usually just means a modifier key that signals your control code to up the velocity of the character.  Nothing too complicated here.

Jumping
Now what would a platformer be without jumping?  That's right, something else.  Jumping itself is pretty straight forward, we just need to push the character upward when given the signal.  Now what if we want something like Mario where the longer the button is held the higher he jumps?  Okay now we're talking!

For this, we need to keep track of button states i.e. press/held/release etc..  Let's assume we know these things (I will probably write a post on it later) and head on over to logic town.  When the jump button is first pressed we apply a large impulse to the character upward, this acts as our initial thrust and baseline jump.  We then set off a timer so we don't just let the player hold down jump and jetpack all over the level.  I usually set mine to 1/2 of a second.  Now, as long as that timer is not zero (don't forget to decrement it) and the jump key is held down we continually add a smaller thrust to the character.  I used a ratio of 1:10 for initial to sustained propulsion which seems to work fine for me.  

Extra
All this is fine and dandy but sometimes we want more, like say the ability to jump further based on current running speed or spinning around in the air or dynamically changing the animation speed with the running speed.  Really this is where you have a chance to shine and make your movement stand out.  With the basics down you should be able to add a number of things to help deepen your movement.  

And just to see all of this in action, here is a little video of my implementation at work
http://www.youtube.com/watch?v=mvcJ9I_9oww

Tuesday, March 9, 2010

What I've been up to

Alright, so maybe I'm not that great at blogging yet, or maybe I haven't felt like I've had anything to say for awhile. At any rate, I've been busy and I need to start updating this thing again. So without any more ado.

My Unnamed Game Engine
I've been working on creating a number of extensions and systems that I've found a need for to use with Gosu. It is all C++ since I don't really want to mess with wrapping most of it for Ruby (there are semi-equivalent Ruby solutions available), but in working on this I have certainly accrued quite a bit more experience with C++ and learned a nice set of tricks. The project can be found on Assembla where you will immediately be confronted with my unfinished stub documentation. Until recently, the code base has gone through several dramatic changes which made documenting anything a fairly needless task. However I will discuss a few of the major features here.

To start, I've built a simple game state system based on using a stack of states. The topmost state in the stack is sent the normal callbacks of update, render, and button events. In addition to these, there are also initialization, cleanup, pause and resume methods that are called on state transitions. These exist mainly for memory management (something I have not yet fully needed to flesh out). Just today, I added a pluggable factory implementation to aid the dynamic use of states. With this, it is now easy to create a new state that does not have to interfere with the core classes (saving compile times). It is also simple to dynamically create and push new states on at runtime, which eases my need for quick iteration through skipping titles and menus without recompiling (since I don't have hot asset loading yet). Information on this set up can be found on gamedev.net. The only problem I found with that particular example is that static member initialization order is undefined so in order to ensure that things work you must make your maker registry a pointer and create it in the registering function (this is detailed in the forum discussion).

Another large portion of the project are my graphics systems. Gosu itself already has a great interface to do 2D rendering, however I wanted to make a nice parallax rendering setup which required a few tweaks. In order to maintain a clean interface to rendering I needed to abstract the drawing code away from game objects. Otherwise each object would need to know how to translate world space coordinates into the screen, which can easily become hairy. I tried providing a translation function, but passing around a pointer to the translation module wasn't much nicer so I ended up pushing all rendering and sprite management into its own little unit. Within that unit, you can create sprites and spritesheets. Since the rendering itself is abstracted, each gameobject simply changes the state of the graphics objects to change how they are rendered within the manager. The sprite objects themselves are merely classes wrapping up the many parameters passed to Gosu's draw calls, listed here:
  • position (world space)
  • zoom factor
  • rotation angle
  • drawing layer
  • visible flag
  • scaling factors
  • image center
  • color modification
Spritesheets are a little more involved, since Gosu doesn't support them directly, but provides an interface to build sheets by returning a STL compliant container holding the Gosu::Image objects. This functionality is contained within my SpriteSheet class which adds support for cycle speed and all the same parameter functionality of Sprite. The parallax rendering is a full parallax implementation, meaning it supports the normal horizontal panning, but also vertical, zoom, and rotation. A demo of this can be viewed on YouTube.

JSON Configuration
Normally, text based configuration in games is done through XML. Personally I find XML to be bloated and goofy looking, despite its power and versatility. Instead, I chose JSON which I find much more readable even though it does not support schemas nor are there many nice libraries that take care of parsing, modification and serialization. The library I am using is TinyJSON, which seems to be disappearing from the Internet. The benefit of this sort of parser is that it is lightweight (aside from requiring Boost::Spirit) and fairly easy to use. It does not support serialization out of the box though it is easily implemented. Because of the complicated data structures used it is quite a pain to modify the data model (the structure does make it rather easy to use normally, just a pain to modify). However, both of these functionalities have been added within the project as well as a cleaner interface to obtain parsed data.

Using this, I have established a set of configuration files to direct the flow of the engine as well as tell it what assets to load and how to use them. This ranges from establishing key bindings to window size properties to level environment arrangements. At one point I added configuration support for menus, but for now I prefer to write custom menus in C++.

UI Components
This addition is a popular sort of Gosu Extension, though at the time I started making it there weren't many available (I think everyone started one at the same time). Mine is fairly simple, you create a base object that represents your game window then add objects to that. There is a draggable window component that also supports adding components, but the hierarchy doesn't go much further than that. Alongside this scheme is functionality for what I call pages. A page here is a context for the UI containers that allows the user to use a single container for multiple interface configurations that can be switched between. This is not the most elaborate or feature rich UI system, but it suits me just fine.

Physics
The final addition I will talk about here is the inclusion of box2D physics. There aren't a great number of C++ 2D physics libraries around, but even if there were box2D is a fantastic one to choose. It doesn't have too many frills which makes it easy to get started using. Plus, it is actively developed on by a number of people who know game physics. At this point, my inclusion of it within the engine is pretty minimal. I have a few callback listeners set up to notify objects of collision events, but with the upcoming new version that API will change to simplify my implementation. For the most part I haven't had too much need to wrap any particular functionality or build any crazy contraptions. So I'm going to just let those things build up over time as I need specific things. I will probably be creating a particle emission system at some point that will make use of box2D, but for now I don't really need it.

Game Projects
Now, obviously there isn't much point in building all of this if I weren't creating some games. At this moment I'm working on two projects in my spare time. The first is a reincarnation of my "Circle Game" or Hamsterball Galaxy. The point of doing this is that originally I wanted to open up level creation to the users and add several graphical tweaks to the game. These additions were limited to my implementation however since I built my levels as static arrays (holy crap) and didn't spend much time working on the graphics code. This time around, using the engine should make these things much more feasible and hopefully allow me to take the project to a higher level where I'd be more comfortable with attaching a price to it.

The other game project is just now coming out of prototype phase and into a formal birth. Sometime last year I toyed around with doing Mario Galaxy style movement in 2D and found a nice starting point to accomplish it using box2D. With that, and more brainstorming I've come to believe that this style of movement would work amazing within a Metroid style run 'n gun - dungeon crawler game. There are still some tweaks that need to be done with movement to make it squeaky clean, but things are still looking promising.

Wrap Up
This is but one side of my current status, next week-ish I will try to write a post about my graduate work.

Sunday, April 19, 2009

Walla Zombies!

So I've finished my game for the Ludum Dare contest. Today I spent a few hours fixing my graphics to not be so shoddy.


The buildings don't really match up to the scale of the characters, though I'm not really worried about that. As for code changes, I gave both the zombies and player simple momentum for knockback when being hit. For the zombies, this also helped smooth out their movement. I've also put in some simple particle effects on damage. The effect shoots out 10 colored balls which fly out in a random direction and slightly up. They have basic gravity and will bounce when hitting the ground (z=0). For the zombies, I colored them a stale red-near brown. Donuts emit brown, and the player red. This gives a nice effect and really does make the game more interesting. Another small graphical change is that characters turn more red as their health goes down. This is more visually stimulating than modifying the alpha.

A larger update added today is a melee attack. You can see from the screenshot that the character is holding a rolling pin. If zombies get too close to the character, he/she can right click the mouse to swing which will hit surrounding zombies and push them back a bit. This is nerfed to reduce players' attempts to rely on it though, by limiting the speed to 1/5 of a second and only hitting ten zombies(this also reduces some sound effects clutter as I didn't build a sound manager of any sort so sounds are played for every action).

As for optimization, I gave the zombies a timer to stall updating the field which is staggered among all of them. After the initial delay, it will reset to 5 ticks on each count down. This way, with 50 zombies on screen only 10 or so will attempt to update the field at any tick. Adding this did not seem to harm the zombie behavior, and the game no longer crawls after throwing many donuts. The targeting has also been optimized, before they would attempt to update the field for each available target that was close. Now they find the nearest object and update the vector field based on that object only.

All in all, I believe the game is a success. It started as a quirky game with some interesting developmental elements, i.e. vector fields for AI movement.

Almost forgot links to the game.
OS X application
Windows executable
Source
For linux, grab the source and install Ruby+Gosu as per the README (unless you already have it)

Saturday, April 18, 2009

Ludum Dare

So I found out yesterday that the Ludum Dare competition was Internet based (hooray for making assumptions!) and now I'm participating with the Ruby/Gosu crowd. If you are not familiar with the contest, it is a solo contest where you basically get a theme (Advancing Wall of Doom this time) then build a game from scratch (outside of several accepted frameworks for code). My idea is a combination of word play and sleep induced story.

A friend of mine jokingly said something about "walla" which turns out is a word, and a city. As a word, it means the incoherent rumble of voice that comes from a group of people. It is also a city in Washington (Walla Walla). From that, my game is a "walla" zombies in Walla Walla. The point of the game is to survive a horde of zombies by running and tossing donuts (y'know cause zombies like donuts). Don't ask why donuts, I don't know. I was half-asleep when that idea came to mind. Now, the main character is a baker and that just happens to be all that he has on hand.

For mechanics, the zombies move according to a vector field, ala Ronald C. Arkin's paper "Motor Scheme - Based Mobile Robot Navigation". The map is split into 10x10 pixel cells, with randomly initialized vectors pointing where to go. On each update, the zombies pick up this vector and move in that direction. There is a three in ten chance that they will just move randomly, adding noise to the field in case they get stuck, and to make their movement more erratic. If they are close to a target, they will build a local vector map pointing towards the target and update the map. If they are touching (very close) they will "hit" that object, which will either return 1 or -1 if that target is the player or a donut. This way they can gain health from players and lose from donuts. Over time, they will die on their own (starvation) which is the objective of the game.

Because I like making things difficult, I decided on using a simple array based collision map. Normally, this is a fair idea but instead of storing this data in an image or something convenient I just used text. This is mainly because I don't have the RMagick gem installed and don't really want to install it. I would also rather keep my Ruby dependencies to a minimum as I don't want to make it difficult for any judges to run my game. My window is 640x480 pixels, which works nicely with a 10 pixel unit space. This leaves me to author a 64x48 array of ones and zeros. To keep from driving myself mad, I'm just going to limit my game to one map and design that map so that most of the space is solidly open or blocking. From the screenshots below, you can see that the horizontal middle of the map is where most of the action is.

The engine for the game is built on top of Gosu, with a minimal state stack to separate the logic of title sequence, gameplay and credits. Using a nifty trick from another Gosu enthusiast, I've extended the core Array class to catch undefined method calls and feed them into the array elements. This makes it simple to do things such as @objects.draw

class Array
def method_missing(method, *arg)
self.each { |item| item.send(method, *arg) }
end
end
I've also extended the Image class in Gosu just to simplify calling draw with a bunch of re-used parameters, and also to enable simple animations for rotations and alpha changes.

On my laptop (1.6 GHz Pentium M, 2GB RAM, ATI x300 radeon mobility) I can easily have fifty zombies running around. Though this slows down pretty significantly with the vector field updates when you toss out several donuts. There isn't a whole lot I can do about this, as the work is being done in Ruby and I don't really have time to write some C code to fix such a specific thing.

For graphics and sound, I was initially going to use the sprites from lostgarden.com. However, using graphics not made by yourself is against the competition's rules. To cover this, I just traced over my background. Not really a good solution, but I'm fairly handicapped when it comes to art. Sound was built using GarageBand and sfxr both incredibly useful for projects like this.

To introduce the game, I created a title sequence that shows a few screens giving the backstory (the little that exists). After that there is a sequence zooming into Walla Walla starting from a view from space. To do this in 2D, I found several images starting with a picture of Earth, a colored map of the United States, a map of Washington's counties, then a map showing Walla Walla within the Walla Walla county (I'm not making this name up, I swear).

Without any further ado, here are some screenshots.










Sunday, April 5, 2009

shapes and crap

After seeing some animation of circles spawning with random colors and growing, I started making something similar with Gosu in Ruby. After showing some friends it quickly snowballed into supporting multiple shapes, rotations, random selection and cycling selection.

Basically, you need to try it to see what the hell it does.
Number keys change shape,
R turns on/off rotations,
O randomly selects shape, and
C cycles through shapes

file:///Z:/Ruby%20Projects/Circles/Circles.exe

Thursday, April 2, 2009

SDL ain't dead yet!

So I've been working on a clunky 3D OpenGL engine for my OpenGL class any for myself. As far as I'm concerned the class is just there to give me time to work on actually using all this graphics stuff I've already learned. Anyway, I'm planning on having it do a bunch of basic things;
  • load and render an obj file with a single UV mapped texture
  • load a series of images and render as a skybox without seams
  • use a grayscale image to build a terrain, and render with some texture
  • support point and directional lights
  • tie into Bullet for physics
  • use SDL for various bindings
So far I have most of these things set up, I just need some game objects and start using the core of Bullet.

However, I did hit a few snags along the way. Some are just shortcomings of my current implementations, others a bit odder.

Like most of my current projects, I'm attempting to keep my code cross platform by continually building in XCode and Visual Studio and using subversion hosted at Assembla.com. Earlier this week I hit a large snag while using XCode. I had cleaned my project to get rid of several mislinked libraries and unused resources when I discovered that I was getting an EXC_BAD_ACCESS runtime error in some code that had been working just fine for a while. It was in my obj loading phase where I was attempting to push some UV data on a std::vector (like I said, this is a clunky engine). But for some reason this was failing. Oddly enough, I was using other vectors alongside this one in similar ways and they seemed to work just fine.
At first, I figured I just needed to claim some memory before using the vector just to be safe. Of course, reserving and even adding some padding data before-hand just caused the application to crash on those operations. After fondling the debugger a bit I found that the type pointer was either null, missing (what) or otherwise ill-defined. This caused some serious head to wall banging as I couldn't understand how the code even existed without knowing what type it was. I convinced myself that there was a problem with initialization of my data member, so I tried putting a constructor into the initializer list (note, I'm doing all this inside my containing class' constructor and not using a pointer to a vector so this shouldn't be a problem), but to no avail. Finally, I decided to stick this thing in Visual Studio and see what happens. Once I got the solution set up and linking to the libraries right, I compiled and.. it ran. No problems, aside from a few small differences in rendering output due to different graphics cards. So either VS was just being nice to me, or XCode wasn't compiling my code right. I gave the problem some time, and when coming back to it I started trying silly things like changing my order of declarations in the class header. Putting the vector declarations first did nothing, putting some declarations in the middle did nothing, but changing the order of the vectors themselves did something. Turns out, whichever vector was declared last would throw this runtime error. What this means I have no clue, I'm not even sure how to Google for that to find a solution. So I ended up "solving" the problem by adding one more vector member aptly named "fuckme".

Oh, here are some screenshots of the current build showing off a cube of boxmen, a skybox and working terrain. If you look closely, you might notice that the terrain texture doesn't completely match up to the terrain itself. Don't worry, this is just a proof of concept and that image wasn't intended for this use.



Sunday, February 1, 2009

Simple AI design

Because I have several C++ projects that I'm going to need to develop AI for, I might as well begin working through some code design.

As far as game engines go, the singleton manager paradigm is pretty useful (though only in specific scenarios). With an AI system, this manager needs to keep track of all scene objects using AI, the AI itself, and information used by each agent. To me, this means that I can create some grouping for particular sets of AI functions and for each scene object requiring AI control I just need to know what set of functions I'm using. The information, or knowledge base, for each AI/object pair doesn't need to be anything fancy, so a struct will do fine. This leaves me with three components; the AI Manager, the AI Controllers, and a knowledge struct.

The manager is a singleton (no need for several managers in one running engine) that allows adding/removing of AI to scene objects, and provides a means to update all objects in batch. Keeping track of these mappings is sufficient to be a linked list of structs containing a pointer to the object, some identifier for type of AI used, and a knowledge object. More functionality may be needed, but for now this is all I should have to worry about.

The AI Controller types need to be able to support multiple AI paradigms. Initially I was thinking about keeping the knowledge separate from the controllers. Though this forced me to limit the types of AI that I would be using. It would either have to deal with complete information or incomplete, fuzzy or crisp, etc.. Instead of that, I'm better off keeping the knowledge within each controller. Though I'll still define a struct for the different types of data that I'll deal with.

As a base for the knowledge struct I'm including the following;
  • player position
  • player health
  • own position
  • own health
  • # proximal friendlies
  • list of identified projectiles and percieved tragectories (more intelligent agents)
I have listed two fields that are redundant as each controller would have access to it's object's health and position. Though this data may not be in some particular format which the AI functionality would prefer. So I'm listing them here anyway.

Put together, I have a manager which will create an AI control object when given a new scene object to manage. The control object will construct a knowledge set updated by perceptional utilities on the scene object and use this to make decisions for that scene object.

This design is incomplete, but I'm listing it now as an initial design.