C++ space shooter problem
Jag har ett prblem som jag inte lyckats hitta källan till. När jag skall avfyra ett skott (laser) så dyker det upp en kopia av mitt skepp (spriteObject). Jag har lyckats att få den att rita ut den rätta bilden också utöver skeppet.
När jag har avfyrat skottet så skall det färdas uppåt - y led och när skottet har lämnat rutan skall det gömmas. Detta händer inte utan de så kallade bilderna stannar kvar där skeppet är och stannar där.
Det är en hel del kod att gå igenom men tänkte om någon kunde lokalisera problemet.
PS: Kod för space tangenten är i Sprite::handle_input() i main samt i spel-loopen i main.
utöver det finns addBullet(), som adderar ett skott.
Min kod:
Sprite.h
#ifndef SPRITE_H
#define SPRITE_H
#include <SDL.h>
#include <SDL_image.h>
#include <string>
const int SS_WIDTH = 52;
const int SS_HEIGHT = 97;
const int SCREEN_WIDTH_W = 1024;
const int SCREEN_HEIGHT_H = 600;
class Sprite{
public:
Sprite(std::string name, std::string name_image, SDL_Surface* spriteImage);
Sprite();
virtual ~Sprite(){}
void setSpeed( int x, int y);
void setPos( int x, int y );
int get_x_pos() const;
int get_y_pos() const;
void handle_input();
void move();
void show();
int init( SDL_Surface* img, int w, int h );
void draw();
void xadd(int nr) { x_pos += nr; }
void yadd(int nr) { y_pos += nr; }
void xsub(int nr) { x_pos -= nr; }
void ysub(int nr) { y_pos -= nr; }
private:
std::string name, name_image;
int x_pos, y_pos, x_speed, y_speed, lives, score, mDrawn;
SDL_Surface* si;
SDL_Rect box;
};
#endif
Sprite.cpp
#include "sprite.h"
Sprite::Sprite(void){}
Sprite::Sprite(std::string name, std::string filename, SDL_Surface* spriteImage)
:name(name), name_image(filename)
{
//si=IMG_Load(name_image.c_str());
si = spriteImage;
x_pos = 500;
y_pos = 480;
x_speed = 0;
y_speed = 0;
}
void Sprite::setSpeed(/*Sprite* temp,*/ int x, int y){
this->x_speed += x, this->y_speed += y;
}
int Sprite::get_x_pos() const{
return this->x_pos;
}
int Sprite::get_y_pos(/*Sprite* temp*/) const{
return this->y_pos;
}
int Sprite::init( SDL_Surface* img, int w, int h )
{
si = img;
box.x = x_pos;
box.y = y_pos;
box.w = w;
box.h = h;
return 0;
}
void Sprite::setPos( int x, int y )
{
x_pos = x;
y_pos = y;
}
Main
#include <SDL.h>
#include <SDL_image.h>
#include <SDL_ttf.h>
#include <SDL_mixer.h>
#include "Sprite.h"
#include "Loader.h"
#include "Render.h"
#include <string>
#include <sstream>
//Screen sizes
const int SCREEN_WIDTH = 1000;
const int SCREEN_HEIGHT = 800;
const int SCREEN_BPP = 32;
//Frames per second
const int FRAMES_PER_SECOND = 60;
#define BULLETS 10
//Dot sizes
//const int DOT_HEIGHT = 20;
//const int DOT_WIDTH = 20;
//Spaceship sizes
//const int SS_HEIGHT = 97;
//const int SS_WIDTH = 52;
//The surfaces
SDL_Surface* screen = NULL;
SDL_Surface* background = NULL;
SDL_Surface* spriteObject = NULL;
SDL_Surface* asteroids = NULL;
SDL_Surface* message = NULL;
SDL_Surface* lives = NULL;
SDL_Surface* dot = NULL;
SDL_Surface* wep = NULL;
Sprite ship;
Sprite bullets[BULLETS];
int bdraw[BULLETS];
//Stores event data to be used.
SDL_Event event;
//The portions of the sprite map to be blitted
//Only use incase of sprite sheets.
SDL_Rect astro[16];
//The fonts thats gonna be used.
TTF_Font* font = NULL;
TTF_Font* lfont = NULL;
//The color of the font.
SDL_Color textColor = { 255, 255, 255 };
//The Camera
//SDL_Rect camera = { 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT };
//Sounds
//Music
Mix_Music* music = NULL;
//Sound Effects
Mix_Chunk* laser = NULL;
Mix_Chunk* explosion = NULL;
Mix_Chunk* GameOver = NULL;
////The dot that will move around on the screen
//class Dot
//{
//private:
// //The X and Y offsets of the dot
// int x, y;
// //The velocity of the dot
// int xVel, yVel;
//public:
// //Initiates the variables
// Dot();
// //Takes the key presses and adjusts the dot's velocity
// void handle_input();
// //Moves the dot
// void move();
// //shows the dot on the screen
// void show();
//};
/*
//Button class
class Button
{
private:
//The attributes of the button
SDL_Rect box;
//The part of the button sprite sheet that will be shown
SDL_Rect* clip;
public:
//Initialize the variables
Button( int x, int y, int w, int h );
//Handles events and set the button's sprite region
void handle_events();
//Shows the button on the screen
void show();
};
*/
//SDL_Surface* load_image(std::string filename) {
//
// //Temporary storage for the image that's loaded
// SDL_Surface* loadedImage = NULL;
// //The optimized image that will be used
// SDL_Surface* optimizedImage = NULL;
// //Load the image
// loadedImage = IMG_Load( filename.c_str() );
// //If nothing went wrong in loading the image
// if( loadedImage != NULL )
// {
// //Create an optimized image
// optimizedImage = SDL_DisplayFormat( loadedImage );
// //Free the old image
// SDL_FreeSurface( loadedImage );
// }
// /*
// //If the optimized image was done just fine.
// if( optimizedImage != NULL )
// {
// //Map the color key
// Uint32 colorkey = SDL_MapRGB( optimizedImage->format, 0, 0xFF, 0xFF );
// //Sets all the pixels of color R 0, G 0xFF to be
// //transparent
// SDL_SetColorKey( optimizedImage, SDL_SRCCOLORKEY, colorkey );
// }
// */
// //returns the optimized image
// return optimizedImage;
//}
void apply_surface( int x, int y, SDL_Surface* source, SDL_Surface* destination, SDL_Rect* astro = NULL, SDL_Rect* camera = NULL )
{
//Make a temporary rectangle to hold the offsets
SDL_Rect offset;
//Give the offsets to the rectangle
offset.x = x;
offset.y = y;
//Blit the surface
SDL_BlitSurface( source, astro, destination, &offset );
}
//Here is the initialization function. This function starts up SDL, sets up the window,
//sets the caption and returns false if there are any errors.
bool init()
{
if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 )
{
return false;
}
//Set up screen
screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE );
//check if screen loads correctly
if( screen == NULL )
{
return false;
}
//Initialize SDL_ttf
if( TTF_Init() == -1 )
{
return false;
}
///Initialize SDL_mixer
if( Mix_OpenAudio( 44100, MIX_DEFAULT_FORMAT, 2, 4096 ) == -1 )
{
return false;
}
//Set the window caption
SDL_WM_SetCaption( "Space Invaders", NULL );
return true;
}
bool load_files()
{
//Load images
spriteObject = load_image( "Images\\spaceship.png" );
background = load_image( "Images\\bigstar.png" );
asteroids = load_image( "Images\\asteroid-spread-sheet.png" );
dot = load_image( "Images\\dot.bmp" );
wep = load_image( "Images\\double-laser.png" );
//Open the font
font = TTF_OpenFont( "Fonts\\SLANT.ttf", 20 );
lfont = TTF_OpenFont( "Fonts\\SLANT.ttf", 22 );
//If there was any error loading the images.
if( spriteObject == NULL || background == NULL
|| asteroids == NULL || dot == NULL
|| wep == NULL )
{
return false;
}
//If there was any error loading the fonts.
if( font == NULL || lfont == NULL )
{
return false;
}
//load music
music = Mix_LoadMUS( "Sounds\\starship.wav" );
//If there was any error loading the music
if( music == NULL )
{
return false;
}
//Load sound effects
laser = Mix_LoadWAV( "Sounds\\laser.wav" );
//If there was any error loading the sound effects.
if( laser == NULL )
{
return false;
}
//If everything loaded fine.
return true;
}
void clean_up()
{
//Free's the loaded images
SDL_FreeSurface( spriteObject );
SDL_FreeSurface( background );
SDL_FreeSurface( message );
SDL_FreeSurface( asteroids );
SDL_FreeSurface( dot );
SDL_FreeSurface( wep );
//Close the font that was used
TTF_CloseFont( font );
TTF_CloseFont( lfont );
//Free the music files
Mix_FreeMusic( music );
//Free the sound effects
Mix_FreeChunk( laser );
//Quit SDL_mixer
Mix_CloseAudio();
//Quit SDL_ttf
TTF_Quit();
//Quit SDL
SDL_Quit();
}
/*
Button::Button( int x, int y, int w, int h )
{
//Set the button's attributes
box.x = x;
box.y = y;
box.w = w;
box.h = h;
}
void Button::handle_events()
{
//The mouse offset
int x = 0, y = 0;
//If a mouse button was pressed
if( event.type == SDL_MOUSEBUTTONDOWN )
{
//If the left mouse button was pressed
if( event.button.button == SDL_BUTTON_LEFT )
{
//Get the mouse offsets
x = event.button.x;
y = event.button.y;
//If the mouse is over the button
if( ( x > box.x ) && ( x < box.x + box.w ) && ( y > box.y ) && ( y < box.y + box.h ) )
{
//Set the button sprite
}
}
}}
*/
// The Timer
void addBullet()
{
for( int i = 0; i < BULLETS; i++ )
{
if(bdraw[i] == 0)
{
bullets[i].setPos(ship.get_x_pos()+3, ship.get_y_pos()+50);
bdraw[i] = 1;
return;
}
}
}
class Timer
{
private:
//The clock time when the timer started
int startTicks;
//the ticks stored when the timer was paused
int pausedTicks;
//The timer status
bool paused;
bool started;
public:
//Initializes variables
Timer();
//The various clock actions
void start();
void stop();
void paus();
void unpause();
//Gets the timer´s time
int get_ticks();
//checks the status of the timer
bool is_started();
bool is_paused();
};
Timer::Timer()
{
//Initializes the variables
startTicks = 0;
pausedTicks = 0;
paused = false;
started = false;
}
void Timer::start()
{
//start the timer
started = true;
//Unpause the timer
paused = false;
//Get the current clock time
startTicks = SDL_GetTicks();
}
void Timer::stop()
{
//Stop the timer
started = false;
//Unpause the timer
paused = false;
}
int Timer::get_ticks()
{
//If the timer is running
if( started == true )
{
//If the timer is paused
if( paused == true )
{
//Returns the number of ticks when
//the timer was paused
return pausedTicks;
}
else
{
//Returns the current time minus the start time
return SDL_GetTicks() - startTicks;
}
}
//If the timer isnt running
return 0;
}
void Timer::paus()
{
//If the timer is running and isn't already paused
if( (started == true ) && ( paused == false ) )
{
//Pause the timer
paused = true;
//Calculate the paused ticks
pausedTicks = SDL_GetTicks() - startTicks;
}
}
void Timer::unpause()
{
//If the timer is paused
if ( paused = true )
{
//Unpause the timer
paused = false;
//Reset the starting ticks
startTicks = SDL_GetTicks() - pausedTicks;
//Reset the paused ticks
pausedTicks = 0;
}
}
bool Timer::is_started()
{
return started;
}
bool Timer::is_paused()
{
return paused;
}
//Dot::Dot()
//{
// //Initializes the offsets
// x = 0;
// y = 0;
// //Initializes the velocity
// xVel = 0;
// yVel = 0;
//}
//void Dot::handle_input()
//{
// //If a key was pressed
// if( event.type == SDL_KEYDOWN )
// {
// //Adjust the velocity
// switch( event.key.keysym.sym )
// {
// case SDLK_UP: yVel -= DOT_HEIGHT / 2; break;
// case SDLK_DOWN: yVel += DOT_HEIGHT / 2; break;
// case SDLK_LEFT: xVel -= DOT_WIDTH / 2; break;
// case SDLK_RIGHT: xVel += DOT_WIDTH / 2; break;
// }
// }
// //If a key was released
// else if( event.type == SDL_KEYUP )
// {
// //Adjust the velocity
// switch( event.key.keysym.sym )
// {
// case SDLK_UP: yVel += DOT_HEIGHT / 2; break;
// case SDLK_DOWN: yVel -= DOT_HEIGHT / 2; break;
// case SDLK_LEFT: xVel += DOT_WIDTH / 2; break;
// case SDLK_RIGHT: xVel -= DOT_WIDTH / 2; break;
// }
// }
//}
//void Dot::move()
//{
// //Move the dot left or right
// x += xVel;
// //If the dot went too far to the left or right
// if( ( x < 0 ) || ( x + DOT_WIDTH > SCREEN_WIDTH ) )
// {
// //Move back
// x -= xVel;
// }
// //Move the dot up or down
// y += yVel;
// //If the dot went too far up or down
// if( ( y < 0 ) || ( y + DOT_HEIGHT > SCREEN_HEIGHT ) )
// {
// //Move back
// y -= yVel;
// }
//}
//void Dot::show()
//{
// //show the dot
// apply_surface( x, y, dot, screen );
//}
void render_Update()
{
apply_surface( 0, 0, background, screen );
apply_surface( 0, 0, asteroids, screen, &astro[ 0 ] );
apply_surface( 130, 20, asteroids, screen, &astro[ 1 ] );
apply_surface( 250, 75, asteroids, screen, &astro[ 2 ] );
apply_surface( 50, 150, asteroids, screen, &astro[ 3 ] );
apply_surface( 350, 30, asteroids, screen, &astro[ 4 ] );
apply_surface( 400, 170, asteroids, screen, &astro[ 5 ] );
apply_surface( 500, 50, asteroids, screen, &astro[ 6 ] );
apply_surface( 30, 300, asteroids, screen, &astro[ 7 ] );
apply_surface( 880, 0, asteroids, screen, &astro[ 8 ] );
apply_surface( 700, 300, asteroids, screen, &astro[ 9 ] );
apply_surface( 650, 175, asteroids, screen, &astro[ 10 ] );
apply_surface( 300, 300, asteroids, screen, &astro[ 11 ] );
apply_surface( 480, 300, asteroids, screen, &astro[ 12 ] );
apply_surface( 750, 0, asteroids, screen, &astro[ 13 ] );
apply_surface( 900, 150, asteroids, screen, &astro[ 14 ] );
apply_surface( 900, 300, asteroids, screen, &astro[ 15 ] );
apply_surface( 20, 560, message, screen );
apply_surface( 20, 580, lives, screen );
// Loop through all bullet-spots
for(int i = 0; i < BULLETS; i++)
//If we have a bullet in that spot, paint it.
if(bdraw[i] == 1 ) { bullets[i].draw();}
}
void Sprite::handle_input()
{
//If a key was pressed
if( event.type == SDL_KEYDOWN )
{
//Adjust the speed
switch( event.key.keysym.sym )
{
case SDLK_UP: y_speed -= SS_HEIGHT / 20; break;
case SDLK_DOWN: y_speed += SS_HEIGHT / 20; break;
case SDLK_LEFT: x_speed -= SS_WIDTH / 20; break;
case SDLK_RIGHT: x_speed += SS_WIDTH / 20; break;
case SDLK_SPACE: addBullet();
}
}
//If a key was released
else if( event.type == SDL_KEYUP )
{
//Adjust the speed
switch( event.key.keysym.sym )
{
case SDLK_UP: y_speed += SS_HEIGHT / 20; break;
case SDLK_DOWN: y_speed -= SS_HEIGHT / 20; break;
case SDLK_LEFT: x_speed += SS_WIDTH / 20; break;
case SDLK_RIGHT: x_speed -= SS_WIDTH / 20; break;
}
}
}
void Sprite::move()
{
//Move the SS left or right
x_pos += x_speed;
//If the SS went too far to the left or right
if( ( x_pos < 0 ) || ( x_pos + SS_WIDTH > SCREEN_WIDTH ) )
{
//Move back
x_pos -= x_speed;
}
//Move the SS up or down
y_pos += y_speed;
//If the SS went too far up or down
if( ( y_pos < 0 ) || ( y_pos + SS_HEIGHT > SCREEN_HEIGHT ) )
{
//Move back
y_pos -= y_speed;
}
// Loop through all bullets
for(int i = 0; i > BULLETS; i++ )
{
if(bdraw[i] == 1) // If they are visible
{
bullets[i].ysub(2); // Move them up 2 units at the time
if(bullets[i].get_y_pos() < 0) // If they are outside the screen
{
bdraw[i] = 0; // hide them
}
}
}
}
void Sprite::show()
{
apply_surface( x_pos, y_pos, spriteObject, screen );
}
void shoot()
{
//Get position of spriteObject
}
bool check_Collision( SDL_Rect A, SDL_Rect B )
{
//The sides of the rectangles
int leftA, leftB;
int rightA, rightB;
int topA, topB;
int bottomA, bottomB;
//Calculate the sides of rect A
leftA = A.x;
rightA = A.x + A.w;
topA = A.y;
bottomA = A.y + A.h;
//Calculate the sides of rect B
leftB = B.x;
rightB = B.x + B.w;
topB = B.y;
bottomB = B.y + B.h;
//If any of the sides from A are outside of B
if( bottomA <= topB )
{
return false;
}
if( topA >= bottomB )
{
return false;
}
if( rightA <= leftB )
{
return false;
}
if( leftA <= rightB )
{
return false;
}
//If none of the sides from A are outside B
return true;
}
bool check_Collision( Sprite* tmp, SDL_Rect rect )
{
int leftRect, rightRect, topRect, bottomRect;
leftRect = rect.x;
rightRect = rect.x + rect.w;
topRect = rect.y;
bottomRect = rect.y + rect.h;
//check for collision
if( ( tmp->get_x_pos() + SS_WIDTH ) <= ( leftRect ) )
{
return false;
}
if( ( tmp->get_x_pos() ) <= ( rightRect ) )
{
return false;
}
if( ( tmp->get_y_pos() + SS_HEIGHT ) <= ( topRect ) )
{
return false;
}
if( ( tmp->get_y_pos() ) >= ( bottomRect ) )
{
return false;
}
return true;
}
void Sprite::draw()
{
if( mDrawn == 0 ) mDrawn = 1;
SDL_Rect dest;
dest.x = x_pos; dest.y = y_pos;
/*SDL_BlitSurface(si, NULL, screen, & dest);*/
apply_surface(x_pos, y_pos, wep, screen );
}
int main( int argc, char* args[] )
{
/*********************************************************************/
//Initialize the sprites
//Sprite s1("spaceship", "spaceship-sprite.gif", spriteObject);
/*********************************************************************/
//Make sure the program waits for quit.
bool quit = false;
ship.init(spriteObject, SS_WIDTH, SS_HEIGHT);
ship.setPos(500, 600);
for(int i = 0; i < BULLETS; i++ )
bullets[i].init( wep, 35, 39 );
//Keep track of the current frame.
int frame = 0;
//Weather or not to cap the frame rate
bool cap = true;
//The frame rate regulator
Timer fps;
//Calls the init and file loading methods.
if( init() == false )
return 1;
if( load_files() == false )
return 1;
//Render the fonts
message = TTF_RenderText_Solid( font, "Score:", textColor );
lives = TTF_RenderText_Solid( lfont, "Lives:", textColor );
//If there was an error rendering the text
if( message == NULL || lives == NULL )
{
return 1;
}
/*************************************************************************/
//Sprite s1("spaceship", "spaceship.png", spriteObject);
/************************************************************************/
//Take the rects from the sprite sheet.
astro[ 0 ].x = 0;
astro[ 0 ].y = 0;
astro[ 0 ].w = 128;
astro[ 0 ].h = 128;
astro[ 1 ].x = 128;
astro[ 1 ].y = 0;
astro[ 1 ].w = 128;
astro[ 1 ].h = 128;
astro[ 2 ].x = 256;
astro[ 2 ].y = 0;
astro[ 2 ].w = 128;
astro[ 2 ].h = 128;
astro[ 3 ].x = 384;
astro[ 3 ].y = 0;
astro[ 3 ].w = 128;
astro[ 3 ].h = 128;
astro[ 4 ].x = 0;
astro[ 4 ].y = 128;
astro[ 4 ].w = 128;
astro[ 4 ].h = 128;
astro[ 5 ].x = 0;
astro[ 5 ].y = 256;
astro[ 5 ].w = 128;
astro[ 5 ].h = 128;
astro[ 6 ].x = 0;
astro[ 6 ].y = 384;
astro[ 6 ].w = 128;
astro[ 6 ].h = 128;
astro[ 7 ].x = 128;
astro[ 7 ].y = 128;
astro[ 7 ].w = 128;
astro[ 7 ].h = 128;
astro[ 8 ].x = 128;
astro[ 8 ].y = 256;
astro[ 8 ].w = 128;
astro[ 8 ].h = 128;
astro[ 9 ].x = 128;
astro[ 9 ].y = 384;
astro[ 9 ].w = 128;
astro[ 9 ].h = 128;
astro[ 10 ].x = 256;
astro[ 10 ].y = 128;
astro[ 10 ].w = 128;
astro[ 10 ].h = 128;
astro[ 11 ].x = 256;
astro[ 11 ].y = 256;
astro[ 11 ].w = 128;
astro[ 11 ].h = 128;
astro[ 12 ].x = 256;
astro[ 12 ].y = 384;
astro[ 12 ].w = 128;
astro[ 12 ].h = 128;
astro[ 13 ].x = 384;
astro[ 13 ].y = 128;
astro[ 13 ].w = 128;
astro[ 13 ].h = 128;
astro[ 14 ].x = 384;
astro[ 14 ].y = 256;
astro[ 14 ].w = 128;
astro[ 14 ].h = 128;
astro[ 15 ].x = 384;
astro[ 15 ].y = 384;
astro[ 15 ].w = 128;
astro[ 15 ].h = 128;
//Main loop- will keep going until the user sets quit to true.
while( quit == false )
{
//Start the frame timer
fps.start();
//If there is no music playing
if( Mix_PlayingMusic() == 0 )
{
//Play the music
if( Mix_PlayMusic( music, -1 ) == -1 )
{
return 1;
}
}
//While there's an event to handle
while( SDL_PollEvent( &event ) )
{
ship.handle_input();
switch(event.type)
{
case SDL_QUIT://If the user presses X ( close ).
//Quits the program
quit = true;
break;
case SDL_KEYDOWN:
switch( event.key.keysym.sym )
{
case SDLK_SPACE:
{
//Play laser sound
if( Mix_PlayChannel( 0, laser, 0 ) == -1 )
{
return 1;
}//Lasers position
}
}
}
}
ship.move();
//Bullet collision
render_Update();
//Render the dot on screen
//myDot.show();
ship.show();
for(int i = 0; i < BULLETS; i++)
bullets[i].show();
//Update Screen
if( SDL_Flip( screen ) == -1 )
{
return 1;
}
//Increment the frame counter
frame++;
//If we want to cap the frame rate
if( ( cap == true ) && ( fps.get_ticks() < 1000 / FRAMES_PER_SECOND ) )
{
//Sleep the remaining frame time
SDL_Delay( ( 1000 / FRAMES_PER_SECOND ) - fps.get_ticks() );
}
}
clean_up();
return 0;
}
//Tackar för svar
Sandric