Ok, guys, I'm making a progress with my Pacman game. I now made the map using tiles and reading from file, and I made the collision. But now I have another problem.
The problem is the following:
In the original Pacman game, as you know, when you press an arrow key to make a turn AND you can't make the turn right now ( because there are walls around you ), the game SAVES your last pressed arrow key AND after 1 or 2 seconds, when you can actually make the turn, it makes it for you, depending on the last key you pressed. See the pictures below:
[attachment=30361:Pac_Before.png] [attachment=30362:Pac_After.png]
Ok, 1st step is to save the last pressed arrow key. I made an int arrow which saves the arrow keys like this:
if( SDLK_RIGHT ) { arrow = RIGHT }
if( SDLK_LEFT ) { arrow = LEFT } etc...
So now my last arrow key is saved.
Now I wrote this.
if ( hit_wall() == true )
{
if ( arrow = RIGHT )
{
velocityX = SPEED_NORMAL;
velocityY = 0;
}
etc... for all the other key presses
So now it will change the direction later when there is a space to make the turn, BUT....
But now the problem is that the ONLY time pacman makes a turn is when there is a collision.
Ok, see the left picture is when Up is PRESSED.
[attachment=30363:pac_bugged_before.png] [attachment=30364:pac_bugged_after.png]
So this is definitely not the solution.
I have the SDL_Rect get_tilebox() function which returns the tile rect, but when I actually call it, how can I check tilebox.x and tilebox.y.
I have ideas but the code is very very ugly, so I need something simple and efficient. so...as you can see by my username, I need Heelp!!!
( Here is a link to the original game - http://www.webpacman.com )
and here is all my code ( You want to see the pacman::movement stuff and pacman::handle_events maybe )
//The header files
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_ttf.h"
#include "SDL/SDL_mixer.h"
#include <string>
#include <iostream>
//Screen dimensions
const int SCREEN_WIDTH = 630;
const int SCREEN_HEIGHT = 630;
const int SCREEN_BPP = 32;
//The frames per second
const int FRAMES_PER_SECOND = 100;
//Pacman stuff
const int PAC_DIAMETER = 23;
const int SPEED_NORMAL = 1;
//The direction status of the Pac
const int PAC_RIGHT = 1;
const int PAC_DOWN = 2;
const int PAC_LEFT = 3;
const int PAC_UP = 4;
//The different tile sprites
const int TILE_BLACK = 0;
const int TILE_BLUE = 1;
//The different TYPES of tiles
const int TILE_SPRITES = 2;
//Tile dimensions and number
const int TILE_WIDTH = 30;
const int TOTAL_TILES = 441;
SDL_Surface *screen = NULL;
SDL_Surface *tileSheet = NULL;
//In-game sprite surfaces
SDL_Surface *pacRight = NULL;
SDL_Surface *pacDown = NULL;
SDL_Surface *pacLeft = NULL;
SDL_Surface *pacUp = NULL;
//The event structure
SDL_Event event;
//
SDL_Rect clips[ TILE_SPRITES ];
//The font
TTF_Font *font = NULL;
//The color of the font
SDL_Color color[2] = { { 255, 255, 255 }, { 255, 0, 0 } };
class Tile
{
private:
//The attributes of the tile
SDL_Rect tilebox;
//The type of tile
int type;
public:
//Initialize the variables
Tile( int x, int y, int tileType );
//Show the tile
void show();
//Get the tile type
int get_type();
//Get the collision box
SDL_Rect get_tilebox();
};
class Pacman
{
private:
//The Rect of Pacman
SDL_Rect pacbox;
//The offsets
float offsetX;
float offsetY;
//The speed of moving
float velocityX;
float velocityY;
//The position of pacman
int arrow;
int turnpac;
int walkstatus;
int transition;
public:
//The constructor
Pacman();
//Handle input
void handle_events();
//Change the coordinates of Pacman when moving
void movement( Tile *tiles[] );
//Handles Pacman animation when walking
void walk_anim();
//\ Pacman on screen
void show();
};
bool set_tiles( Tile *tiles[] )
{
//The tile offsets
int x = 0, y = 0;
//Opening the text file with the 0s and 1s
FILE* filePointer;
filePointer = fopen("Pics/pacmanWholemap.txt", "rt");
if( filePointer == NULL )
{
return false;
}
int t = 0, counter = 0, tileType = 0;
//While going through all the characters...
while( ( t = getc( filePointer ) )!= EOF )
//If it sees zero, put 1st tile
{
if( t == '0' || t == '1' )
{
//Make the type of the tile = 0
tileType = t - '0';
tiles[ counter ] = new Tile ( x, y, tileType );
counter++;
if( counter == TOTAL_TILES )
{
break;
}
//Move to the next tile coordinates
x += TILE_WIDTH;
//If you are out of screen
if( x >= 21*TILE_WIDTH )
{
x = 0;
y += TILE_WIDTH;
}
if( y >= 21*TILE_WIDTH )
{
return true;
}
}
}
}
class Timer
{
private:
//The clock time when the timer started
int startTicks;
//The timer status
bool started;
public:
//Initializes variables
Timer();
//The various clock actions
void start();
void stop();
//Gets the timer's time
int get_ticks();
//Checks the status of the timer
bool is_started();
};
Timer::Timer()
{
//Initialize the variables
startTicks = 0;
started = false;
}
void Timer::start()
{
//Start the timer
started = true;
//Get the current clock time
startTicks = SDL_GetTicks();
}
void Timer::stop()
{
//Stop the timer
started = false;
}
int Timer::get_ticks()
{
//If the timer is running
if( started == true )
{
//Return the current time minus the start time
return SDL_GetTicks() - startTicks;
}
//If the timer isn't running
return 0;
}
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 loading the screen
if( screen == NULL )
{
return false;
}
//Initialize SDL_ttf
if( TTF_Init() == -1 )
{
return false;
}
//Set the window caption
SDL_WM_SetCaption( "Pacman", NULL );
//If everything initialized fine
return true;
}
SDL_Surface * load_image( std::string filename )
{
//The image that's loaded
SDL_Surface* loadedImage = NULL;
//The optimized surface
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 )
{
SDL_SetColorKey( optimizedImage, SDL_SRCCOLORKEY, SDL_MapRGB( optimizedImage->format, 0, 0, 0 ) );
}
}
//Return the optimized surface
return optimizedImage;
}
bool load_files()
{
//Load the font
font = TTF_OpenFont( "lazy.ttf", 38 );
//Load the background
//Load the tiles sheet
tileSheet = load_image( "Pics/blue red.png");
//Load the pacman images
pacRight = load_image( "Pics/pac_right.png" );
pacDown = load_image( "Pics/pac_down.png" );
pacLeft = load_image( "Pics/pac_left.png" );
pacUp = load_image( "Pics/pac_up.png" );
//If there was a problem in loading the sprites
if( pacRight == NULL || pacDown == NULL || pacLeft == NULL || pacUp == NULL )
{
return false;
}
if( tileSheet == NULL )
{
return false;
}
//If everything loaded fine
return true;
}
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;
}
void clip_tiles()
{
//Clip the sprite sheet
clips[ TILE_BLACK ].x = 0;
clips[ TILE_BLACK ].y = 0;
clips[ TILE_BLACK ].w = TILE_WIDTH;
clips[ TILE_BLACK ].h = TILE_WIDTH;
clips[ TILE_BLUE ].x = TILE_WIDTH;
clips[ TILE_BLUE ].y = 0;
clips[ TILE_BLUE ].w = TILE_WIDTH;
clips[ TILE_BLUE ].h = TILE_WIDTH;
}
bool hit_wall( SDL_Rect box, Tile *tiles[] )
{
for( int t = 0; t < TOTAL_TILES; t++ )
{
if( tiles[ t ]->get_type() == TILE_BLUE )
{
if( check_collision( box, tiles[ t ]->get_tilebox() ) )
{
return true;
}
}
}
//If no collision was found
return false;
}
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 );
}
//void close_all( Tile *tiles[] )
void close_all( Tile *tiles[] )
{
//Free the pacman surfaces
SDL_FreeSurface( pacRight );
SDL_FreeSurface( pacDown );
SDL_FreeSurface( pacLeft );
SDL_FreeSurface( pacUp );
//Free the background and tiles surfaces
SDL_FreeSurface( tileSheet );
//Free the tiles
for( int t = 0; t < TOTAL_TILES; t++ )
{
delete tiles[ t ];
}
//Close Font
TTF_CloseFont( font );
//Quit SDL_ttf
TTF_Quit();
//Quit SDL
SDL_Quit();
}
Pacman::Pacman()
{
//Initialize the Rect variables
pacbox.x = 63;
pacbox.y = 33;
pacbox.w = PAC_DIAMETER;
pacbox.h = PAC_DIAMETER;
//Initialize movement variables
velocityX = SPEED_NORMAL;
velocityY = 0;
walkstatus = PAC_RIGHT;
arrow = 0;
transition = 0;
}
void Pacman::handle_events()
{
//If a key was pressed
if( event.type == SDL_KEYDOWN )
{
//Set the velocity
if( event.key.keysym.sym == SDLK_RIGHT )
{
arrow = PAC_RIGHT;
}
if( event.key.keysym.sym == SDLK_DOWN )
{
arrow = PAC_DOWN;
}
if( event.key.keysym.sym == SDLK_LEFT )
{
arrow = PAC_LEFT;
}
if( event.key.keysym.sym == SDLK_UP )
{
arrow = PAC_UP;
}
}
}
void Pacman::movement( Tile *tiles[] )
{
//Move
pacbox.x += velocityX;
pacbox.y += velocityY;
for( int t = 0; t < TOTAL_TILES; t++ )
{
if( tiles[ t ]->get_type() == TILE_BLACK )
{
}
}
//Check Pac - walls collision
if( hit_wall( pacbox, tiles ) )
{
if( velocityX != 0 && velocityY == 0 )
{
pacbox.x -= velocityX;
}
if( velocityY != 0 && velocityX == 0 )
{
pacbox.y -= velocityY;
}
if( arrow == PAC_RIGHT )
{
velocityX = SPEED_NORMAL;
velocityY = 0;
}
if( arrow == PAC_DOWN )
{
velocityX = 0;
velocityY = SPEED_NORMAL;
arrow = 0;
}
if( arrow == PAC_LEFT )
{
velocityX = -SPEED_NORMAL;
velocityY = 0;
arrow = 0;
}
if( arrow == PAC_UP )
{
velocityX = 0;
velocityY = -SPEED_NORMAL;
arrow = 0;
}
}
//Keep the Pac in bounds
if( pacbox.x < - PAC_DIAMETER )
{
if( transition == 0 )
{
pacbox.x = SCREEN_WIDTH;
transition ++;
}
}
if( pacbox.x > SCREEN_WIDTH )
{
if( transition == 0 )
{
pacbox.x = -PAC_DIAMETER;
transition ++;
}
}
else
{
if( transition == 1 )
{
transition = 0;
}
}
if( pacbox.y < 0 || pacbox.y + PAC_DIAMETER > SCREEN_HEIGHT )
{
pacbox.y -= velocityY;
}
//Check velocity and set position
//If Pacman is moving left
if( velocityX > 0 )
{
//Set the animation to left
walkstatus = PAC_RIGHT;
}
if( velocityX < 0 )
{
//Set the animation to left
walkstatus = PAC_LEFT;
}
if( velocityY < 0 )
{
//Set the animation to left
walkstatus = PAC_UP;
}
if( velocityY > 0 )
{
//Set the animation to left
walkstatus = PAC_DOWN;
}
}
void Pacman::show()
{
if( walkstatus == PAC_RIGHT )
{
apply_surface( pacbox.x, pacbox.y, pacRight, screen );
}
if( walkstatus == PAC_DOWN )
{
apply_surface( pacbox.x, pacbox.y, pacDown, screen );
}
if( walkstatus == PAC_LEFT )
{
apply_surface( pacbox.x, pacbox.y, pacLeft, screen );
}
if( walkstatus == PAC_UP )
{
apply_surface( pacbox.x, pacbox.y, pacUp, screen );
}
}
Tile::Tile( int x, int y, int tileType )
{
//Get the offsets
tilebox.x = x;
tilebox.y = y;
//Set the collision box
tilebox.w = TILE_WIDTH;
tilebox.h = TILE_WIDTH;
//Get the tile type
type = tileType;
}
void Tile::show()
{
//Show the tile
apply_surface( tilebox.x, tilebox.y, tileSheet, screen, &clips[ type ] );
}
int Tile::get_type()
{
return type;
}
SDL_Rect Tile::get_tilebox()
{
return tilebox;
}
int main( int argc, char* args[] )
{
bool quit = false;
Tile *tiles[ TOTAL_TILES ];
//The tiles that will be used
for( int t = 0; t < TOTAL_TILES; t++ )
{
tiles[t] = NULL;
}
//Initialize the SDL stuff
if( init() == false )
{
return 1;
}
//Load the files
if( load_files() == false )
{
return 2;
}
//Clip the tile sheet
clip_tiles();
//Set the tiles
set_tiles( tiles );
//The timer
Timer fps;
//The pacman
Pacman pacman1;
//While the user hasn't quit
while( quit == false )
{
//While there's events to handle
while( SDL_PollEvent( &event ) )
{
pacman1.handle_events();
//If the user has pressed Esc or X
if( event.type == SDL_QUIT || event.key.keysym.sym == SDLK_ESCAPE )
{
//Quit the program
quit = true;
}
}
//Moves Pac
pacman1.movement( tiles );
//Apply the tiles as background
for( int t = 0; t < TOTAL_TILES; t++ )
{
if( tiles[ t ] != NULL )
{
tiles[ t ]->show();
}
}
//Show the Pac on the screen
pacman1.show();
//Update the screen
if( SDL_Flip( screen ) == -1 )
{
return 1;
}
//Cap the frame rate
if( fps.get_ticks() < 1000 / FRAMES_PER_SECOND )
{
SDL_Delay( 1000 / FRAMES_PER_SECOND - fps.get_ticks() - 7 );
}
}
//Clean up
close_all( tiles );
return 0;
}