Sign in to follow this  
JonathanO'Brien

Applying a Surface on Collision (SDL)

Recommended Posts

So I wrote a simple program where a box is controlled by the arrow keys and moves around a background on which there is an SDL_Rect "wall". The collision works fine (between the box and wall), but I would like to have a surface applied when the collision is detected.


[code]


#include "SDL.h"
#include "SDL_image.h"
#include <string>

//width, height, bpp and frame rate of program
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
const int SCREEN_BPP = 32;
const int FRAME_RATE = 30;

const int SQUARE_WIDTH = 20;
const int SQUARE_HEIGHT = 20;

SDL_Surface *screen = NULL;
SDL_Surface *square = NULL;
SDL_Surface *background = NULL;
//TODO: Declare surfaces
SDL_Event event;

SDL_Rect wall;

//classes
class Square //like dot, with SDL_Rect for x and y co-ords
{
private:

//velocity of the dot
int xVel, yVel;

public:
//x and y offsets
SDL_Rect box;
//init variables
Square();
//handle user input and apply it to the dot
void handle_input();
//move dot
void move();
//display dot
void show();
};

class Timer
{
private:
//time when timer started/paused
int startTicks;
int pausedTicks;

//timer status
bool paused;
bool started;

public:
//init variables
Timer();

//clock actions
void start();
void stop();
void pause();
void unpause();

//Gets timer's time
int get_ticks();

//check timer status
bool is_started();
bool is_paused();
};

//functions
SDL_Surface *load_image(std::string filename)
{
//The image that's loaded
SDL_Surface* loadedImage = NULL;

//The optimized surface that will be used
SDL_Surface* optimizedImage = NULL;

//Load the image
loadedImage = IMG_Load(filename.c_str());

//If the image loaded
if( loadedImage != NULL )
{
//Create an optimized surface
optimizedImage = SDL_DisplayFormat(loadedImage);

//Free the old surface
SDL_FreeSurface(loadedImage);

//If the surface was optimized
if(optimizedImage != NULL)
{
//Color key surface
SDL_SetColorKey(optimizedImage, SDL_SRCCOLORKEY, SDL_MapRGB(optimizedImage->format, 0, 0xFF, 0xFF));
}
}

//Return the optimized surface
return optimizedImage;
}

void apply_surface(int x, int y, SDL_Surface* source, SDL_Surface* destination, SDL_Rect* clip = NULL)
{
//Holds offsets
SDL_Rect offset;

//Get offsets
offset.x = x;
offset.y = y;

//Blit
SDL_BlitSurface(source, clip, destination, &offset);
}

bool check_collision(SDL_Rect A, SDL_Rect B)
{
//boundaries for collision
int leftA, leftB;
int rightA, rightB;
int topA, topB;
int bottomA, bottomB;

//size of rectA
leftA = A.x;
rightA = A.x + A.w;
topA = A.y;
bottomA = A.y + A.h;

//size of rectB
leftB = B.x;
rightB = B.x + B.w;
topB = B.y;
bottomB = B.y + B.h ;

//if sides of A are outside B
if(bottomA <= topB)
{
return false;
}
else if(topA >= bottomB)
{
return false;
}
else if(rightA <= leftB)
{
return false;
}
else if(leftA >= rightB)
{
return false;
}

//if sides of A are within B
else
{
return true;
apply_surface(0, 0, background, screen, NULL);
}
}

bool init()
{
//Initialize all SDL subsystems
if(SDL_Init(SDL_INIT_EVERYTHING) == -1)
{
return false;
}

//Set up the screen
screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE);

//If there was an error in setting up the screen
if(screen == NULL)
{
return false;
}

//Initialize SDL_mixer
//Set the window caption
SDL_WM_SetCaption("Motion", NULL);

//If everything initialized fine
return true;
}

bool load_files()
{
//Load the background image
square = load_image("square.bmp");
background = load_image("background.png");

//If there was a problem in loading the background
if(square == NULL)
{
return false;
}

if(background == NULL)
{
return false;
}
//If there was an error in loading the font
//Load the music
//music = Mix_LoadMUS( "beat.wav" );

//If there was a problem loading the music

//Load the sound effects
//scratch = Mix_LoadWAV( "scratch.wav" );
//high = Mix_LoadWAV( "high.wav" );
//med = Mix_LoadWAV( "medium.wav" );
//low = Mix_LoadWAV( "low.wav" );

//If everything loaded fine
return true;
}

void clean_up()
{
//Free the surfaces
SDL_FreeSurface(square);

//Free the sound effects
//Mix_FreeChunk( scratch );
//Mix_FreeChunk( high );
//Mix_FreeChunk( med );
//Mix_FreeChunk( low );

//Free the music
//Mix_FreeMusic( music );

//Close the font
//TTF_CloseFont( font );

//Quit SDL_mixer
//Mix_CloseAudio();

//Quit SDL_ttf

//Quit SDL
SDL_Quit();
}

//Class functions

//Timer
Timer::Timer()
{
//init variables
startTicks = 0;
pausedTicks = 0;
paused = false;
started = false;
}

void Timer::start()
{
//start/unpause
started = true;
paused = false;
//get current time
startTicks = SDL_GetTicks();
}

void Timer::stop()
{
//stop/pause timer
started = false;
paused = false;
}

int Timer::get_ticks()
{
//if timer is running
if(started == true)
{
//if paused
if(paused == true)
{
//return #ticks when paused
return pausedTicks;
}
else
{
//return current time - start ticks
return SDL_GetTicks() - startTicks;
}
}

//if timer isnt running
return 0;
}

void Timer::pause()
{
//if timer is running and not paused
if((started == true) && (paused == false))
{
//pause timer
paused = true;
//calculate paused ticks
pausedTicks = SDL_GetTicks() - startTicks;
}
}

void Timer::unpause()
{
//if paused
if(paused == true)
{
//unpause
paused = false;
//reset start ticks
startTicks = SDL_GetTicks() - pausedTicks;
//reset paused ticks
pausedTicks = 0;
}
}

bool Timer::is_started()
{
return started;
}

bool Timer::is_paused()
{
return paused;
}

//Square
Square::Square()
{
//offsets
box.x = 0;
box.y = 0;

//dimensions
box.w = SQUARE_WIDTH;
box.h = SQUARE_HEIGHT;

//velocity
xVel = 0;
yVel = 0;
}

void Square::handle_input()
{
if(event.type == SDL_KEYDOWN)
{
switch(event.key.keysym.sym)
{
case SDLK_UP: yVel -= SQUARE_HEIGHT / 2; break;
case SDLK_DOWN: yVel += SQUARE_HEIGHT / 2; break;
case SDLK_LEFT: xVel -= SQUARE_WIDTH / 2; break;
case SDLK_RIGHT: xVel += SQUARE_WIDTH / 2; break;
}
}
else if(event.type == SDL_KEYUP)
{
switch(event.key.keysym.sym)
{
case SDLK_UP: yVel += SQUARE_HEIGHT / 2; break;
case SDLK_DOWN: yVel -= SQUARE_HEIGHT / 2; break;
case SDLK_LEFT: xVel += SQUARE_WIDTH / 2; break;
case SDLK_RIGHT: xVel -= SQUARE_WIDTH / 2; break;
}
}
}

void Square::move()
{
//move on x axis
box.x += xVel;

//if it goes too far left or right or collides
if((box.x < 0) || (box.x + SQUARE_WIDTH > SCREEN_WIDTH) || (check_collision(box, wall)))
{
//move back
box.x -= xVel;
}

//move on y axis
box.y += yVel;

//if it goes too far up ot down or collides
if((box.y < 0) || (box.y + SQUARE_HEIGHT > SCREEN_HEIGHT) || (check_collision(box, wall)))
{
box.y -= yVel;
}
}

void Square::show()
{
//show square
apply_surface(box.x, box.y, square, screen);

if(check_collision(box, wall) == true)
{
apply_surface(0, 0, background, screen, NULL);
}
}

int main(int argc, char* args[])
{
bool quit = false;

Square mySquare;
Timer fps;

if(init() == false)
{
return 1;
}

if(load_files() == false)
{
return 1;
}

wall.x = 300;
wall.y = 40;
wall.w = 40;
wall.h = 400;

while(quit == false)
{
fps.start();

while(SDL_PollEvent(&event))
{
mySquare.handle_input();

if(event.type == SDL_QUIT)
{
quit = true;
}
}

mySquare.move();

//show white screen, grey wall
if(check_collision(mySquare.box, wall) == false)
{
SDL_FillRect(screen, &screen->clip_rect, SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF));
SDL_FillRect(screen, &wall, SDL_MapRGB(screen->format, 0x77, 0x77, 0x77));
}
else
{
apply_surface(0, 0, background, screen, NULL);
}

mySquare.show();

if(SDL_Flip(screen) == -1)
{
return 1;
}

if(fps.get_ticks() < 1000 / FRAME_RATE)
{
SDL_Delay((1000 / FRAME_RATE) - fps.get_ticks());
}
}

clean_up();

return 0;
}
[/code]


I think that
[code]
apply_surface(0, 0, background, screen NULL)
[/code]

Should be fine, but I don't know where to insert it.

Thanks.

Share this post


Link to post
Share on other sites
rip-off    10979
You are applying the surface after you've returned from the function. Increase your compiler's warning level, it should warn you about such "dead code".

However, if you are running at a decent frame rate the image will flash so quickly you might barely notice it. Don't apply the surface in check_collision() anyway, it mixes two unrelated concepts (checking for collision and reacting to a collision).

Instead, when a collision occurs set a simple timer variable to some value which indicates the number of milliseconds you want the image to appear. Show the image while the timer is positive. Decrement the timer while it is positive by the number of ticks spent in that frame.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this