Advertisement

SDL tictactoe

Started by April 11, 2011 11:56 PM
0 comments, last by guywithknife 13 years, 7 months ago
Well let me first take it upon myself to introduce myself I am new to this form because instead of text based programs I am starting to actually make games!smile.gif

Anyways, been having trouble with my program because it still lets the player pick the same spot again after its already been filled, the debugger is not helping due to my poor knowledge with it.dry.gif I am almost positive that the problem is in the handle_events() function, the debugger tells me that the bool value is returning true to check if the spot is taken but a simple if statement is still letting the player pick the same spot, occasionally if you keep clicking it won't let pick the same spot. Criticism well appreciated on any other bad coding in the program.

Source (Scroll to handle events for the problem):


#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_ttf.h"
#include <sstream>

using namespace std;

const int SCREEN_H = 480;
const int SCREEN_W = 755;
const int SCREEN_BPP = 32;

SDL_Surface *current_turn = NULL;
SDL_Surface *background = NULL;
SDL_Surface *screen = NULL;
SDL_Surface *target_X = NULL;
SDL_Surface *target_O = NULL;

SDL_Event event;
bool Turn = true;

class Target
{
private:
SDL_Rect box;
public:
bool taken;
Target(int x,int y,int h, int w);
void handle_events();
};


SDL_Surface *clarify_image( std::string filename)
{
SDL_Surface *loaded_image = NULL;
SDL_Surface *optimized_image = NULL;
loaded_image = IMG_Load( filename.c_str());
if ( loaded_image != NULL)
{
optimized_image = SDL_DisplayFormat( loaded_image );
SDL_FreeSurface(loaded_image);
if (optimized_image != NULL)
{
Uint32 colorkey = SDL_MapRGB(optimized_image->format,0,0xFF,0xFF);
SDL_SetColorKey( optimized_image,SDL_SRCCOLORKEY,colorkey);
}
}
return optimized_image;
}

void apply_surface(int x,int y,SDL_Surface* source,SDL_Surface* destination,SDL_Rect* clip = NULL )
{
SDL_Rect offset;
offset.x = x;
offset.y = y;
SDL_BlitSurface(source, NULL,destination, &offset);
}

bool load_files()
{
target_X = clarify_image("target_X.png");
target_O = clarify_image("target_O.png");
background = clarify_image("background.png");
current_turn = target_X;
if ((background == NULL) || (target_X == NULL) || (target_O == NULL)) {return false;}
else
return true;
}

bool init()
{
if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 ) { return false;}
screen = SDL_SetVideoMode( SCREEN_W, SCREEN_H, SCREEN_BPP, SDL_SWSURFACE );
if( screen == NULL ) {return false;}
SDL_WM_SetCaption( "Jake's program", NULL );
if(TTF_Init() == -1) {return false;}
return true;
}

void cleanup()
{
SDL_FreeSurface( background );
SDL_FreeSurface( target_X );
SDL_FreeSurface( target_O );
SDL_Quit();
}


Target::Target(int x,int y,int w,int h)
{
box.x = x;
box.y = y;
box.w = w;
box.h = h;
}

void Target::handle_events()
{
int x = 0,y = 0;
if (event.type == SDL_MOUSEBUTTONDOWN)
{
x = event.motion.x;
y = event.motion.y;

if( event.button.button == SDL_BUTTON_LEFT )
{
x = event.button.x;
y = event.button.y;
if( ( x > box.x ) && ( x < box.x + box.w ) && ( y > box.y ) && ( y < box.y + box.h ) )
{
if (Turn == true)
{
if (Target::taken == false)
{
apply_surface(box.x,box.y,target_X,screen);
Turn = false;
Target::taken = true;
}
}
else
if (Turn == false)
{
if (Target::taken == false)
{
apply_surface(box.x,box.y,target_O,screen);
Turn = true;
Target::taken = true;
}
}
else
if (Target::taken == true)
{
if (Turn == true)
{
Turn = false;
}
else
if (Turn == false)
{
Turn = true;
}
}

}
}
}
}


int main ( int argc, char *args[] )

{
//check for errors
bool quit = false;
if( init() == false ) { return 1;}
if( load_files() == false ) { return 2;}
apply_surface( 0,0,background,screen);
//game loop
while (quit == false)
{
Target myTarget1(2,2,247,119);
Target myTarget2(251,2,247,119);
Target myTarget3(502,2,247,119);
Target myTarget4(2,127,247,119);
Target myTarget5(251,127,247,119);
Target myTarget6(502,127,247,119);
Target myTarget7(2,249,247,119);
Target myTarget8(251,249,247,119);
Target myTarget9(502,249,247,119);
myTarget1.taken = false;
myTarget2.taken = false;
myTarget3.taken = false;
myTarget4.taken = false;
myTarget5.taken = false;
myTarget6.taken = false;
myTarget7.taken = false;
myTarget8.taken = false;
myTarget9.taken = false;

if(SDL_PollEvent(&event))
{
myTarget1.handle_events();
myTarget2.handle_events();
myTarget3.handle_events();
myTarget4.handle_events();
myTarget5.handle_events();
myTarget6.handle_events();
myTarget7.handle_events();
myTarget8.handle_events();
myTarget9.handle_events();

if( event.type == SDL_QUIT )
{
//Quit the program
quit = true;
}
}
if (SDL_Flip( screen ) == -1)
{
return 3;
}
}

//cleanup
cleanup();
return 0;
}
The problem is that you are recreating the Target objects in your loop (the while loop in main). Every iteration of the loop, you create new objects, process them (set taken to true, if you click on them), then the objects are destroyed and new ones are created. To fix this, move the [font="Courier New"]Target myTarget1 = Target(...); ...[/font] code out of the loop (before the [font="Courier New"]while(quit == false)[/font]).

Here are some tips on improving the code:

  • Make [font="Courier New"]taken[/font] private and add [font="Courier New"]taken = false;[/font] into the constructor ([font="Courier New"]Target::Target()[/font]). This will let you remove the [font="Courier New"]myTarget1.taken = false[/font][font="Courier New"];[/font][font="CourierNew, monospace"] [/font]from main.
  • Inside [font="Courier New"]Target::handle_events()[/font], you do not need to prefix taken with [font="Courier New"]Target::[/font] (so [font="Courier New"]Target::taken[/font] becomes just [font="Courier New"]taken[/font]).
  • Consider making event a local variable in main and passing it to [font="Courier New"]Target::handle_events()[/font] instead (so [font="Courier New"]handle_events()[/font] becomes [font="Courier New"]handle_events(SDL_Event& event)[/font] - the & means pass-by-reference and is similar to passing a pointer, except that the function can treat it as a normal variable ( . instead of ->, no need to delete its memory etc)).
  • Create an array (or an std::vector) of Target instances, instead of myTarget1, myTarget2 etc:



    #include <vector>

    int main ( int argc, char *args[] )
    {
    //check for errors
    bool quit = false;
    if( init() == false ) { return 1;}
    if( load_files() == false ) { return 2;}
    apply_surface( 0,0,background,screen);

    // set up targets (taken is automatically set to false in the constructor)
    std::vector targets;
    targets.push_back(Target(2,2,247,119));
    targets.push_back(Target(251,2,247,119));
    targets.push_back(Target(502,2,247,119));
    targets.push_back(Target(2,127,247,119))
    targets.push_back(Target(251,127,247,119));
    targets.push_back(Target(502,127,247,119));
    targets.push_back(Target(2,249,247,119));
    targets.push_back(Target(251,249,247,119));
    targets.push_back(Target(502,249,247,119));

    // Local variable, instead of global
    SDL_Event event;

    //game loop
    while (quit == false)
    {
    // CODE MOVED OUT OF LOOP TO FIX BUG

    if(SDL_PollEvent(&event))
    {
    // When you learn more about std::vector, replace this with "iterators" instead
    for (unsigned int index=0; index < targets.size(); ++index) {
    targets[index].handle_events(event);
    }

    if( event.type == SDL_QUIT )
    {
    //Quit the program
    quit = true;
    }
    }
    if (SDL_Flip( screen ) == -1)
    {
    return 3;
    }
    }
    //cleanup
    cleanup();
    return 0;
    }

This topic is closed to new replies.

Advertisement