Shmup Development (using XNA and C#)

Wednesday, January 16, 2008

Components of a shmup game: Manage and recycle objects

I thought about writing some series about developing a shmup game. It will be from my perspective (with the shmup engine I'm creating) and focus on some of the components in a shmup game. If I provide examples and code there will be with C# and XNA. I will probably not explain in detail what the sourcecode looks like, I will more explain the concept and design. Ok, lets go!

This is the first part of the series "Components of a shmup game" where I will write about how my shmup engine manages and recycles objects.

Introduction to objects in a shmup game

In a shmup game lots of objects are created and destroyed very often. Bullets that the player is firing, enemies that are spawned and then milliseconds later are destroyed, explosion particles and so on... The average lifetime of an object in a shmup game is very short.

Every time the player fires a bullet I don't want to create a new bullet (new Bullet()) because this will be pretty inefficient for the garbage collector, instead I want to recycle an already destroyed bullet. This makes all of the objects in the game need to know when they should be destroyed and recycled.

With this in mind I decided to create a few classes that helps me achieve this.

What the classes looks like when managing objects

What we know: Every game object in the shmup engine can be updated and drawn. It also need to know when it should be destroyed, recycled and how to be created from the "recycle bin".

Product - Base for every game object. Provides functionality to be updated/drawn. Can also be added to a manager through the method Activate(IManager manager) and removed from an manager with the Deactivate() method.

IManager - Interface for every object manager. Provides functionality to add an object with Add(IProduct product).

Manager - An implementation for a manager. Provides functionality to update and draw all the objects in the manager. When an object is destroyed and wants to be recycled it uses the associated Factory to add it to the "recycle bin".

IManufacturer - Interface for a manufacturer. Provides functionality to create an object with the method Create().

Factory - Handles creation of objects. Provides functionality to add and create objects to/from the "recycle bin". Manufacturers can be registered (with a name) to the factory for creation of objects that has not been recycled.

What is a factory and manufacturer, and how does it work?

It's pretty simple, a manufacturer is used to create objects. It has a single method, Create() that returns a created object. Every manufacturer knows how to create exactly one object.

A factory contains a dictionary of manufacturers. Manufacturers are registered (added) to the factory with the method Register(string name, IManufacturer manufacturer). The factory is also used with the Manager to handle destroyed objects. The factory got a Create(string name) method (the name is specified for the method so it knows which manufacturer to use to create the object). The factory also got a dictionary of destroyed objects (with the name of the object as the key).

When the Create(string name) method on the factory is called it first looks in the recycled objects dictionary to see if there are any objects available. If there are objects available it will be removed from the list and immediately returned. If there are no objects available the Manufacturer (with the specified name) is used to create the object and return it.

Example when the player fires bullets

Let me explain the object management of a bullet that is fired by the player and then hits a enemy (some stuff are excluded to we can focus on object management).

First we need to do some setup (this is before the game has been started):

  • We created a BulletManufacturer class that creates a bullet.
  • Register the BulletManufacturer in the Factory (with the name "MyBullet").
This is what happens when the game is running and player wants to fire a bullet:

  • Player presses space to fire a bullet. The Create("MyBullet") method on the Factory is called.
  • Factory checks if there are any recycled objects available. There are not (because the bullet has never been fired before).
  • Factory gets the BulletManufacturer (with "MyBullet" name) and calls the Create() method which returns a bullet. We now got our bullet that we add to our Manager (that handles bullets).
  • Manager updates and draws the bullet as it moves across the screen for a few frames.
  • The bullet collides with an enemy. Now we want our bullet to be removed from the Manager so we call Deactivate() on it.
  • When the bullet is deactivated the Manager will add it to the Factory recycled objects.
  • A few frames passes by and the player wants to fire another bullet. The Create("MyBullet") method on the Factory is called.
  • Factory checks if there are any recycled objects available. There are, so we just return the recycled bullet. We now got our bullet that we add to our Manager again.
That's how it works. I have provided more concept than code, but I hope this can help some of you to understand how you could implement this kind of object management.

I have the intention to write more about developing shmup components (for example):

  • Rendering system
  • How the stage and timeline works
  • Behaviors for entities
  • Developing a datadriven shmup
Would anyone be interested in that? Please write some comments...

Monday, January 07, 2008

Domain registered: is mine

I have just registered the domain for this blog. I was certain that the domain was already taken, but it wasn't... and now it's mine!! Mohahahaha...

Friday, January 04, 2008

Shmup engine running on the Xbox 360

I'm now a member of the XNA creators club, which means I can run my games on Xbox 360. It's so much more fun to develop and see it in action on a console.

Here are some of the features that has been in focus:

  • Rendering system: graphics can be drawn in the renderer in any order. Then when the draw function of the renderer is called all the queued graphics (models, sprites, particles) is sorted (by graphicstype and draworder) and then drawn. This works very well, just don't care in which order to draw the graphics.
  • Base classes: entity, enemy, player, stage, bullet, behavior...
  • Content pipeline: stage and enemy can now be loaded with the content pipeline.
  • Behaviors: can be added to any entity. Have created a few like chasebehavior (for enemies to chase the player or homing missiles), weaponbehavior (to fire bullets, both for player and enemy), scopebehavior (so objects can be removed when outside the screen), splinebehavior (make objects follow a spline).
Features I will continue to work with:

  • Bullet patterns: patterns will be loaded with the content pipeline.
  • State management: Screens and menus.
  • Editor: A simple editor to create enemies and bullet patterns.
Some screenshots (and video maybe) is coming later. I'm creating games for the Xbox 360, cool or what? :-)