Gemini dev update #2
So much has changed since my last update. First off, we’ve created a system for managers to be plugged into the basic game state. The three core managers are game object, update and render. The default versions of these three get auto-added to a game state unless you specify your own to use.
Why might this be useful or interesting you ask? Well consider the problem of one behavior we were working on. CollidableWhenMoving hooks into a game object’s move method using on_after_move. The behavior then needs to check the object that just moved against anything it might have collided with. There’s a basic behavior (BoundingBoxCollidable) that does the actual coordinate checking, but CollidableWhenMoving still needs to get a list of other game objects to check against. Previously, the behavior was keeping an internal list of objects it had been added to. This sort of worked, except that it used class level variables which really breaks down if you want to be able to pause, swap to another state for a while and then come back. Also, other collision’ish behaviors would have to maintain their own lists of game objects and there was no way to share those lists so CollidableWhenMoving could only collide with other CollidableWhenMoving objects. Oh, and it was also an ugly hack.
So the answer was clear, we needed a way for behaviors to generically get information. This evolved into the idea of a state having some number of managers that could provide that information. So now after the movement of a game object, CollidableWhenMoving can query the GameObjectManager registered on the state and ask it for an appropriate list of objects to check against.
Another big improvement was the idea that behaviors should be able to be used as interfaces. So kind_of? was enhanced to check against behaviors as well. Also a new behavior class method: depends_on_kind_of was added to allow a behavior to express the need for another behavior witout having to specify the type. Unlike depends_on, the depends_on_kind_of method does not require or add any dependant behaviors, it simply sets up a instantiation check that will raise an exception if there is not a sub-class of the declared behavior on the object. This allows you to depend on some kind of algorithm object, even though you don’t care which one.
The keymap concept has been enhanced to give you some fairly nice syntax for setting up input processing. Here’s the keymap file for the example pong-like game.
map KEY_HELD, :source_value => Input::KEY_Q, :destination_type => :p1_paddle_movement, :destination_value => :up map KEY_HELD, :source_value => Input::KEY_A, :destination_type => :p1_paddle_movement, :destination_value => :down map KEY_HELD, :source_value => Input::KEY_O, :destination_type => :p2_paddle_movement, :destination_value => :up map KEY_HELD, :source_value => Input::KEY_L, :destination_type => :p2_paddle_movement, :destination_value => :down
The destination_type and destination_value are totally arbitrary and should be customized to make sense for each particular game. Other supported input map types are key_pressed, key_released, mouse_moved and mouse_button_pressed/released.
Finally, we’ve split out the example game into the examples directory. It’s now an actual game with animating sprites, scores and two player controls.