SDL Sprite Sheet Clipping

I am trying to create a basic TicTacToe Game in SDL and so far have come up with the code below. Currently I have the board set up with 9 buttons that when you hover over it sets it to a grey image clipped from a sprite sheet that shows you aer hovering over it. When you left click it sets it to a Circle clipped from the sprite sheet and when you right click it shows a Cross clipped from the sprite sheet. When you are not hovering it displays a white box. However when you right or left click the image changes but as soon as you move it changes back.
I can't for the life of me work out how to get it to stay as either a cross or cirlce.

Any help anyone could give would be greatly appreciated.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
//SDL Includes
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_ttf.h"
#include "SDL/SDL_mixer.h"
#include <string>

//Screen Attributes
const int SCREEN_WIDTH = 640; 
const int SCREEN_HEIGHT = 607; 
const int SCREEN_BPP = 32;

//The button states in the sprite sheet
const int CLIP_MOUSEOVER = 0;
const int CLIP_MOUSEOUT = 1;
const int CLIP_MOUSEDOWN = 2;
const int CLIP_MOUSEUP = 3;

//The surfaces
SDL_Surface *board = NULL; 
SDL_Surface *sprites = NULL;
SDL_Surface *screen = NULL;

//Event Structures 
SDL_Event event;

//The clip regions of the sprite sheet
SDL_Rect clips[ 4 ];

//The button
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 ); 
    }
    
    //Return the optimized image 
    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 init()
{
    //Initialize all SDL subsystems 
    if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 ) 
    { 
        return 1; 
    }
    
    //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 1; 
    }
    
    //Set the window caption 
    SDL_WM_SetCaption( "TicTacToe", NULL );
    
    //If everything OK
    return true;
}

bool load_files()
{
    //Load Images
    board = load_image( "images/board.tga" );
    
    //Load the button sprite sheet
    sprites = load_image( "images/sprites.tga" );
    
    //If there was an error loading the images
    if( board == NULL )
    {
        return false;
    }
    
    //If everything loaded fine
    return true;
}

void clean_up()
{
    //Free the loaded image
    SDL_FreeSurface(board);
    SDL_FreeSurface(sprites);
    
    //Quit SDL
    SDL_Quit();
}

void set_clips()
{
    //Clip the sprite sheet
    clips[ CLIP_MOUSEOVER ].x = 0;
    clips[ CLIP_MOUSEOVER ].y = 169;
    clips[ CLIP_MOUSEOVER ].w = 160;
    clips[ CLIP_MOUSEOVER ].h = 169;

    clips[ CLIP_MOUSEOUT ].x = 180;
    clips[ CLIP_MOUSEOUT ].y = 169;
    clips[ CLIP_MOUSEOUT ].w = 160;
    clips[ CLIP_MOUSEOUT ].h = 169;

    clips[ CLIP_MOUSEDOWN ].x = 0;
    clips[ CLIP_MOUSEDOWN ].y = 0;
    clips[ CLIP_MOUSEDOWN ].w = 160;
    clips[ CLIP_MOUSEDOWN ].h = 169;

    clips[ CLIP_MOUSEUP ].x = 180;
    clips[ CLIP_MOUSEUP ].y = 0;
    clips[ CLIP_MOUSEUP ].w = 160;
    clips[ CLIP_MOUSEUP ].h = 169;
}

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;

    //Set the default sprite
    clip = &clips[ CLIP_MOUSEOUT ];
}


void Button::handle_events()
{
    //The mouse offsets
    int x = 0, y = 0;

    //If the mouse moved
    if( event.type == SDL_MOUSEMOTION )
    {
        //Get the mouse offsets
        x = event.motion.x;
        y = event.motion.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
            clip = &clips[ CLIP_MOUSEOVER ];
        }
        //If not
        else
        {
            //Set the button sprite
            clip = &clips[ CLIP_MOUSEOUT ];
        }
    }
    //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
                clip = &clips[ CLIP_MOUSEDOWN ];
            }
        }
        if( event.button.button == SDL_BUTTON_RIGHT )
        {
            //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
                clip = &clips[ CLIP_MOUSEUP ];
            }
        }
    }
    
}

void Button::show()
{
    //Show the button
    apply_surface( box.x, box.y, sprites, screen, clip );
}

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

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

    //Load the files
    if( load_files() == false )
    {
        return 1;
    }
    
    //Blits board
    apply_surface( 0, 0, board, screen, NULL );

    //Clip the sprite sheet
    set_clips();

    //Make the button
    Button myButton( 25, 10, 180, 169 );
    Button myButton2( 235, 10, 180, 169 );
    Button myButton3( 450, 10, 180, 169 );
    Button myButton4( 25, 210, 180, 169 );
    Button myButton5( 235, 210, 180, 169 );
    Button myButton6( 450, 210, 180, 169 );
    Button myButton7( 25, 420, 180, 169 );
    Button myButton8( 235, 420, 180, 169 );
    Button myButton9( 450, 420, 180, 169 );
    
    //While the user hasn't quit
    while( quit == false )
    {
        //If there's events to handle
        if( SDL_PollEvent( &event ) )
        {
            //Handle button events
            myButton.handle_events();
            myButton2.handle_events();
            myButton3.handle_events();
            myButton4.handle_events();
            myButton5.handle_events();
            myButton6.handle_events();
            myButton7.handle_events();
            myButton8.handle_events();
            myButton9.handle_events();

            //If the user has Xed out the window
            if( event.type == SDL_QUIT )
            {
                //Quit the program
                quit = true;
            }
        }

        //Show the button
        myButton.show();
        myButton2.show();
        myButton3.show();
        myButton4.show();
        myButton5.show();
        myButton6.show();
        myButton7.show();
        myButton8.show();
        myButton9.show();

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

    //Clean up
    clean_up();

    return 0;
}
closed account (D80DSL3A)
You want the button image to remain fixed after clicking on it?
I suggest you add another data member to your button class to record the button state.
If you have bool set; and initialize it in the Button constructor to:
set = false;
then you can test for this in your handle_events() function.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void Button::handle_events()
{
    if( set )
        return;// if set is true then don't change the image, just return
    // your existing code
    // excerpt from the part handling a left-click
            if( ( x > box.x ) && ( x < box.x + box.w ) && ( y > box.y ) && ( y < box.y + box.h ) )
            {
                //Set the button sprite
                clip = &clips[ CLIP_MOUSEDOWN ];
                set = true;// image will now be fixed
            }
      // likewise for the right-click code. assign set = true;
    
Fantastic, thanks so much :)
Topic archived. No new replies allowed.