Changing the game.hpp file

To get physics into our game, we will need to modify several class definitions and add new #define macros. Let's start by updating our game.hpp file. The first thing we need to add is #define in order to set up a constant value for our star's mass. I want to have a large constant value for the star mass that we will check against in our ElasticCollision function. If the mass of either object in our elastic collision is the same value as STAR_MASS, we do not want to accelerate that object. In reality, if you were to throw a rock into the sun, you would accelerate the sun a tiny, tiny amount in the direction you threw the rock. This amount would be so small relative to the sun that it would be undetectable. We will have a fixed value for the star's mass where any objects with a mass that size will not accelerate when hit by any objects in our game. To do this, we will need to add the following #define:

#define STAR_MASS 9999999

After adding the #define, we will need to modify our Collider class, giving it a new ElasticCollision function. This function will take in a second Collider object and use the velocity and masses of those two objects to determine what their new velocities will be. We will also need to add a mass attribute that we will name m_Mass. Finally, we need to move two attributes into our Collider class that was previously in the child classes of Collider. These variables are the 2D m_Direction and m_Velocity vectors because our elastic collision function will need this data to calculate the new velocities. This is what the new version of the Collider class looks like:

class Collider {
public:
bool m_Active;
float* m_ParentRotation;
float* m_ParentX;
float* m_ParentY;
Vector2D m_TempPoint;

bool CCHitTest( Collider* collider );

void ElasticCollision( Collider* collider );
float m_Mass;
Vector2D m_Direction;
Vector2D m_Velocity;
Vector2D m_Position;

float m_Radius;
float m_SteeringRadius;
float m_SteeringRadiusSQ;
void SetParentInformation( float* rotation, float* x, float* y );

Collider(float radius);
bool HitTest( Collider *collider );
bool SteeringLineTest( Vector2D &p1, Vector2D &p2 );
bool SteeringRectTest( Vector2D &start_point, Vector2D
&end_point );
void WrapPosition();
};

The four lines we added are near the center of this new version of the class:

void ElasticCollision( Collider* collider );
float m_Mass;
Vector2D m_Direction;
Vector2D m_Velocity;

After adding m_Direction and m_Velocity to our Collider class, we need to remove m_Velocity from three of the child classes where we had that code in previous versions of our game. We need to remove those attributes from the Asteroid, Ship, and Projectile classes. Here are the two lines we need to remove:

Vector2D m_Direction;
Vector2D m_Velocity;

In the following code snippet, we have the Asteroid class after you have removed those two lines:

class Asteroid : public Collider {
public:
SDL_Texture *m_SpriteTexture;
SDL_Rect m_src = {.x = 0, .y = 0, .w = 16, .h = 16 };
SDL_Rect m_dest = {.x = 0, .y = 0, .w = 0, .h = 0 };

Uint32 m_CurrentFrame = 0;
int m_NextFrameTime;
float m_Rotation;

Emitter* m_Explode;
Emitter* m_Chunks;

Asteroid( float x, float y,
float velocity,
float rotation );

void Move();
void Render();
void Explode();
};

This is what the Ship class will look like after you have removed those two lines:

class Ship : public Collider {
public:
const float c_Acceleration = 10.0f;
const float c_MaxVelocity = 100.0f;
const int c_AliveTime = 2000;
const Uint32 c_MinLaunchTime = 300;

bool m_Accelerating = false;
Uint32 m_LastLaunchTime;
const int c_Width = 32;
const int c_Height = 32;
SDL_Texture *m_SpriteTexture;
SDL_Rect src = {.x = 0, .y = 0, .w = 32, .h = 32 };

Emitter* m_Explode;
Emitter* m_Exhaust;
Shield* m_Shield;
std::vector<Collider*> m_Colliders;

Uint32 m_CurrentFrame = 0;
int m_NextFrameTime;
float m_Rotation;

void RotateLeft();
void RotateRight();
void Accelerate();
void Decelerate();
void CapVelocity();
void Shoot();
virtual void Move() = 0;
Ship();
void Render();
bool CompoundHitTest( Collider* collider );
};

Finally, here is what the Projectile class will look like after you have removed those two lines:

class Projectile: public Collider {
public:
const char* c_SpriteFile = "sprites/ProjectileExp.png";
const int c_Width = 16;
const int c_Height = 16;
SDL_Texture *m_SpriteTexture;
SDL_Rect src = {.x = 0, .y = 0, .w = 16, .h = 16 };

Uint32 m_CurrentFrame = 0;
int m_NextFrameTime;
const float c_Velocity = 300.0;
const float c_AliveTime = 2000;
float m_TTL;

Projectile();
void Move();
void Render();
void Launch(Vector2D &position, Vector2D &direction);
};

The last class we must change is our Star class. The Star class is now going to be able to attract the spaceships in our game gravitationally. To do this, we will be adding a constant attribute that defines the maximum range of our gravitational force. In reality, gravity extends on forever, but for our game, we do not want the gravity to affect our spaceships when the star is off-screen (or at least very far off-screen). Because of this, we are going to limit the distance of the gravitational effect to 500 pixels. We will also add a new function to our class called ShipGravity. We will be passing a Ship object into this function, and the function will modify the velocity of the ship based on the squared distance to the Star object. This is what the new version of the Star class definition will look like:

class Star : public Collider {
public:
const float c_MaxGravityDistSQ = 250000.0; // 300 squared

SDL_Texture *m_SpriteTexture;
SDL_Rect m_src = {.x = 0, .y = 0, .w = 64, .h = 64 };
SDL_Rect m_dest = {.x = 0, .y = 0, .w = 64, .h = 64 };

std::vector<Emitter*> m_FlareList;

Uint32 m_CurrentFrame = 0;
int m_NextFrameTime;

Star();

void Move();
void Render();

void ShipGravity( Ship* s );
};