Jump to content
  • Advertisement
Sign in to follow this  
c4c0d3m0n

SDL_Event - Custom events

This topic is 3778 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello all I was wondering whether the SDL_Event structure can hold more than one event. When I use SDL_PollEvent(), I use it in a while() loop. Does this mean there are more events stored in the structure (like a buffer)? Could I theoretically flush the buffer? The reason I'm asking is because I'm thinking about using custom events to have my classes talk to eachother. My main game loop resides inside the Tetris class, but my input handling is done from the Player class. If Player recognises P, Tetris is the one that should pause. Ideally, I would just like something like this:

while( SDL_PollEvent( &event ) ) {

    player.handleInput( &event );

    if( event.type == SDL_USEREVENT ) {

        if( event.code == REQUEST_PAUSE )
          timer.pause();

        if( event.code == REQUEST_EXIT )
          quitloop = true;
    }
}

Obviously, Player::handleInput would also be taking care of the input used to do player-ish stuff.

Share this post


Link to post
Share on other sites
Advertisement
The SDL_Event structure was designed to be used with SDL events only.

If you want your newly defined events to also contain the SDL ones- use layering/composition, like so.


struct Tetris_Event
{
//Custom data here...
SDL_Event sdlEvent;
};
.

My advice to you however is to review your design a little. Classes should have well defined responsibilities & who is responsible for handling "user input" in your example is somewhat confusing.

You could have the Tetris (or say, TetrisGame) class process all the user input (SDL_Events) events. Then- say you needed to rotate the active piece- TetrisGame detects an SDL_Event.KEY_PRESS_WHATEVER & then sends off a RotatePiece_Event (containing information like the direction of rotation) to the appropriate TetrisPiece class (which in turn is responsible for the actual rotation).

Share this post


Link to post
Share on other sites
Quote:
Original post by Metro_Mystery
The SDL_Event structure was designed to be used with SDL events only.


Actually SDL does provide one event type that users can use for their own uses.

That doesn't invalidate what you said though. c4c0d3m0n, using the SDL event mechanism is a bad way to do what you are trying to do. Objects should talk to each other by calling member functions.

Share this post


Link to post
Share on other sites
Quote:
Original post by Simian Man
Actually SDL does provide one event type that users can use for their own uses.


Ahh SDL_UserEvent... Whoops! Even so, as we've both said; it's a very bad idea using it!

Share this post


Link to post
Share on other sites
Alright then, I'll handle the input through Tetris.

My Player class holds all the player-data, including the current piece. It's starting to become funny how many times I'm calling a flipping function (for turning a piece).


void Player::flipcw()
{
curr_tetrominoe.flipcw();
}

void Tetrominoe::flipcw()
{
form.flipcw()
}

void Matrix::flipcw()
{
// Only flip if the matrix is square
if( w == h ) {

// Make a quick copy of the current matrix
Matrix tmp( *this );

// Transform!
for( int x = 0; x < w; ++x ) {
for( int y = 0; y < h; ++y ) {

this->set( x, y, tmp.get( y, h-x-1 ) );
}
}

}
}
Tetrominoe is a 4x4-Matrix full of 0 and 1, defining the form, and an int defining the type


I was hoping to save one flipcw() function by having the events parsed on to the Player and then the Player handling the userinput (which in a way makes sence, the input is for the Player, not the Game).

Share this post


Link to post
Share on other sites
Quote:
Original post by c4c0d3m0n
It's starting to become funny how many times I'm calling a flipping function (for turning a piece).


From what I can see, you're delegating responsibility- & it's actually part of good design. If it doesn't make sense for someone to handle an event, pass it down to someone else who may be able to.

If your Player class holds all the tetris piece data, perhaps GameBoard would be a better name. That way you can be sure it isn't the GameBoard's responsibility to handle SDL events but rather the TetrisGame (engine). Generally, a Player class holds things like the player's name, score etc. You can have this too, just design a class and have an instance as a member of the TetrisGame- along with the GameBoard (after all, a TetrisGame HAS a player and a GameBoard).

Share this post


Link to post
Share on other sites
In order to simplify my design a bit, I got rid of the idea that there has to be a Player that plays Tetris. I just put all the Player stuff in Tetris, so that I'm actually programming the game now, and not a game idea and a player to play this idea. Also, this passing down of responsibilities now suddenly seems to pay off, for a tetrominoe is now always allowed to flip (when something is in the way for example). Here is my current Tetris class

///

/// tetris.h

///

///





#ifndef TETRIS_H

#define TETRIS_H

#include "graphics.h"
#include "font.h"
#include <SDL/SDL.h>

#include "matrix.h"
#include "tetrominoe.h"



/// ////// ///
/// Tetris ///
/// ////// ///

class Tetris
{
public:

//Tetris();
Tetris( Graphics* pointer = NULL, int width = 10, int height = 20 );
//~Tetris();

void play();


private:

// Game stuff
Matrix playfield;

Tetrominoe curr_tetro;
Tetrominoe next_tetro;

int tetro_posx;
int tetro_posy;

int player_score;
int player_level;
int player_lines;


// Operational stuff
void passTetro();

bool moveDown();
bool moveLeft();
bool moveRight();
void drop();

bool flipCW();
bool flipCCW();


// Functional stuff
Graphics* gfxptr;
Font font;

SDL_Event event;

};



#endif // TETRIS_H




bool Tetris::flipCW()
{
// Let's flip prematurely
curr_tetro.flipcw();

// The flag to check whether we did any inapropriate flipping
bool damage = false;

// Let's check is we aren't flipping out of bounds
if( tetro_posx + curr_tetro.freeSpaceLeft() + 1 <= 0 )
damage = true;

if( tetro_posx + TETRO_SIZE - curr_tetro.freeSpaceRight() - 1 >= playfield.width() )
damage = true;

if( tetro_posy + TETRO_SIZE - curr_tetro.freeSpaceBottom() - 1 >= playfield.height() )
damage = true;

// Now we need to check wether we are doing any damage to the field
if( !damage ) {
for( int i = 0; i < TETRO_SIZE; ++i ) {
for( int j = 0; j < TETRO_SIZE; ++j ) {
// If the tetro contains a piece on the coordinates
if( curr_tetro.read( j, i ) > 0 ) {
// If the field has something where the piece is now
if( playfield.get( tetro_posx + j, tetro_posy + i ) > 0 ) {
damage = true;
}
}
}
}
}

// We need to fix the damage
if( damage ) {
curr_tetro.flipccw();
return false;
}

// We flipped already

return true;
}

bool Tetris::flipCCW()
{
// Let's flip prematurely
curr_tetro.flipccw();

// The flag to check whether we did any inapropriate flipping
bool damage = false;

// Let's check is we aren't flipping out of bounds
if( tetro_posx + curr_tetro.freeSpaceLeft() + 1 <= 0 )
damage = true;

if( tetro_posx + TETRO_SIZE - curr_tetro.freeSpaceRight() - 1 >= playfield.width() )
damage = true;

if( tetro_posy + TETRO_SIZE - curr_tetro.freeSpaceBottom() - 1 >= playfield.height() )
damage = true;

// Now we need to check wether we are doing any damage to the field
if( !damage ) {
for( int i = 0; i < TETRO_SIZE; ++i ) {
for( int j = 0; j < TETRO_SIZE; ++j ) {
// If the tetro contains a piece on the coordinates
if( curr_tetro.read( j, i ) > 0 ) {
// If the field has something where the piece is now
if( playfield.get( tetro_posx + j, tetro_posy + i ) > 0 ) {
damage = true;
}
}
}
}
}

// We need to fix the damage
if( damage ) {
curr_tetro.flipcw();
return false;
}

// We flipped already

return true;
}



Here are my flipping functions. I don't like them, right now they are basically the same, except for calling flipcw() or flipccw(). I don't like big chunks of code repeating liek that. Is there a better way to solve this? (Maybe through function pointers?)

Share this post


Link to post
Share on other sites
Yes, but be very careful. Using function pointers often complicates code, which would go against your attempt t simplify things.

The easiest way to clean your code up is to implement one flip function in terms of the other.

For example, if flipCW just rotates the pieces- you could implement flip CCW like this.


bool Tetris::flipCCW()
{
flipCW();
flipCW();
flipCW();
}


as rotating counter-clockwise once in tetris is the same as rotating clockwise three times.

Hope that helps :).

Share this post


Link to post
Share on other sites
That wouldn't work though. Look at how FlipCW() works. The function will only flip if there is room to flip. There could be a situation where flipping clockwise is impossible, but flipping counter-clockwise is not. Seeing FlipCW() wouldn't work, because there is something in the way, it would automatically mean FlipCCW() doesn't work either, which is wrong.

I had another thought on this problem, I might just change the function to something like this:

enum rotation_directions { CW, CCW };

void Tetris::flip( int way )
{
// Let's flip prematurely
if( way == CW )
curr_tetro.flipcw();
else
curr.tetro.flipccw();


// ... etc

}

Share this post


Link to post
Share on other sites
Quote:
Original post by c4c0d3m0n

I had another thought on this problem, I might just change the function to something like this:

*** Source Snippet Removed ***


I was going to suggest something like that. Or keep your original set up but take the repeated code from both functions and put it into a new function and call that in both of them. Something like CheckForDamage() or whatever you would want to call it.

No need for a complicated solution when a simple one works just fine.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!