- Game Development Patterns and Best Practices
- John P. Doran Matt Casanova
- 694字
- 2021-07-02 23:43:48
The monolithic game object
The easy way to do a game object is to have a single struct that contains all of the data a game object will need. This seems correct because everything in the game has the same basic data. For example, we know players and enemies all have a position, scale, and rotation. So our struct will look like this:
struct GameObject
{
//using vectors from the Mach 5 Engine
M5Vec2 pos;
M5Vec2 scale;
float rotation;
};
This game object works well in theory, but it is too basic. It is true that everything in our game probably needs a position, scale, and rotation. Even an invisible trigger region needs these properties. However, as it stands, we can't draw our object: we have no health, and no way to do damage. So, let's add a few things to make the game object a little more real:
struct Object
{
//using vectors from the Mach 5 Engine
M5Vec2 pos;
M5Vec2 scale;
float rotation;
float damage;
int health;
int textureID; //for drawing
float textureCoords[4]; //for sprite animation
unsignedchar color[4]; //the color of our image
};
Now we have added a few more basic elements to our game object. Most of our game object types will have health and damage, and we have added a texture ID so we can draw our game object, and some texture coordinates so we can use a sprite sheet for animation. Finally, we added a color so we can reuse the same texture and color it differently for different enemies (think about the different ghosts in Namco's Pacman).
This is not that bad yet but, unfortunately, this is just the beginning. Once we start making a real game instead of just brainstorming about a basic game object, our struct member count starts to explode.
Imagine we are making a Space Shooter. There are lots of things we will want to add:
- The player will have multiple types of weapons that all do different amounts of damage
- The player might have access to bombs and missiles that each have an ammo count
- The missile needs a target to seek
- The bomb needs an explosion radius
- There are two super enemies that each have a special ability with a cool-down time
- The player and one super enemy both have the ability to use a shield
- The UI buttons have some actions associated with clicking them
- We have power-ups that add health and add lives
- We need to add a lives count to all objects to account for the power up
- We should add velocity to objects and do time-based movement instead of just setting the position directly
- We need to add an enumeration for the type of the game object so we can update it properly
Here is what our game object looks like now:
struct GameObject
{
M5Vec2 pos;
M5Vec2 scale;
M5Vec2 vel;
float rotation;
ObjectType type; //Our object type enum
int objectID; //So the missile can target
int lives;
int shieldHealth; //For Player and SuperBomber
int health;
float playerLaserDamage;
float playerIonDamage;
float playerWaveCannonDamage;
float superRaiderDamage;
float superRaiderAbilityDamage;
float superRaiderAbilityCoolDownTime;
float superBomberDamage;
float superBomberAbilityDamage;
float superBomberAbilityCoolDownTime;
int bombCount;
float bombRadius;
int missileCount;
int missileTargetID;
int textureID; //the object image
float textureCoords[4];//for sprite animation
unsigned char color[4]; //the color of our image
Command* command; //The command to do
};
As you can see, this basic method of creating a game object doesn't scale very well. We already have more than 25 members in our struct and we haven't even talked about adding space stations that can spawn or repair units. We have only two boss types, we can make a few enemy types by allowing different enemies to use different player weapons such as the laser or missiles, but we are still limited.
The major problem with this approach is that, as the game gets bigger, our game object must also get very big. Some types, such as the player, will use many of these members, but other types, such as a UI button, will only use a small amount. This means if we have lots of game objects, we are very likely wasting a lot of memory per object.