• No results found

The Entity Class

In document Programming 2D Games - Charles Kelly (Page 173-178)

6 Collisions and Entities

6.3 The Entity Class

// Set collision vector

collisionVector = *ent.getCenter() - corner;

return true;

}

return false;

}

Listing 6.10. The collideCornerCircle function is used when a circle is in the Voronoi region of a box.

6.3 The Entity Class

The collision code we have been creating is part of the new Entity class. The Entity class inherits from the Image class and adds the following:

• The ability to collide with other entities.

• Health property and related functions.

• Velocity and delta velocity for movement control.

• Mass property and gravity functions.

• Artificial intelligence shell function.

When we want to create a game item that has any of these new properties or capa-bilities, we will create a new class that inherits from Entity. Since the Entity class inherits from the Image class, all of the properties and functions of Image are also part of Entity.

The new Entity properties are as follows:

entityNS::COLLISION_TYPE collisionType. The collision type: NONE, CIRCLE, BOX, or ROTATED_BOX.

VECTOR2 center. The center of the entity.

floatradius. Defines the radius of the circle used for circular collision detection.

RECT edge. The rectangular region used by BOX or ROTATED_BOX collision detec-tion. The edge members are left, right, top, and bottom. The collision box is specified relative to the entity center. A collision box that is 16 pixels tall and 28 pixels wide would be specified as: top = -8; edge.bottom = 8; edge.left = -14;

edge.right = 14;

VECTOR2velocity. The vector containing the current entity velocity.

161 6.3. The Entity Class

floatmass. The mass of the entity.

floathealth. Health of the entity from 0 to 100.

boolactive. The current state of this entity; only active entities may collide.

The entity class also contains a number of variables used during collision detection.The entity.h header file contains some simple set and get functions for the new variables.

The other functions are in entity.cpp. The constructor does simple variable initialization (Listing 6.11).

The function Entity::initialize receives a pointer to the current game engine, the width, the height, and number of columns in the texture image, and a pointer to a TextureManager object. The gamePtr pointer is used to retrieve the current input sys-tem, which is saved to the local input pointer. Image::initialize is called inside a return statement, which passes the return value from Image::initialize back to the caller of Entity::initialize (Listing 6.12).

// Programming 2D Games

collisionType = entityNS::CIRCLE;

health = 100;

gravity = entityNS::GRAVITY;

}

Listing 6.11. The Entity class constructor.

//========================================================================

// Initialize the Entity

// Pre: *gamePtr = pointer to Game object

162 6. Collisions and Entities // width = width of Image in pixels (0 = use full texture width) // height = height of Image in pixels (0 = use full texture height) // ncols = number of columns in texture (1 to n) (0 same as 1) // *textureM = pointer to TextureManager object

// Post: returns true if successful, false if failed

//========================================================================

bool Entity::initialize(Game *gamePtr, int width, int height, int ncols, TextureManager *textureM)

{ input = gamePtr->getInput(); // The input system return(Image::initialize(gamePtr->getGraphics(),width,height,ncols, textureM));

}

Listing 6.12. The Entity::initialize function.

The default behavior of the Entity::activate function is simply to set active to true. The function is provided in case a user-created entity requires a more complex logic to activate (Listing 6.13).

//========================================================================

// Activate the entity

//========================================================================

void Entity::activate() { active = true;

}

Listing 6.13. The simple Entity::activate function may be overridden for more complex entities.

The Entity::update function adds deltaV to the velocity vector and then clears deltaV. The deltaV variable is set in Entity::bounce (see Listing 6.20). Classes that derive from Entity should use the velocity vector to update the position. The Image::update function is called and rotatedBoxReady is set to false to indicate that BOX and ROTATED_BOX collision detection need to call computeRotatedBox before using the bounding box for collision detection (Listing 6.14).

//========================================================================

// Update

// Typically called once per frame

// frameTime is used to regulate the speed of movement and animation //========================================================================

void Entity::update(float frameTime) { velocity += deltaV;

deltaV.x = 0;

deltaV.y = 0;

Image::update(frameTime);

163 6.3. The Entity Class

rotatedBoxReady = false; // For rotatedBox collision detection }

Listing 6.14. Updating the entity’s velocity and Image.

//========================================================================

// ai (artificial intelligence) // Typically called once per frame

// Performs ai calculations, ent is passed for interaction

//========================================================================

void Entity::ai(float frameTime, Entity &ent) {}

Listing 6.15. The Empty::ai function allows Entity objects to be created.

The Entity::ai function is a simple placeholder. The entity has no default artificial intelligence. We chose to use an empty function here instead of a pure virtual function. A pure virtual function would require any derived class to provide the function code. Provid-ing the empty function, as we do here, allows objects of the Entity class to be instantiated.

That allows us to create objects from the Entity class directly. The ability to create Entity objects might be handy if we want to do some rapid prototyping for our game (Listing 6.15).

The Entity::collidesWith function (Listing 6.16) checks to see if this entity is colliding with the entity passed in the ent parameter. The collision type used by each entity is determined and the appropriated collision function is called. Entities default to CIRCLE collision. To change the collision method used by derived classes of entity, set the collisionType variable to one of the following collision types:

entityNS::CIRCLE, entityNS::BOX or entityNS::ROTATED_BOX.

//========================================================================

// Perform collision detection between this entity and the other Entity // Each entity must use a single collision type. Complex shapes that // require multiple collision types may be done by treating each part as a // separate entity.

// Typically called once per frame

// The collision types: CIRCLE, BOX, or ROTATED_BOX // Post: returns true if collision, false otherwise // sets collisionVector if collision

//========================================================================

bool Entity::collidesWith(Entity &ent, VECTOR2 &collisionVector) { // If either entity is not active then no collision may occcur if (!active || !ent.getActive())

return false;

// If both entities are CIRCLE collision if (collisionType == entityNS::CIRCLE &&

164 6. Collisions and Entities ent.getCollisionType() == entityNS::CIRCLE)

return collideCircle(ent, collisionVector);

// If both entities are BOX collision

if (collisionType == entityNS::BOX && ent.getCollisionType() == entityNS::BOX)

return collideBox(ent, collisionVector);

// All other combinations use separating axis test // If neither entity uses CIRCLE collision

if (collisionType != entityNS::CIRCLE &&

ent.getCollisionType() != entityNS::CIRCLE) return collideRotatedBox(ent, collisionVector);

else // One of the entities is a circle // If this entity uses CIRCLE collision if (collisionType == entityNS::CIRCLE)

return ent.collideRotatedBoxCircle(*this, collisionVector);

else // The other entity uses CIRCLE collision

return collideRotatedBoxCircle(ent, collisionVector);

return false;

}

Listing 6.16. Does this entity collide with the ent entity?

The Entity::outsideRect function returns true if the current entity is outside the specified rectangle. This function might be useful to test if our player is inside a special area of the game (Listing 6.17).

//========================================================================

// Is this Entity outside the specified rectangle // Post: returns true if outside rect, false otherwise

//========================================================================

bool Entity::outsideRect(RECT rect)

{ if( spriteData.x + spriteData.width*getScale() < rect.left ||

spriteData.x > rect.right ||

spriteData.y + spriteData.height*getScale() < rect.top ||

spriteData.y > rect.bottom) return true;

return false;

}

Listing 6.17. Is the entity outside the specified rectangle?

The Entity class includes an empty damage function. The damage function will be called when the entity is damaged by a weapon. Currently, the Entity class has no idea about the details of the entity, so the function is empty. Normally this function will be over-ridden by the deriving class to provide appropriate damage. Providing an empty function in the Entity class permits Entity objects to be instantiated if desired (Listing 6.18).

165

In document Programming 2D Games - Charles Kelly (Page 173-178)