Rebirth & Rubygame, Together Forever

(June 10, 2008 @ 12:32 AM)

I’ve decided on the relationship between Rebirth and Rubygame. Or rather, the relationship came naturally, and it seems agreeable, so it’s the direction I’m going to go.

In Rebirth 0.1, the View class wraps around Rubygame’s Screen class with a different API. As you can see in the source, View just sets the screen mode, then stores the Screen as a class variable. (Right now it doesn’t do anything with it, but it will for setting title, etc.)

This arrangement came out of simple laziness – I did the least amount of work to fulfill the specifications of the View class. And it works really well having Rebirth sitting on top of Rubygame. Rebirth can be pure Ruby, and take advantage of Rubygame’s features – opening a screen, loading images, getting events, etc. Features that Rebirth doesn’t need (Rects, Surface blitting, etc.) it can just ignore.

What this means is that Rubygame will continue to develop on its own, and Rebirth will be a new based on top of it. This is good for both libraries, in fact:

  1. It keeps my interest and motivation up, because I get to work on something new and fresh.
  2. It gives me an excuse to use and improve Rubygame as well, adding new features I need for Rebirth.
  3. It won’t interfere with games that are just using Rubygame (no major backwards compatibility breaking).

So, that is the happy news!

Rebirth 0.1

(June 09, 2008 @ 09:17 PM)

Rebirth 0.1 is done. All it can do is open and close the View (equivalent to Screen in Rubygame – in fact, built on top of Screen). So, you probably don’t want or need to download it. It’s immortalized as tag release-0.1 on Github.

0.2 will be done when keyboard events are done. 0.3 will add a Rectangle class, so there will actually be something to see. You can read the ROADMAP to see the rest of the releases that are currently planned (up to 0.8 so far).

Rebirth News

(June 04, 2008 @ 02:50 PM)

Two bits of news about Rubygame and Rebirth today.

First, I laid out some goals / guiding principles for Rebirth. I don’t know if they’re of interest to anyone else, but here they are:

  1. Ease of use. It should be natural to express game behavior, without needing to jump through hoops. Use of defaults and constraints to suggest a course of action and reduce the “burden of choice” on developers.

  2. Flexibility. Rebirth should be able to handle games of many types and genres; physics or non-physics, action or slow-paced.

  3. Object-oriented. It should focus on game objects and how they behave and interact, not on the mechanics of image blitting and event management.

  4. Examples. Plenty of running example games to help users get started and see how the library can / should be used.

  5. Documentation. Every module, every class, every method documented, plus tutorials with examples about various important concepts and features.

  6. Behavior-driven development. Spec first, then implement. Full spec coverage, master branch is always green.

  7. Small, incremental releases. Every feature should be a release, very release should add or refine a feature. Avoid build-ups.

These goals (especially 3, 4, 6, and 7) reflect what I consider to be Rubygame’s shortcomings.

Second, it’s becoming more clear that Rebirth could be just a layer on top of Rubygame and ruby-opengl. In fact, that’s just what I did last summer, in the original Rubygame 3.0 branch. Really, the work I’m doing now is just another refinement of the ideas that I was thinking last summer. (There’s probably some good code I can lift from that branch.) So, it might be that Rebirth will be an add-on to Rubygame, rather than a replacement.

There’s also the possibility of incremental revisions to Rubygame to bring it closer to my goals with Rebirth. The problem there is that it’s a slow process, and that carries the risk of losing interest. It would also lack the freedom to make radical changes that you get with something new.

Github Project for Rebirth

(June 01, 2008 @ 09:10 PM)

I’ve set up a Github project for Rebirth. There’s not a whole lot to see there yet – the bouncy ball game, a partially complete paddle ball game, and some not-implemented specs for event hooks and shapes. But you might be interested to take a look at the style so far.

A look at the first Rebirth demo game

(May 29, 2008 @ 11:44 PM)

I finished a demo game yesterday, as an aid in designing the still-imaginary Rebirth API. I actually meant to post this last night, but I ended up staying up until past 2AM trying to find a way to do syntax highlighting on Mephisto, to no avail.

The game is a simple one: bounce a ball in the air by clicking it, and don’t let it fall to the ground. You get a point for each time you click it, but lose a point for each time it hits the ground. If you get up to 15 points, you win. Not the most challenging thing in the world, but it has all the elements of a complete game.

The code for the entire game is about 100 lines long. Rather than cop out and just post the whole file, I’ll show and explain a few highlights. Keep in mind that the code to support this doesn’t exist yet; I’m just threshing it out, and imagining how it might be used. As I explained in my previous post, once I’ve got some sample games written, I’ll codify the API in specs, and then implement it.

First up, is the class for the Ball object. Here’s the entire class definition:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Represents a bouncing ball.
class Ball < GameObject
  # Set up the physical and visual properties of the ball.
  def initialize( params = {} )
    base_params = { 
      :center  => v(0,0),
      :radius  => 15.0,
      :density => 5.0,
      :elast   => 0.9,
      :color   => :red
    }
    
    add_shape Circle.new( base_params.merge(params) )
  end
end

As you can see, it just creates a Circle instance with certain parameters, and adds the Circle as a shape. The hash of base parameters defines what the default ball is like, but you can override / augment them by passing a hash to the initializer. There will be other possible parameters besides just the ones shown there, but these are the ones that are important to the ball (Circle will use defaults for the rest).

Circle will be one of a handful of built-in shape classes, which provide a visual appearance and a physical behavior for game objects (i.e. for collision detection and physics). By default, objects are both visible and collidable, but you can turn either (or both) off by providing certain parameters. That way, you can have non-collidable objects, or collidable invisible objects. And, yes, all the shape classes will be part of the physics engine, powered by Chipmunk.

So far, it has a ball that we can see, and that acts physically. Later on, it adds a hook to perform a certain action when the player clicks on the ball:

1
2
3
4
5
6
$game[:ball] = Ball.new

$game[:ball].when_clicked do |click|
  $game[:score] += 1
  $game[:ball].shove( :from => click.pos, :strength => 30.0 )
end

Here, it makes an instance of Ball, and stores the instance in a namespace for later use ($game is an instance of Game, which I’ll cover later). Then, it uses the when_clicked method to add a hook which will be triggered when the user clicks on the ball. The block adds one point to the player’s score, and also applies a physical impulse to the ball to shove it away from the cursor, sending the ball back into the air. (By the way, the hook could have just as well been set up in the Ball’s initialize method, for behaviors that you want every instance to have.)

Elsewhere, it sets up a when_collided hook on the floor, to call a block to remove one point from the player’s score. It also creates a when_true hook on $game itself; when_true periodically evaluates a Proc to see if the statement is true, in this case to test if the player has 15 points yet.

There’s other interesting code that I’d show you, but I don’t want this post to get really long. I expect to put this project up on Github eventually, so you’ll be able to get all the code you want. If the demand is there, I might do another post tomorrow to demo another part.

P.S. Rebirth is still strictly theoretical. I’d give it a 50:50 chance that Rebirth sees a release, and only a 1-in-20 chance that it will result in any major functionality removal from core Rubygame.

Rubygame: Rebirth

(May 27, 2008 @ 01:14 AM)

I’m going to try an experiment. A clean slate, a new project, a new library. Shrugging off the baggage and legacy of the Old Rubygame, and starting fresh, as I talked about in the previous post.

I’m going to design a new library from scratch, applying what I’ve learned from the first attempt, but with no thought to compatibility. I’m dubbing the project Rubygame: Rebirth. Rather melodramatic, but it hits the right chord.

I’m going to tinker in a local git repository for a week or so, and then decide the future of the experiment. If it feels right, I’ll put it up on Github, and take it from there. If it pans out, I’ll trash it.

Here’s the ‘plan’:

First, I’m going to write some simple games with the library, before it even exists. Each game will have a different complexity level. At the low end would be something as simple as Pong. At the high end would be a run-and-jump platformer with physics, textures, and sound effects. Obviously, none of the games will run at this point, but they’ll be the sandbox for designing an API that I would want to use.

Once I have a few games written, I’m going to extract the core API requirements from those games, and express them as specs. Again, they won’t pass (they’ll be “not implemented”), but they’ll be a more formal definition of the API-to-be. The API will be categorized by the complexity of the game that requires it, and mapped out as milestones to guide development, with the simplest things first, and the most complex things last. The games and specs will also act as progress indicators – as the library becomes more complete, the games will start to run, and the specs will start to be green-able.

Each new feature would correspond to a milestone, and each milestone would mean a new release. The first release would come when the simplest game (Pong or whatnot) ran successfully. Every new feature would be another release. Some releases would also have a new game that began to run due to the latest feature addition. Bug fixes wouldn’t get their own releases, but just wait until the next feature.

And of course, all of these plans would be subject to change. I know myself too well to think that I can predict how this project will go. Things change, ideas change, people change. Nothing would be carved in stone, just sketched out in pencil as a guide.

I have no idea if anybody will care, or branch it and make changes. The plan doesn’t depend on it, but it does allow for it – by laying out the draft API from early on, other people might help fill in the blanks. I’m not getting my hopes up, though.

What will come of this experiment? I certainly can’t predict. At worst, it’s a false start, and I trash it within a week. At best, it’s the future of a new, reborn Rubygame.

Insert dramatic music here.

Sexy Progress vs Compatibility

(May 26, 2008 @ 05:22 PM)

There are times when I am tempted – so sorely tempted – to break compatibility between Rubygame 2 and Rubygame 3 in a huge way. Wipe the slate clean and rebuild, carrying over only the best ideas from the Old Rubygame. If I were going to do that, here’s what the New Rubygame would be like:

  • No SDL. Certainly no SDL_mixer or SDL_gfx, which have been great annoyances to me – the former for its flakeyness, and the latter for its lack of a precompiled Windows DLL (which I only care about because it significantly raises the barrier for Windows users to try out Rubygame).

  • Instead, OpenGL and OpenAL. Mostly for the robustness and wide cross-platform adoption, but also for the sexy feature factor. “Hardware accelerated” looks good on a résumé.

  • Chipmunk integration from the start. “Real-time physics engine” also looks good on a résumé.

  • Higher level Sprite and other classes, with more controlled APIs, and a well-defined system for extending them. Plugins preferred over inheritance.

  • Hook-based event management.

  • No Rect. No Surface. No draw_* methods.

  • Instead, shapes – for collision/physics, and for drawing. Drawing styles with attributes for fill and border. Images would be textured quads. Inspired by SVG.

  • Total independence from screen resolution. Objects exist and interact in world space, and can be viewed at any size or rotation with no worries about doing rotozooms and storing temporary images.

  • Generally, more focus on objects and behavior, and way, way less focus on managing pixels.

  • Fully specced, BDD all the way, and clear example games demonstrating how to use each feature.

  • Way cooler than Gosu. ; )

So what’s stopping me from doing all this awesome stuff? It’s not the effort or the time involved – new things like this are interesting and motivating, and it would proceed easily and quickly. And certainly, dropping all the baggage from Rubygame would be liberating and motivating in itself.

The problem is, New Rubygame wouldn’t even be remotely compatible with Old Rubygame. The core concepts are fundamentally different. Upgrading old games would practically mean rewriting them. For some games, it wouldn’t even be possible to upgrade, because the feature set would be so different. New Rubygame would be a whole different species, a whole different library from Old Rubygame.

So here are the possible roads forward:

  1. Continue adapting the current Rubygame, adding new things and deprecating older things, slowly and incrementally progressing towards a better Rubygame.
  2. Start over with Rubygame 3 as a whole new creature. Scrap the old library, leave old apps in the dust.
  3. Start a new, separate library to implement this new vision. Rubygame continues on its own.

Food for thought.