Changes to camera.cpp

Now that we have added a desired position attribute to the class definition, we need to change our camera.cpp file. We need to modify the constructor to set the position of the camera to the position of the player's ship. Here are the lines we will need to add to our constructor:

m_Position = player->m_Position;
m_Position.x -= CANVAS_WIDTH / 2;
m_Position.y -= CANVAS_HEIGHT / 2;

The following is the constructor after we have added those lines:

Camera::Camera( float width, float height ) {
m_HalfWidth = width / 2;
m_HalfHeight = height / 2;

m_Position = player->m_Position;
m_Position.x -= CANVAS_WIDTH / 2;
m_Position.y -= CANVAS_HEIGHT / 2;
}

Our Camera::Move function will be entirely different. You might as well remove all of the lines of code that are in the current version of Camera::Move, because none of them are useful anymore. Our new desired position attribute will be set at the beginning of the Move function, the way that the position was set previously. To do this, add the following lines to the empty version of Camera::Move that you created by deleting everything from that function:

m_DesiredPosition = player->m_Position;
m_DesiredPosition.x -= CANVAS_WIDTH / 2;
m_DesiredPosition.y -= CANVAS_HEIGHT / 2;

If the player is not alive, we will want our camera to settle down on this position. After the player is dead, we will not want any attractors to affect the position of the camera. Moving the player camera too much after the player dies looks a little strange, so add the following lines of code that check whether the player's ship is active and, if not, moves the position of the camera toward the desired position and, then returns from the Move function:

if( player->m_Active == false ) {
m_Position.x = m_Position.x + (m_DesiredPosition.x - m_Position.x)
* delta_time;
m_Position.y = m_Position.y + (m_DesiredPosition.y - m_Position.y)
* delta_time;
return;
}

We are going to make all of the active projectiles in our game attractors. If an enemy is shooting at us, it is a threat to our ship and  should therefore draw the camera's attention. If we shoot projectiles, that also indicates the direction where we are focused. We are going to use a for loop to loop over all of the projectiles in our game, and, if that projectile is active, we will use its position to shift the desired position of our camera. Here is the code:

Projectile* projectile;
std::vector<Projectile*>::iterator it;
Vector2D attractor;
for( it = projectile_pool->m_ProjectileList.begin(); it != projectile_pool->m_ProjectileList.end(); it++ ) {
projectile = *it;
if( projectile->m_Active ) {
attractor = projectile->m_Position;
attractor -= player->m_Position;
attractor.Normalize();
attractor *= 5;
m_DesiredPosition += attractor;
}
}

After using our attractors to shift the desired position of the camera, we will modify the m_DesiredPosition variable based on the velocity of the player's ship with the following line of code:

m_DesiredPosition += player->m_Velocity * 2;

Because our level wraps around, and if you exit from one side of the level you reappear on the opposite side, we will need to adjust the desired position of our camera to account for this. Without the following lines of code, the camera makes a sudden jarring transition when the player moves outside the level bounds on one side and reappears on the other:

 

if( abs(m_DesiredPosition.x - m_Position.x) > CANVAS_WIDTH ) {
if( m_DesiredPosition.x > m_Position.x ) {
m_Position.x += LEVEL_WIDTH;
}
else {
m_Position.x -= LEVEL_WIDTH;
}
}
if( abs(m_DesiredPosition.y - m_Position.y) > CANVAS_HEIGHT ) {
if( m_DesiredPosition.y > m_Position.y ) {
m_Position.y += LEVEL_HEIGHT;
}
else {
m_Position.y -= LEVEL_HEIGHT;
}
}

Finally, we will add a few lines of code to smoothly transition the camera's current position to the desired position. We use delta_time to make this transition take about a second. Setting our camera position directly instead of using the desired position and transitioning results in jerky movements when new attractors enter the game. Here is the transition code:

m_Position.x = m_Position.x + (m_DesiredPosition.x - m_Position.x) * 
delta_time;
m_Position.y = m_Position.y + (m_DesiredPosition.y - m_Position.y) *
delta_time;

Now that we have seen all of the lines of our Move function separately, let's take a look at the completed new version of the function:

void Camera::Move() {
m_DesiredPosition = player->m_Position;
m_DesiredPosition.x -= CANVAS_WIDTH / 2;
m_DesiredPosition.y -= CANVAS_HEIGHT / 2;

if( player->m_Active == false ) {
m_Position.x = m_Position.x + (m_DesiredPosition.x - m_Position.x)
* delta_time;
m_Position.y = m_Position.y + (m_DesiredPosition.y - m_Position.y)
* delta_time;
return;
}

Projectile* projectile;
std::vector<Projectile*>::iterator it;
Vector2D attractor;

for( it = projectile_pool->m_ProjectileList.begin();
it != projectile_pool->m_ProjectileList.end(); it++ ) {
projectile = *it;
if( projectile->m_Active ) {
attractor = projectile->m_Position;
attractor -= player->m_Position;
attractor.Normalize();
attractor *= 5;
m_DesiredPosition += attractor;
}
}
m_DesiredPosition += player->m_Velocity * 2;

if( abs(m_DesiredPosition.x - m_Position.x) > CANVAS_WIDTH ) {
if( m_DesiredPosition.x > m_Position.x ) {
m_Position.x += LEVEL_WIDTH;
}
else {
m_Position.x -= LEVEL_WIDTH;
}
}

if( abs(m_DesiredPosition.y - m_Position.y) > CANVAS_HEIGHT ) {
if( m_DesiredPosition.y > m_Position.y ) {
m_Position.y += LEVEL_HEIGHT;
}
else {
m_Position.y -= LEVEL_HEIGHT;
}
}

m_Position.x = m_Position.x + (m_DesiredPosition.x - m_Position.x) *
delta_time;
m_Position.y = m_Position.y + (m_DesiredPosition.y - m_Position.y) *
delta_time;
}