Download C# source code and ClickOnce installer - requires .NET Framework 2.0
Designing the Asteroid class
Most of the movement code is the same for the player and the asteroids. The asteroids' movement is somewhat simpler since they have some initial random velocity, but never accelerate, but this can be achieved simply by leaving the Acceleration property as 0.
It is therefore useful to keep the movement code in a common base class, GameObject and have the Player class simply set the acceleration and turning rate to the desired values, then ask the base to calculate the updated position. We can also extend the GameField object that was used before to track the size of the playing area to also track the current list of objects. This lets all of the update and drawing operations be performed at once with a single call.
Consider a theoretical simple game with the following types of object:
- Player, with animated sprite with different images for walking, shooting, etc.
- Monster, with animated sprite
- Obstacle, with either a single sprite image or an animated sprite
- Various powerups, with a single sprite image each
Although there are four types of object, there are only two types of sprite - static, with a single image, and animated, with many images - and some objects may even have the same behaviour, but different types of sprite. Also, there is no need to duplicate the sprite objects - only one copy of each bitmap needs to be stored, rather than one per object.
It is much easier to create a seperate inheritance hierarchy with a Sprite base class, and give the game objects an instance of Sprite, than to build the drawing into every object type. Maintenance also benefits, since drawing code for each type of sprite is kept in one place, and when a new type of sprite is added, every type of object gains use of it. This is even more important in a complex 3D game, where there may be a mesh representing the object's appearance, a simpler mesh used for collision detection, as well as geometry (possibly not a mesh) and associated information such as mass of each component used for the physics engine. Merging all of them into one class would create a useless clutter.
The Asteroids2 sample provides a Sprite base class, as well as two implementations. One simply draws a polygon; the other contains a collection of individual Sprites. The Player class uses this to seperate the ship and its exhaust, so it can disable the exhaust sprite when the engine is not in use (rather than keeping two seperate sprites, one for engine on and one for engine off).
The algorithm used here is fairly simple: generate a certain number of points spaced evenly around a circle. Then, set the radius at each point to a random value.
for (int i = 0; i < numberOfVertices; i++)
float angle = 2 * pi * (float)i / numberOfVertices;
float radius = random between minRadius, maxRadius;
Vertex = Vector2(radius * cos(angle), radius * sin(angle));
The number of vertices and the exact overall size of the asteroid can both be varied as well. Velocity and, if the asteroid needs to spin, the rate of rotation should also be random. angle could also be varied randomly, possibly by applying a random offset.
Alternatively, a set of points with random positions (in either cartesian or polar coordinates) could be generated, and the resulting array sorted by polar angle.
Next time: Bullets, collision detection and scoring.