官术网_书友最值得收藏!

Pooling the player's projectiles

Now that we have looked at the class definitions for our Projectile and ProjectilePool classes, we need to create a projectile.cpp file and a projectile_pool.cpp file to store the function code for those classes. Because this is in Chapter 6Game Objects and the Game Loop, I would recommend creating a new folder named Chapter06 to hold these files.  This code will do the work of pooling our projectiles, requesting an inactive projectile when we need one, and moving and rendering our active projectiles. First, let's look at the code we have in projectile.cpp:

#include "game.hpp"

Projectile::Projectile() {
m_Active = false;
m_X = 0.0;
m_Y = 0.0;
m_VX = 0.0;
m_VY = 0.0;

SDL_Surface *temp_surface = IMG_Load( c_SpriteFile );

if( !temp_surface ) {
printf("failed to load image: %s\n", IMG_GetError() );
return;
}

m_SpriteTexture = SDL_CreateTextureFromSurface( renderer,
temp_surface );

if( !m_SpriteTexture ) {
printf("failed to create texture: %s\n", IMG_GetError() );
return;
}

SDL_FreeSurface( temp_surface );
}

void Projectile::Move() {
m_X += m_VX;
m_Y += m_VY;
m_TTL -= diff_time;

if( m_TTL <= 0 ) {
m_Active = false;
m_TTL = 0;
}
}

void Projectile::Render() {
dest.x = m_X;
dest.y = m_Y;
dest.w = c_Width;
dest.h = c_Height;

int return_val = SDL_RenderCopy( renderer, m_SpriteTexture,
NULL, &dest );
if( return_val != 0 ) {
printf("SDL_Init failed: %s\n", SDL_GetError());
}
}

void Projectile::Launch(float x, float y, float dx, float dy) {
m_X = x;
m_Y = y;
m_VX = c_Velocity * dx;
m_VY = c_Velocity * dy;
m_TTL = c_AliveTime;
m_Active = true;
}

That is the code that deals with moving, rendering, and launching a single projectile. The first function declared here is the constructor:

Projectile::Projectile() {
m_Active = false;
m_X = 0.0;
m_Y = 0.0;
m_VX = 0.0;
m_VY = 0.0;

SDL_Surface *temp_surface = IMG_Load( c_SpriteFile );

if( !temp_surface ) {
printf("failed to load image: %s\n", IMG_GetError() );
return;
}

m_SpriteTexture = SDL_CreateTextureFromSurface( renderer,
temp_surface );

if( !m_SpriteTexture ) {
printf("failed to create texture: %s\n", IMG_GetError() );
return;
}
SDL_FreeSurface( temp_surface );
}

The primary concern of this constructor is to set the projectile to inactive and create an SDL texture that we will later use to render our sprite to the canvas element. After defining our constructor, we define our Move function:

void Projectile::Move() {
m_X += m_VX;
m_Y += m_VY;
m_TTL -= diff_time;
if( m_TTL <= 0 ) {
m_Active = false;
m_TTL = 0;
}
}

This function changes the x and y position of our projectile based on the velocity, and reduces the time to live of our projectile, setting it to inactive and recycling it into the projectile pool if it's time to live is less than or equal to zero. The next function we define is our Render function:

void Projectile::Render() {
dest.x = m_X;
dest.y = m_Y;
dest.w = c_Width;
dest.h = c_Height;

int return_val = SDL_RenderCopy( renderer, m_SpriteTexture,
NULL, &dest );

if( return_val != 0 ) {
printf("SDL_Init failed: %s\n", SDL_GetError());
}
}

This code is similar to the code we used to render our spaceship, so it should look pretty familiar to you. Our final projectile function is the Launch function:

void Projectile::Launch(float x, float y, float dx, float dy) {
m_X = x;
m_Y = y;
m_VX = c_Velocity * dx;
m_VY = c_Velocity * dy;
m_TTL = c_AliveTime;
m_Active = true;
}

This function is called from the PlayerShip class whenever the player presses the spacebar on the keyboard. The PlayerShip object will pass in the x and y coordinates of the player's ship, as well as the direction the ship is facing in the dx and dy parameters. These parameters are used to set the x and y coordinates for the projectile as well as the x and y velocity of the projectile. The game sets the time to live to the default alive time and then sets the object to active.

Now that we have fully defined our Projectile class, let's set the ProjectilePool class that will manage those projectiles. The following code will be in our projectile_pool.cpp file:

#include "game.hpp"

ProjectilePool::ProjectilePool() {
for( int i = 0; i < 10; i++ ) {
m_ProjectileList.push_back( new Projectile() );
}
}

ProjectilePool::~ProjectilePool() {
m_ProjectileList.clear();
}

void ProjectilePool::MoveProjectiles() {
Projectile* projectile;
std::vector<Projectile*>::iterator it;

for( it = m_ProjectileList.begin(); it != m_ProjectileList.end(); it++ ) {
projectile = *it;
if( projectile->m_Active ) {
projectile->Move();
}
}
}

void ProjectilePool::RenderProjectiles() {
Projectile* projectile;
std::vector<Projectile*>::iterator it;

for( it = m_ProjectileList.begin(); it != m_ProjectileList.end(); it++ ) {
projectile = *it;
if( projectile->m_Active ) {
projectile->Render();
}
}
}

Projectile* ProjectilePool::GetFreeProjectile() {
Projectile* projectile;
std::vector<Projectile*>::iterator it;

for( it = m_ProjectileList.begin(); it != m_ProjectileList.end(); it++ ) {
projectile = *it;
if( projectile->m_Active == false ) {
return projectile;
}
}
return NULL;
}

The first two functions are the constructor and destructor functions. These functions create and destroy the projectiles inside our list. The next function is the MoveProjectiles function, which loops through our m_ProjectileList looking for active projectiles and moving them. After that, we have a RenderProjectiles function, which is quite similar to our MoveProjectiles function. This function loops through our list calling the Render function on all active projectiles. The final function is the GetFreeProjectile function, which steps through m_ProjectileList looking for the first projectile that is not active in order to return it. Whenever we want to launch a projectile, we will need to call this function to find one that is not active.

主站蜘蛛池模板: 秀山| 同心县| 永嘉县| 无锡市| 铜山县| 晋城| 甘孜| 贵定县| 永康市| 当雄县| 赫章县| 秦安县| 蕉岭县| 泗洪县| 城口县| 遂昌县| 中西区| 辽源市| 咸阳市| 满城县| 南平市| 克什克腾旗| 海淀区| 高要市| 新和县| 文安县| 张家口市| 长白| 上虞市| 哈密市| 洛川县| 双城市| 安仁县| 棋牌| 台山市| 丰都县| 陇西县| 庄浪县| 民丰县| 宝应县| 普兰县|