Archive

Posts Tagged ‘gemini’

Things to do on your next game jam

October 27, 2008 Leave a comment

I just wrapped up a game jam at the Art Institue over the past weekend (screenshots pending).  We didn’t get much in the way of innovative gameplay implemented, mainly just expanding the behaviors that Gamini has.  Ideally these game jams should be more about totally radical ideas.  You have 3 days at most so you’re not making a “real” game, so why not go nuts on the design.  Something that, to me, seems like a gam-jam kind of project and pretty interesting is The Unfinished Swan by Ian Dallas.  They have a really cool video on the site that’s definately worth your time.

Categories: Games Tags: ,

Gemini dev update #2

August 15, 2008 4 comments

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.

Categories: Development, Games Tags: , ,

Gemini dev log: The path to (rigid body) madness

July 30, 2008 Leave a comment

Is having a physics engine wired into the base of your game engine madness?  Clearly the opposite extreme, waiting until the game is well underway and then bolting a physics system on is pretty close to my definition of madness, but I’m not shure if the other extereme is equally un-sane.

My reasoning for wanting to do something like build on top of a physics library from the start is that you can unify many systems that might otherwise grow into less-than-optimally-compatible interfaces.  I’m thinking specifically of movement in a game world.  Normally we teleport our objects around at 30-60 fps giving the nice illusion of fluid movement.  Of course you occasionally jump over a solid object if you’re moving too fast so you then step back and start interpolating the movement and eventually end up with something fairly close to a physics library, at least in terms of determining collisions.  So why not just start with the physics lib from day 1 and build your collision detection, vectorized movement, etc. on top?  Then when you actually want physics based behavior there’s no need to figure out how to integrate some external library, everything is ready to go.

I liken this to something like metaprogramming in your language.  If you start off with Java and then decide later, “gee I really need to hook into every method in this one class and do some logging”, well, have fun getting to know Mr AspectJ.  If you’re in a language like Ruby, the metaprogramming is built in just waiting for when you need it.  The unfortunate side effect though is that you’re paying for the metaprogramming facilities even when you’re writing Java style OO, one reason Ruby is so much slower than Java.  So would sticking in a physics system make Gemini 100 times slower?  I don’t think so, especially since the facilities of a Physics library mesh so well with things we already need in a game engine, like the aforementioned collision detection.  Time will tell to what factor of incorrect my assumption is though (I’m usually off by more than 3x, *sigh*).

My current candidate for a fast physics lib is Chipmunk.  Written in C it should be pretty easy to hook up via JRuby‘s FFI system (which wraps JNA and soon JFFI).  Thanks to Gemini’s awesome behavior system we’re fairly certain we can swap out Spatial for PhysicsSpatial and no higher level behaviors needs to know that the x, y, width, height are coming from a Chipmunk spatial struct vs local variables.  Of course the collision behavior would need to change to use the physics lib, but the nice thing is everything else is insulated.  You can could easily write higher level behaviors that depend on some sort of collision behavior, completely ignorant of weather they do their voodo via primitive shape intersection tests, complex physics based simulations or the divining of chicken entrails.  That last one is still a work in progress.

So, am I crazy to attempt such a thing?  Has this been done already?  Any war stories that you’d like to share?

Categories: Development, Games Tags: , ,

Gemini dev update #1

July 29, 2008 Leave a comment
500 bouncing balls

250 bouncing balls

Some of my previous posts regarding Gemini seemed to have garnered some attention thanks to someone posting one of them to DZone (thanks whoever that was).  So, since there’s no official home page with nice docs and tutorials and such I decided I would just keep a more public journal of the development progress of Gemini until those things are actually warranted.

So, to bring people up to speed on this Gemini thing.  It’s a JRuby game engine that sits on top of the Java based Slick library which itself uses OpenGL via LWJGL (that enough layers for ya?).

Gemini’s secret sauce is the idea that your game logic should not be in a big monolithic while loop.  Of course your game needs the basic game loop ingredients of checking for input, updating the game state and redrawing the scene but is a big while loop really the best place for all that?  So we started with the idea of game objects as the basic “thing” that exists in the world.  Game objects in reality are really just empty containers for you to attach behaviors to, without any behaviors they aren’t really much of a “thing”.  So, game objects via behaviors become the centerpoint of the game development effort.  To that end game objects support the idea of adding and removing behaviors and behaviors understand the idea of dependencies.  With that in place, you can create a game object that has a sprite, can move around and collide with other things and has callbacks for all its events in just a few lines.

class Ball < Gemini::GameObject has_behavior :UpdatesAtConsistantRate has_behavior :BoundingBoxCollidable has_behavior :Sprite end [/sourcecode] Now, this doesn't tell the Ball object, what sprite to use, what to do on updates, what sorts of things to collide with, etc. Behaviors add methods to the game object they are attached to; methods that we can use in the load method to set up all our properties. [sourcecode lang='ruby'] # the x= and y= methods are added by BoundingBoxCollidable which depends on # Movable2D which depends on Spatial which provides the x= and y= (phew!) def load collides_with_tags :wall preferred_collision_check BoundingBoxCollidable::TAGS self.image = "ball.png" self.updates_per_second = 30 self.x = rand(640 - width) self.y = rand(480 - height) @vector = [rand(5) - 3, rand(5) - 3] end [/sourcecode] Those self.= calls are there to force the method to be invoked instead of creating and assigning to a local variable. So with that done, the only pieces left to get a bunch of balls bouncing around on the screen is to say what happens on each updated (the tick method gets called by the UpdatesAtConsistantRate behavior) and to say what happens when the ball runs into a wall (defined by anything with a :wall tag). [sourcecode lang='ruby'] # The on_ callback system is instance level and thus would be added to the load method on_collided do |event, continue| vector[0] = -1 if x > (640 – width)
vector[0] = 1 if x < 0 vector[1] = -1 if y > (480 – height)
vector[1] = 1 if y < 0 end # The move method was added by BoundingBoxCollidable which depends on Movable2D def tick move(x + @vector[0], y + @vector[1]) end [/sourcecode] So, plenty of hard coded stuff that we plan to swap out for a relational positioning system (0 = left side of screen, 1 = right side of screen) and the collision handler could probably be a bit prettier but it's a start. So where is Gemini today?  Well, certainly not in a position to make an actual game with.  There's infrastructure for our concepts of behaviors and game objects, there's an internal message queue which allows game objects to communicate asynchronously and in a totally decoupled manner (it's also going to be used for stuff like input handling). The next two components to start hacking on are the input system and a basic GUI system which my associate Logan Barnett will be heading up.  Beyond that there are lots of places to hit up for performance improvements including but no limited to moving various parts over into Java based libs.  Certainly something computationally heavy like a physics engine would be a great candidate for Java, and thankfully there are several to choose from (plus all the C based ones that have simply been wrapped in Java).  So the future is bright, we can already move a good number of sprites around doing collision detection with zero optimizations and the behavior based system appears to have long legs in terms of allowing us to implement everything from keyboard input to playing sounds to moving as part of a cutscene as part of a behavior.

Categories: Development, Games Tags:

50% performance boost, for free?

July 25, 2008 5 comments

Wouldn’t it be nice to live in a world where you can wake up one day and have some project of yours just magically run 50% faster? Well my friends, JRuby is a world of mystery and amazement. In the past few days the JRuby team has been working feverishly on their Java integration rewrite. Along the way Charles Nutter managed to clean up the number of layers a Ruby call had to go through to get to Java. The net result: my test case for Gemini that I posted about earlier when from a frame rate of 27 fps to 40 fps. None of my actual code changed, I just swapped out the jruby.jar for a newer build. Swapping them back takes me back down to the 27 fps range. So, mana does fall from heaven occasionally, at least in JRuby land.

Categories: Development Tags: ,

Java game library + JRuby + awesome DSL = Gemini

July 14, 2008 3 comments

I’ve been working with JRuby to build high level systems on top of powerful Java libraries for about 2 years now.  My most successful endeavor has been Monkeybars, a libarary for making Swing a lot easier to use.  My other project has been in the game development arena.  The project name is Gemini, and although it’s not nearly as advanced as Monkeybars, I was able to get to a significant point over the weekend.  Yes, here in all its glory, the simple “crapton of sprites bouncing back and forth demo”.

1000 dukes bouncing back and forth on screen

Now you’re probably saying, big deal, I can do that in like 40 lines of code in <insert favorite programming language/framework> and no doubt you would be correct.  What’s interesting about the way Gemini does things is in how it gives you an extremely flexible way of compositing together your game objects and your application as a whole.

The code to get this going using Gemini is pretty straightforward.  We have a game state that is loaded by Gemini when it starts up.  That game state then instantiates 1000 of our game objects and they proceed to load their images and care for their own logic of bouncing around on the screen.

Here’s the code in main.rb that kicks off the app:

require 'gemini'
Gemini::Main.new("Test game", 640, 480)

And here is the state that is loaded by default when Gemini runs: main_state.rb

class MainState < Gemini::BaseState def load @sprites = [] 1000.times {@sprites << Duke.new} end def update(delta) @sprites.each { |sprite| sprite.update(delta) } end def render(graphics) @sprites.each { |sprite| sprite.draw } end end [/sourcecode] Finally we have the Duke class that was instantiated in the MainGame class: [sourcecode lang='ruby'] class Duke < Gemini::GameObject has_behavior :Movable2D has_behavior :Sprite has_behavior :UpdatesAtConsistantRate def load self.image = "duke.png" self.updates_per_second = 30 @direction = :right self.x = rand(640 - image.width) self.y = rand(480 - image.height) end def tick if x > (640 – image.width) || x < 0 @direction = @direction == :right ? :left : :right end self.x = x + (@direction == :right ? 1 : -1) end end [/sourcecode] Apart from some hackish ternary ifs in the Duke class I think the whole thing is pretty darn readable, especially considering all that it is doing. As you can see, everything is extremely declarative including those has_behavior calls in the Duke class. Those nifty bits of metaprogramming bring in all the crunchy goodness of the class and make the x, y, image and updates_per_second methods appear. Movable2D gives us a move method and also pulls in the Positional2D behavior that provides the x and y methods. UpdatesAtConsistantRate gives us an update method that calls tick at the rate specified by updates_per_second. Finally the Sprite behavior gives us the image method and the draw method that gets called in the MainGame class. Most of this is bare bones at the moment. What if you don't have the UpdatesAtConsistantRate? When update is called you asplode. Same for Sprite / render. So clearly a more flexible game state is needed, probably involving the game object behaviors auto-registering themselves with the game state to be called during an update/render cycle. But as a whole I'm quite happy with the way Gemini is starting to shape up. Next on the agenda is getting keyboard mapping hooked into the RecievesKeyboardEvents behavior so you can control duke, then we'll have what could pass for a real game.

Categories: Development Tags: , , ,