Bullfrog 2, Where art thou?

Back in May of 2007, I announced that Bullfrog 2 development had begun. The game engine was to be entirely rewritten to accelerate graphics by using OpenGL and to add many of the game play features I always felt were missing from the original Bullfrog.

Then in September, I shared with you a short movie showing a very early version of the new game engine. This was all targeting the Mac, just like the original.

While I was very excited about the project, Marcus and I were quite busy with other projects and development was slow. But, just as our schedules began to open up a bit, Apple announced that they were allowing third party developers to write software for their new iPhone.

I guess timing is everything. Within hours of the announcement, we had decided to change directions and target the iPhone and attack the world of mobile gaming.

After more than a year since the original announcement and four months of intense development on a brand new and very exciting platform, the original vision was released.

Bullfrog Touch sports a fast graphics engine, accelerometer-based controls, beautiful scrolling maps, animated water, obstacles, and my personal favorite lily pads.

But, the most exciting part of this whole journey is the huge list of ideas we generated while working on this project. The iPhone and iPod Touch platform is an extremely powerful environment for all kinds of software. The ability to take your iPhone anywhere you go and have the full power of OS X under the hood is sure to lead to some great things.

Bullfrog Game Design: Dynamic Bugs

Developing software is an interesting process. There are times where I work very hard with little to show for it for several days. Then there are those days where I can knock out a ton of tasks on my “To Do” list with little effort. Usually, one state directly follows the other.

I recently spent several days working on the mechanism that Bullfrog 2 will use to load level and bug definitions. There was much reworking and testing involved. Now that the work is complete, designing new levels and bugs should take little time and effort.

Hardcoded Bugs

In the original Bullfrog, the player was tasked with munching bugs as fast as possible. Bugs were randomly spawned on the screen based on a simple algorithm. This algorithm would generate a certain number of bugs depending on what round the player had reached. For example the gnat was generated using the following calculation.

int numberOfGnats = roundIndex * GNAT_SPAWN_RATE;
listing 1

Each bug type had it’s own spawn formula and custom class. Each bug class would then be allocated and tracked in a NSMutableArray during the round.

NSPoint origin = GetRandomGamePoint(gameRect);
unsigned int direction = GetRandomAngle();
switch([bugDef bugType])
{
   case GnatType:
      bug = [[Gnat alloc] initAtPosition:origin
                           withDirection:direction];
      break;					
//   ...
}
listing 2

This approach worked fairly well for a simple game using random spawn points on a simple game board. There were no level design elements to worry about. A bug was either alive and on the screen, or it had been eaten.

Dynamic Bugs

For Bullfrog 2, we really wanted to move away from randomly generated rounds and bugs to designed levels. We plan to have multiple levels with unique artwork and challenges. But how do we define bugs and have them spawn based on a definition file?

We could read in the definition and run through a big switch statement with a case block for each bug type similar to the code above (listing 2) used in the first Bullfrog. But, this gets nasty pretty quick.

We’re also adding new game elements to Bullfrog 2. Players will have obstacles such as rocks and water to deal with while hunting down bugs. These elements also need to be defined and tracked inside the game.

With a bit of imagination, rocks and bugs are basically the same thing except for a few different attributes. Bugs can move, rocks can’t. A mosquito can damage the player, but a rock can block the player’s movement.

This lead us to a base class we’re calling Actor. Each actor can be completely defined with a set of attributes which denote size, animation, and other things.

We still have the problem of needing unique AI (artificial intelligence) for the different bugs. Using just the Actor class won’t provide us with customized code to define personality attributes such as chase and escape behaviors.

So we defined a set of Actor subclasses that provide the custom behaviors of the various bugs and other objects populating the Bullfrog world. But, with each new game object, our switch case grows in complexity.

Objective-C to the Rescue

This is where our decision to use Objective-C pays off. By using the dynamic nature of the Objective-C we can allocate and initialize our actors at runtime without using a huge switch statement.

Given the following Actor definitions (listing 3) we can dynamically generate the level’s actors with a simple loop (listing 4).


   
      class
      BFRock
      blocksMovement
      1
   
   
      class
      BFGnat
      blocksMovement
      0
      moveSpeed
      0.005
      turnFrequency
      5
      turnSpeed
      20
   

listing 3
- (void)loadActorsDefinition:(NSArray *)actorsDefinition 
                   intoLayer:(NSMutableArray *)layer
{
   id actor;
   NSDictionary *actorDef;
   for(actorDef in actorsDefinition) {
      NSString *actorClass = [actorDef valueForKey:@"class"];
      actor = [[NSClassFromString(actorClass) alloc] init];
      if (![actor isKindOfClass:[OLActor class]]) continue;
      [actor loadDefinition:actorDef];
      [layer addObject:actor];
   }
}
listing 4

The key piece here is the function: NSClassFromString(NSString *str). This Foundation function returns a Class object that can then be used just like your hardcoded class definition for allocating a new instance.

In the above function (listing 4) we get the “class” attribute from the XML and feed that into the NSClassFromString function to get our Class. Then pass in the XML for this particular Actor into the instance method -loadDefinition: on the Actor class. Some more Objective-C runtime magic reads in the defined attributes and stores them in the Actor instance properties using key-value coding (listing 5).

NSString *key;
for (key in [definition allKeys]) {
   [self setValue:[definition valueForKey:key] forKey:key];
}
listing 5

Now all actors for each defined level are easily loaded and we don’t have to constantly rewrite or modify our code each time we add a new type of bug or game object.

The difference in complexity and number of lines of code in Bullfrog 2 is greatly reduced because of the magic that Objective-C provides. Dynamic class loading is very powerful and provides us with great flexibility moving forward.

Bullfrog 2 Teaser Screencast

Marcus and I have been working hard on Bullfrog 2. There are many technical hurdles we’ve been navigating through, but it’s been fun so far.

We promised to keep you up to date with progress and discuss the technical challenges we’ve encountered. So far the challenges have been all due to our lack of experience in the new technologies we’ve chosen to use.

Open GL has been a bit of a change from drawing in Cocoa, but once I worked out the “little” problems getting the code to work on multiple graphics cards it’s been mostly smooth sailing.

The biggest challenge has been getting up to speed with the new Leopard technologies. We really want to write about this stuff, but can’t yet because of the NDA we’ve agreed to with Apple. Hopefully, we’ll get to talk about that stuff soon.

But, to show that we are making progress here is a short thirty second movie of our little green hero hopping around a small test level.

Keep in mind this is uses very rudimentary developer artwork I created just to test the screen scrolling and background tiling code. But, it does give a small peak into the direction we’re taking Bullfrog 2.

Bullfrog 2 Teaser

Bullfrog 2 Update

I can’t believe it’s been a month since my last Bullfrog 2 post. Unfortunately, development has gone a bit slower than originally anticipated due to work on other projects.

Leopard

Over the past few days I’ve been moving code from the old Bullfrog game engine to a new Xcode 3 project for full-bore development to begin on Leopard.

Yes, we’ve made the decision to make Bullfrog 2 a Leopard (Mac OS X 10.5) only product. There are just too many things in Leopard that we really want to use.

OpenGL

As I mentioned in the last update, I’ve been learning OpenGL and working towards converting the Bullfrog engine from the old Cocoa drawing code. Today, I checked in my changes that have officially started us down the OpenGL path.

Our green hero is now fully hardware accelerated and I have resolved my earlier transparency issues.

Foundations

The next step is heavy refactoring of the game engine. Bullfrog was my first Cocoa / Objective-C project and the structure of the code definitely reflects that.

Now that I have significantly more experience in how a Cocoa-based project should be structured, we’ll spend a couple of weeks moving code around and getting our foundation in order.

This will allow for multiple developers to work inside the project as well as make the code generally more maintainable.

Just the Beginning

We’re still very much in the preliminary development stages with much design work still to be done. But, it’s a good feeling to move forward on this project.

OpenGL Bullfrog

Finally had some time today to toy around with some OpenGL programming. One of the first architectural changes we’re going to tackle in Bullfrog 2 is to move all the graphics engine code to use OpenGL instead of Cocoa.

I created a new Xcode project to house our experimental code while we find our way around OpenGL. After hacking away for a couple of hours I was able to get a basic though flawed proof of concept to render our old friend from the first Bullfrog game into a custom NSOpenGLView.

I haven’t figured out how to get transparency to work with the alpha channel and the sprite is sized too small, but not too bad for a first go.

After some more reading I should be able to figure out how to fix the frog’s size and transparency issues.

I did encounter an interesting “bug” while putting together the UI in InterfaceBuilder. Using an NSOpenGLView directly with a custom class will never call your -initWithFrame: method. The only way I could find to get the method invoked was to use a Custom View (NSView) instead of the NSOpenGLView and then use my same custom class. Perhaps I’m just missing something, but this seemed strange.

Bullfrog 2

Bullfrog exceeded all my expectations. Even though it was only supposed to be a learning project and was developed with a tiny budget, downloads have been non-stop since it made its way on to the big Mac download websites.

Watching as the high scores have gotten higher and higher over time and reading all the extremely positive feedback has been feeding the game developer monster inside of me.

Finally, I can’t resist any longer. I’ve decided to begin development on the sequel to my little arcade game. But, this time the plan is a little different.

Take Two


The first time around I didn’t know any Objective-C or Cocoa, had a budget of almost zero, and developed the entire game from scratch.

Bullfrog 2 will benefit from all the experience I earned the first time through, an existing code base, a larger media budget, an existing user-base, and a new development partner.

Marcus Zarra and I thought it would be fun to team up and develop Bullfrog 2 together as a joint venture between Outer Level and Zarra Studios.

Sharing the Journey


Neither of us are real “game developers”, so we’ll be working through some interesting challenges on the way to releasing Bullfrog 2.

With this in mind, we’ve decided that sharing the design and development process on our blogs would be fun and hopefully interesting to gamers and fellow indie developers.

Bullfrog 2 is still very early in the design stage, but we already know some of the challenges we’ll be facing.

The first Bullfrog engine was built entirely in Objective-C and Cocoa and had some “interesting” performance challenges. One of the early design decisions I made was to avoid using OpenGL so I would not have to learn two entirely new frameworks to get the project completed.

This time around, one of the big goals is to migrate the rendering engine to OpenGL. We hope that this decision will lead to some huge performance benefits that will allow us to add new fun game-play features.

So we’ll probably have much to say on the OpenGL switch along with other technical hurdles we’ll likely face.

Stay Tuned

If you are interested at all about game development on the Mac, look for articles coming down the pipe about all things Bullfrog 2: design, development, brainstorming, and marketing.