Planetoid Game - by Matthew Glanfield

an OpenGL Game by Matthew Glanfield
COSC 3P98 Final Project

Home Screenshots Sounds User Manual Main Class Design Other Gaming Sites  

Planetoid Game - Main Class Design

The entire Planetoid game was designed and built around an object-oriented environment. Every object in the game is an instance of a class, and they each interact with other objects on the screen.

Sprite Class

The Sprite class is the basis of all other classes in this game. A sprite is any object on the screen that has 3D cooridinates and that can possibly move.

The main definition code for the Sprite class is as follows:

/* Sprite - this represents any moveable object on the screen */
class Sprite {
protected:
	float x, y, z;		// position of enemy
	float vx, vy, vz;	// speed of enemy
	bool alive;			// state of enemy
	float timer;		// time since last movement
	float radius;		// radius of bounding circle

	virtual void updateAllTiming(float t) {};

public:
	Sprite *next;

	Sprite();
	Sprite(float, float, float, float, float, float);

	virtual void move();
	virtual void draw() {};
	bool shouldDie();
	void setRadius(float r) { radius = r; };
	bool collides(Sprite *other);
	bool collides(Sprite *other, float r);
	void setAlive(bool a) { alive = a; };
	bool isAlive() { return alive; };

	float getX() { return x; };
	float getY() { return y; };
	float getZ() { return z; };

	float distance(Sprite *other);

	virtual void remove() {};
	void updateTiming(float t) { timer += t; updateAllTiming(t); };
};

Those functions labeled "virtual" are ones that can be overridden by sub-classes. The most important one to override is the draw() function, which will define how the object will appear on the screen. As you can see from this code the Sprite class alone will not display anything on the screen.

Powerup Class

The Powerup class represents any of the five different powerups on the screen. I chose to include all the powerups in this class rather than forcing sub-classing in order to keep the programming simpler. Since each powerup is so similar there was no need to further expand on this class.

The code for the Powerup class is as follows:

/* Powerup - this represents powerups that the player can shoot at */
class Powerup: public Sprite {
private:
	int type;

public:
	Powerup();
	Powerup(int, float, float, float, float, float, float);
	void draw();
	int getType() { return type; };
};

The type attribute specifies which kind of powerup the class is. These are predefined as follows:

// powerup definitions
#define POWERUP_HP		0	// healing powerup
#define POWERUP_DMG		1	// weapon damage upgrade
#define POWERUP_UPGRADE	2	// weapon upgrade
#define POWERUP_ABOMB	3	// additional abomb
#define POWERUP_PASS	4	// weapon pass-through upgrade

Enemy Class

The Enemy class is the basis for all enemies on the screen. The base Enemy class is used directly for all normal enemies.

The code is as follows:

/* Enemy - this class represents any type of enemy (whether intelligent or not) that will be
trying to kill the player */
class Enemy : public Sprite {
protected:
	int hitPoints;	// hitpoints of enemy
	int r, g, b;	// color of enemy
	int type;		// type of enemy

public:
	Enemy();
	Enemy(float, float, float, float, float, float);

	void draw();
	void setHitPoints(int h) { hitPoints = h; };
	void hit(Projectile *p);
	int getHitPoints() { return hitPoints; };
	void setColor(int rc, int gc, int bc) { r = rc; g = gc; b = bc; };
	void setType(int t) { type = t; };
	void die();
};

The hitPoints determine both how many hits it will take to kill the enemy and how much damage it will do to the player when it collides with the spaceship.

FiringEnemy Class

The FiringEnemy class represents the enemies that move back and forth and fire at the player. Their projectiles are actually small Enemy class instances.

Their code is as follows:

/* FiringEnemy - this represents an enemy that moves back and forth and fires at the player */
class FiringEnemy : public Enemy {
protected:
	float lastFired;	// last time the enemy fired
	float fireRate;		// rate at which enemy can fire
	int dmg;			// damage that this enemy inflicts

	virtual void updateAllTiming(float t) { lastFired += t; };

public:
	FiringEnemy();
	FiringEnemy(float, float, float, float, float, float);

	void move();
	virtual void remove() { global.numFiringEnemies--; };
	void setFireRate(float f) { fireRate = f; };
	void setDamage(int d) { dmg = d; };
};

You can see that the FiringEnemy overrides the remove function. This ensures that whenever a FiringEnemy is removed the global counter is updated.

Boss Class

The Boss class represents the various bosses that are found throughout the game. They are mainly FiringEnemy enemies that are much larger and stronger.

Their code is as follows:

/* Boss - this represents a sub-boss */
class Boss : public FiringEnemy {
public:
	Boss(float, float, float, float, float, float);

	virtual void remove() { global.numBosses--; forceSound("boss_die.wav", 5); };
};

Projectile Class

The Projectile class represents any projectiles on the screen. The base class is used for the cannon shots that the player fires.

The code is as follows:

/* Projectile - this represents any projectile (e.g. bullets, rockets, debri) that is
  moving through space */
class Projectile : public Sprite {
protected:
	int damage;		// damage this projectile does
	int pass;		// how many enemies it will pass through
	int blast;		// blast radius
	int r, g, b;	// color of projectile

public:
	Projectile();
	Projectile(float, float, float, float, float, float);

	virtual void draw();
	void setDamage(int d) { damage = d; };
	int getDamage() { return damage; };
	virtual void hit(Enemy *e);
	void setPass(int p) { pass = p; };
	void setBlast(int b) { blast = b; };

	virtual void checkTarget() {};
};

ABomb Class

Since a-bombs are treated differently than regular projectiles a special class was required. The ABomb class takes care of these special weapons.

The code is as follows:

/* ABomb - this represents an abomb fired by the player */
class ABomb : public Projectile {
protected:
	float dieTime;

	virtual void updateAllTiming(float t) { dieTime += t; };

public:
	ABomb();

	virtual void move();
	virtual void draw();
	virtual void hit(Enemy *e) {};
};

The most important part is that the function hit is overridden, thus removing any consequences of the projectile hitting enemies while it floats away from the player.

Missile Class

The Missile class represents the weapon utility that fires out of the side(s) of the player's spaceship. They have special "heat-seeking" capabilities that required a separate class to be built.

The code is as follows:

/* Missle - this is a type of projectile that will look for the nearest target and go
after it */
class Missile : public Projectile {
private:
	int radar;			// radius of radar
	float lookTime;		// tracks last time an attempt was made to find a target
	bool hasTarget;		// target was found
	Sprite *target;		// target being tracked

	virtual void updateAllTiming(float t) { lookTime += t; };

public:
	Missile();
	Missile(int, float, float, float, float, float, float);

	void findTarget();
	void move();
	void checkTarget();
};

SpaceShip Class

The SpaceShip class represents the player's spaceship that resides in the middle of the screen.

The code is as follows:

/* SpaceShip - this class represents a ship that can be displayed on the screen.  It
  contains all information such as hitpoints, weapons, movement speeds, etc. */
class SpaceShip : public Sprite {
private:
	int hitPoints;		// current hitPoints (i.e. how much more damage the ship can take)
	float facing;		// direction ship is facing (in degrees)
	int dmg;			// weapon damage
	int wPass;			// number of enemies the weapon will pass through
	int blast;			// blast radius
	int missiles;		// number of missiles to be fired out
	float lastMissile;	// last missile time
	int aBombs;			// number of abombs left
	float lastABomb;	// last time an abomb was launched

	virtual void updateAllTiming(float t) { lastMissile += t; lastABomb += t; };

public:
	SpaceShip();
	void draw();
	void setFacing(float f) { facing = f; };
	void hit(Enemy *e);
	int getHitPoints() { return hitPoints; };
	int getWeaponDmg() { return dmg; };
	int getWeaponPass() { return wPass; };
	int getBlast() { return blast; };
	void getPowerup(Powerup* p);
	int getMissiles() { return missiles; };
	bool fireMissile();
	void fireABomb();
	int getABombs() { return aBombs; };
};

By examining the various functions you can see what the SpaceShip is able to do. It is able to getPowerups, fireMissiles, and fireABombs to name a few.

Animation Class

The Animation class was made to allow for explosion animations. I also created an Explosion class even though it was the only type of animation. I did this to make the game expandable to include animated enemies, animated projectiles, and maybe even an animated spaceship for the player.

The code is as follows:

/* Animation - this class represents an animation that is taking place on the screen. */
class Animation : public Sprite {
protected:
	int frame;			// current frame
	int numFrames;		// number of frames in this animation
	float frameRate;	// rate at which the frames change
	float frameTimer;	// used to regulate time for animation

	virtual void updateAllTiming(float t) { frameTimer += t; };

public:
	Animation();

	void updateFrame();
};

The class is basic and does not even have a draw() function. The updateFrame() function will need to be called by any child's draw() function to ensure that the proper frame is rendered.

Explosion Class

As described above, the Explosion class implements the Animation class to show any size explosion on the screen.

The code is as follows:

/* Explosion - this is a child of the Animation class and represents an explosion on the screen */
class Explosion : public Animation {
	int radius;

public:
	Explosion();
	Explosion(float, float, float, float, float, float, float);

	void draw();
};

Again the class is basic. The special animation is found in the draw() function:

/* draw the explosion to the screen */
void Explosion::draw() {
	// frames 1 - 8 are explosion growing, 9 and 10 are for explosion going away
	if (!global.paused) updateFrame();
	if (!alive) return;

	// store old matrix
	glPushMatrix();

	// load the identity and translate it
	glLoadIdentity();
	glTranslatef(x, y, z);

	if (frame <= 0.8 * numFrames) {
		float r = radius * frame / 5.0;
		glColor3ub(255, 255 - (140 * (frame - 1) / (numFrames * 0.8)), 0);
		glutSolidSphere(r, r, r);
	} else {
		float r = radius * (frame - numFrames * 0.8);
		glColor3ub(150, 150, 150);
		glutSolidSphere(r, r, r);
	}

	// restore previous matrix
	glPopMatrix();
};


Copyright © 2006 Matthew Glanfield
http://www.planetoidgame.com