[C SDL] Platform game help

[C SDL] Platform game help

Postby Pix3l » 17 Mar 2015, 23:26

Hello to all, developing a basis for a simple platform game, I encountered some problems in the optimal management of the collisions with the tiles.
Sometimes the player, jumping here and there, remains locked to the ground, and sometimes it didn't collide with tiles at all.
I think this is related to a bad collision detection on Y axis when the player falls, but not sure, and this doesn't happen to much often...

I did a picture of the bug during the play:
Image
To trying to reproduce the bug, just walk and jump around, like the red path in the picture, and soon in a few you try the player will be stuck.

The source code for this example are available here https://sourceforge.net/p/retrogear/code/HEAD/tree/tutorial/platform_movement/.
Collisions for gravity and jumps are handled inside entity.c file, function doEntityGravity().
{l Code}: {l Select All Code}
void doEntityGravity(Entity *pobj)
{
    //Setting entity direction y
    if(pobj->vspeed>0)
    {
        pobj->direction_y = 1;
    }

    if(pobj->vspeed<0)
    {
        pobj->direction_y = -1;
    }

   if(!tileCollision(pobj->x, pobj->y+pobj->vspeed, pobj->w, pobj->h, SOLID, 0))
   {
      pobj->y+= pobj->vspeed;         //Update position
                pobj->vspeed+=pobj->gravity;  //do gravity
       
        if(pobj->vspeed<0)
        {
            pobj->status = JUMP;
        }
       
        if(pobj->vspeed>0)
        {
            pobj->status = FALL;
        }
       
        if(pobj->vspeed >= TILESIZE)   //if the speed is higher than this we might fall through a tile
            pobj->vspeed = TILESIZE;
   }
   
    //In case of cokku
   if(tileCollision(pobj->x, pobj->y+pobj->vspeed, pobj->w, pobj->h, SOLID, 0))
   {
      if(pobj->vspeed < 0)    //Verso l'alto
        {
         pobj->vspeed = 0.1f;    //Cambiamo la direzione della velocità verticale (caduta)
        }

      if(pobj->vspeed > 0)    //Verso il basso
      {
         pobj->vspeed=1.0f;   //Testing the ground

            if(pobj->status!=MOVE)
            {
                pobj->status = STAND;
            }
            pobj->direction_y = 0;
      }
       
        //Sets the entity position nearest to the tile which collide
        pobj->y = (pobj->y / TILESIZE)*TILESIZE; //a little fix for small path...
       
   }
}


Player's handling functions are defined inside player.c file, where the gravity and jumping are called.
{l Code}: {l Select All Code}
void movePlayerDynamic()
{
  (...)
    /**
     * vertical movement
     **/
   if (curr_gamepad->button_A)
   {
        curr_gamepad->button_A = 0;
       
        if(!isEntityOnFloor(&Player))
        {
            printf("Not on floor\n");
            return;
        }

        Player.vspeed = -3.6f;      //jump!
   }

   if (!curr_gamepad->button_A)
   {   
      //if the player isn't jumping already
      Player.vspeed+=Player.gravity;
   }

    doEntityGravity(&Player);
}


Tile collisions are handled by tileCollision function, inside tile.c file
{l Code}: {l Select All Code}
int tileCollision(int x, int y, int w, int h, int type, unsigned int layer)
{
    int i, j;
    int minx, miny, maxx, maxy;
   
    //Collision if outside of game field
    if (x < 0 || (x + w) > TILESIZE * curr_level->cols ||
        y < 0 || (y + h) > TILESIZE * curr_level->rows)
        return 1;

    // pixel to tiles
    minx = x / TILESIZE;
    miny = y / TILESIZE;
   
    maxx = (x + w - 1) / TILESIZE;
    maxy = (y + h - 1) / TILESIZE;

    for (i = minx; i <= maxx ; i++)
    {
        for (j = miny ; j <= maxy ; j++)
        {
            if (curr_level->map[layer][j][i]==type)
               return 1;
        }
    }
    // No collision
    return 0;
}

This one is a little improved version of this.

If you want to activate the debug mode and see the real player (red block), uncomment this line in entity.c file:
{l Code}: {l Select All Code}
#define DEBUG_GFX


What am I did wrong with this code? Is there a better way to implement gravity and collision checks in this kind of game?

Thanks to all.
Last edited by Pix3l on 18 Mar 2015, 19:26, edited 1 time in total.
http://www.pix3lworkshop.altervista.org/ - Your 8bit choice since 2006!
User avatar
Pix3l
 
Posts: 55
Joined: 10 Sep 2010, 21:00
Location: Italy

Re: [C SDL] Platform game help

Postby c_xong » 17 Mar 2015, 23:50

Collision is handled in two phases: detection and resolution.

Detection checks whether anything collides with anything, nothing more. It needs to be fast as it happens all the time.

Resolution makes sure things in collision move away from each other, so that they are no longer in collision. It needs to be robust, to resolve many different scenarios.

What you're describing is a classic case where resolution has failed to remove the collision. The simplest way to check for this is to add an assertion after your resolution, that the entities are no longer in collision. If it is, you can break at that point and work backwards, to see why resolution did not work.
User avatar
c_xong
 
Posts: 234
Joined: 06 Sep 2013, 04:33

Re: [C SDL] Platform game help

Postby Pix3l » 18 Mar 2015, 19:28

Yes, just as I thought, and as I think I've done in the code.
But something still escapes me ...

Anyway, thanks for your reply :]
http://www.pix3lworkshop.altervista.org/ - Your 8bit choice since 2006!
User avatar
Pix3l
 
Posts: 55
Joined: 10 Sep 2010, 21:00
Location: Italy

Re: [C SDL] Platform game help

Postby andrewj » 19 Mar 2015, 01:19

I had a look.

You don't handle the case of the player hitting the ground properly in doEntityGravity(). The line "pobj->y = (pobj->y / TILESIZE)*TILESIZE" places the player at the top of the tile. Since the player is 12 units high, and tiles are 16 units high, that leaves 4 units of space under the player.

So that player tries to fall again by gravity, but the same code runs again and places him at top of tile again.

What you really want is a tileCollision() function which returns how far the player could have moved (i.e. the distance between current position and touching the nearby tile). Then when collision occurs, you place the player at that furthest point (subtracting a tiny bit to prevent getting stuck).

Of course making a tileCollision() function which does that is a lot harder. It should also use floating point for coordinates (the conversion from float to int is part of your problem). Good luck.
User avatar
andrewj
 
Posts: 194
Joined: 15 Dec 2009, 16:32
Location: Tasmania

Re: [C SDL] Platform game help

Postby Pix3l » 19 Mar 2015, 20:13

andrewj {l Wrote}:I had a look.

You don't handle the case of the player hitting the ground properly in doEntityGravity(). The line "pobj->y = (pobj->y / TILESIZE)*TILESIZE" places the player at the top of the tile. Since the player is 12 units high, and tiles are 16 units high, that leaves 4 units of space under the player.

So that player tries to fall again by gravity, but the same code runs again and places him at top of tile again.

What you really want is a tileCollision() function which returns how far the player could have moved (i.e. the distance between current position and touching the nearby tile). Then when collision occurs, you place the player at that furthest point (subtracting a tiny bit to prevent getting stuck).

Of course making a tileCollision() function which does that is a lot harder. It should also use floating point for coordinates (the conversion from float to int is part of your problem). Good luck.


Maybe you're right, but I can simply calculate the distance from the tile with the difference between player height and tile size, and shift the player that much.
If the player height is bigger than tile size, no need to shift.
Anyway, if this was the problem, I think the player will continue to move down due to gravity.
I think will try an another way to check the collision for vertical axis and try to do some more debug...

The tilecollision function, search from an "A" point along a "B" point, every tiles on the way, I thought the way I choose is correct, only bit is missing maybe :]
Anyway, thanks for your interest, I will keep you updated if any progress comes ;)
http://www.pix3lworkshop.altervista.org/ - Your 8bit choice since 2006!
User avatar
Pix3l
 
Posts: 55
Joined: 10 Sep 2010, 21:00
Location: Italy

Re: [C SDL] Platform game help

Postby andrewj » 20 Mar 2015, 02:26

Yeah I was wrong about what was happening.

The line "pobj->y = (pobj->y / TILESIZE)*TILESIZE" is what confused me. When the "y" field is integer, it would do as I said (place the player at the top of his tile), but because "y" field is float it actually does almost nothing (TILESIZE is converted to float due to the C rules when mixing float and integer values to math operators -- the integer values get converted to float).

You still need to fix tileCollision() to take floating point coordinates (i.e. do the math in floating point), and you need to fix the above line so it places the player "on the ground" properly. That should be enough. The actual implementation of tileCollision() looked correct.
User avatar
andrewj
 
Posts: 194
Joined: 15 Dec 2009, 16:32
Location: Tasmania

Re: [C SDL] Platform game help

Postby Pix3l » 02 Apr 2015, 21:53

Well, I found a little spare time to trying to fix the issue.
I stepped back and implemented the logic from scratch, inspired by an old tutorial I used long ago to lay the basis.

This is the new fixed function, tested, and it seems to working good.
By casting to int the Y position of the entity, I can calculate correctly the entity destination on collision with the tiles.
{l Code}: {l Select All Code}
void doEntityGravity(Entity *pobj)
{
    //Checking collision in the up direction
    if(pobj->vspeed<0)
    {
        //Has collide on top?
        if(tileCollision(pobj->x, pobj->y+pobj->vspeed, pobj->w, pobj->h, SOLID, 0))
        {
            pobj->y = ((int)pobj->y / TILESIZE)*TILESIZE;   //Place the object nearest the top tile
         pobj->vspeed = 0;

            pobj->direction_y = 0;
        }
        else //Se non vi sono collisioni
        {
            pobj->direction_y = -1;
            pobj->status = JUMP;
            pobj->y += pobj->vspeed;         //Update its position
            pobj->vspeed += pobj->gravity;   //Gravity continues to push down
        }
    }
    else
    {
        //Has collide on bottom?
        if(tileCollision(pobj->x, pobj->y, pobj->w, pobj->h+pobj->vspeed, SOLID, 0))
        {
            unsigned int diff = TILESIZE - pobj->h;  //Difference between tile height and object height
           
         pobj->y = ((int)pobj->y/TILESIZE) * TILESIZE + diff;
         pobj->vspeed = 1;   //1 so we test against the ground again int the next frame (0 would test against the ground in the next+1 frame)

            if(pobj->status!=MOVE)
            {
                pobj->status = STAND;
            }

            pobj->direction_y = 0;
        }
        else
        {
            pobj->direction_y = 1;
            pobj->status = FALL;
            pobj->y += pobj->vspeed;         //Update its position
            pobj->vspeed += pobj->gravity;   //Gravity continues to push down

            if(pobj->vspeed >= TILESIZE)   //if the speed is higher than this we might fall through a tile
                pobj->vspeed = TILESIZE;
        }
    }
}


Thanks for your tips pal :]
http://www.pix3lworkshop.altervista.org/ - Your 8bit choice since 2006!
User avatar
Pix3l
 
Posts: 55
Joined: 10 Sep 2010, 21:00
Location: Italy

Re: [C SDL] Platform game help

Postby Pix3l » 04 Apr 2015, 10:14

Now I noticed a little problem with input handling system...
If I keep pressing the X key (jump), after pressing another key, the Player will make another jump.
This because the controls system (control.c), sees the X key is still pressed, and reperform the action on every key press, since it checks for X key pressure every time.

{l Code}: {l Select All Code}

#define BUTTON_A SDLK_x
#define BUTTON_B SDLK_z

#define BUTTON_START SDLK_RETURN
#define BUTTON_SELECT SDLK_LSHIFT

typedef struct _Gamepad {
   int button_A, button_B;
   int button_Start, button_Select;
   int button_Left, button_Right, button_Up, button_Down;   
} Gamepad;

//Gamepad structure (Keyboard / Gamepad)
Gamepad gamepad; //[2];

void inputHandler()
{
   while (SDL_PollEvent(&event))
   {
      keystate = SDL_GetKeyState( NULL );
      
      switch (event.type)
      {

         /***********************************************************
          * Keyboard input handling
          **********************************************************/

         case SDL_KEYDOWN:

            if (event.key.keysym.sym == SDLK_ESCAPE)
               quit = 1;
            
                /*******************************************************
                 * Generic gamepad buttons
                 ******************************************************/

                if(keystate[BUTTON_A])
                {
                    #ifdef DEBUG_INPUT
                        printf("Button A pressed\n");
                    #endif
                    curr_gamepad->button_A = 1;
                }

                if(keystate[BUTTON_B])
                {
                    #ifdef DEBUG_INPUT
                        printf("Button B pressed\n");
                    #endif
                    curr_gamepad->button_B = 1;
                }

                if(keystate[BUTTON_START])
                {
                    #ifdef DEBUG_INPUT
                        printf("Button Start pressed\n");
                    #endif
                    curr_gamepad->button_Start = 1;
                }

                if(keystate[BUTTON_SELECT])
                {
                    #ifdef DEBUG_INPUT
                        printf("Button Select pressed\n");
                    #endif
                    curr_gamepad->button_Select = 1;
                }
               
                /*******************************************************
                 * Direction and axis
                 ******************************************************/

                if(keystate[SDLK_LEFT]) //|| joystick axis...
                {
                    #ifdef DEBUG_INPUT
                        printf("Button Left pressed\n");
                    #endif
                    curr_gamepad->button_Left = 1;
                }

                if(keystate[SDLK_RIGHT]) //|| joystick axis...
                {
                    #ifdef DEBUG_INPUT
                        printf("Button Right pressed\n");
                    #endif
                    curr_gamepad->button_Right = 1;
                }

                if(keystate[SDLK_UP]) //|| joystick axis...
                {
                    #ifdef DEBUG_INPUT
                        printf("Button Up pressed\n");
                    #endif
                    curr_gamepad->button_Up = 1;
                }

                if(keystate[SDLK_DOWN]) //|| joystick axis...
                {
                    #ifdef DEBUG_INPUT
                        printf("Button Down pressed\n");
                    #endif
                    curr_gamepad->button_Down = 1;
                }

            break;

            case SDL_KEYUP:

                if(!keystate[BUTTON_A])
                {
                    #ifdef DEBUG_INPUT
                        if(curr_gamepad->button_A)
                        printf("Button A released\n");
                    #endif
                    curr_gamepad->button_A = 0;
                }

                if(!keystate[BUTTON_B])
                {
                    #ifdef DEBUG_INPUT
                        if(curr_gamepad->button_B)
                        printf("Button B released\n");
                    #endif
                    curr_gamepad->button_B = 0;
                }

                if(!keystate[BUTTON_START])
                {
                    #ifdef DEBUG_INPUT
                        if(curr_gamepad->button_Start)
                        printf("Button Start released\n");
                    #endif
                    curr_gamepad->button_Start = 0;
                }

                if(!keystate[BUTTON_SELECT])
                {
                    #ifdef DEBUG_INPUT
                        if(curr_gamepad->button_Select)
                        printf("Button Select released\n");
                    #endif
                    curr_gamepad->button_Select = 0;
                }

                /*******************************************************
                 * Direction and axis
                 ******************************************************/

                if(!keystate[SDLK_LEFT]) //|| joystick axis...
                {
                    #ifdef DEBUG_INPUT
                        if(curr_gamepad->button_Left)
                        printf("Button Left released\n");
                    #endif
                    curr_gamepad->button_Left = 0;
                }

                if(!keystate[SDLK_RIGHT]) //|| joystick axis...
                {
                    #ifdef DEBUG_INPUT
                        if(curr_gamepad->button_Right)
                        printf("Button Right released\n");
                    #endif
                    curr_gamepad->button_Right = 0;
                }

                if(!keystate[SDLK_UP]) //|| joystick axis...
                {
                    #ifdef DEBUG_INPUT
                        if(curr_gamepad->button_Up)
                        printf("Button Up released\n");
                    #endif
                    curr_gamepad->button_Up = 0;
                }

                if(!keystate[SDLK_DOWN]) //|| joystick axis...
                {
                    #ifdef DEBUG_INPUT
                        if(curr_gamepad->button_Down)
                        printf("Button Down released\n");
                    #endif
                    curr_gamepad->button_Down = 0;
                }

         break;
         
         /***********************************************************
          * Joystick input handling
          **********************************************************/

         #ifdef USE_GAMEPAD

            case SDL_JOYBUTTONDOWN:

               switch (event.jbutton.button)
               {
                  case 1:
                     #ifdef DEBUG_INPUT
                        printf("Joystic A pressed\n");
                     #endif
                     
                     curr_gamepad->button_A = 1;
                  break;

                  case 2:
                     #ifdef DEBUG_INPUT
                        printf("Joystic B pressed\n");
                     #endif
                     
                     curr_gamepad->button_B = 1;
                  break;

                  case 8:
                     #ifdef DEBUG_INPUT
                        printf("Joystic Select pressed\n");
                     #endif
                     
                     curr_gamepad->button_Select = 1;
                  break;

                  case 9:
                     #ifdef DEBUG_INPUT
                        printf("Joystic Start pressed\n");
                     #endif
                     
                     curr_gamepad->button_Start = 1;
                  break;

               }

            break;

            case SDL_JOYBUTTONUP:

               switch (event.jbutton.button)
               {
                  case 1:
                     #ifdef DEBUG_INPUT
                        printf("Joystic A released\n");
                     #endif

                  curr_gamepad->button_A = 0;
                  break;

                  case 2:
                     #ifdef DEBUG_INPUT
                        printf("Joystic B released\n");
                     #endif
                     
                     curr_gamepad->button_B = 0;
                  break;

                  case 8:
                     #ifdef DEBUG_INPUT
                        printf("Joystic Select released\n");
                     #endif
                     
                     curr_gamepad->button_Select = 0;
                  break;

                  case 9:
                     #ifdef DEBUG_INPUT
                        printf("Joystic Start released\n");
                     #endif
                     
                     curr_gamepad->button_Start = 0;
                  break;
               }

            break;

            case SDL_JOYAXISMOTION:

               /* Horizontal movement */
               if (event.jaxis.axis == 0)
               {
                  if (event.jaxis.value < -DEAD_ZONE)
                  {
                     #ifdef DEBUG_INPUT
                        printf("Joystic Left pressed\n");
                     #endif

                     curr_gamepad->button_Left = 1;
                  }

                  else if (event.jaxis.value > DEAD_ZONE)
                  {
                     #ifdef DEBUG_INPUT
                        printf("Joystic Right pressed\n");
                     #endif
                     curr_gamepad->button_Right = 1;
                  }

                  else
                  {
                     #ifdef DEBUG_INPUT
                        printf("Joystic Left and Right released\n");
                     #endif

                     curr_gamepad->button_Left = 0;
                     curr_gamepad->button_Right = 0;
                  }
               }

               /* Vertical movement */
               if (event.jaxis.axis == 1)
               {
                  if (event.jaxis.value < -DEAD_ZONE)
                  {
                     #ifdef DEBUG_INPUT
                        printf("Joystic Up pressed\n");
                     #endif

                     curr_gamepad->button_Up = 1;
                  }

                  else if (event.jaxis.value > DEAD_ZONE)
                  {
                     #ifdef DEBUG_INPUT
                        printf("Joystic Down pressed\n");
                     #endif

                     curr_gamepad->button_Down = 1;
                  }
                  else
                  {
                     #ifdef DEBUG_INPUT
                        printf("Joystic Up and Down released\n");
                     #endif

                     curr_gamepad->button_Up = 0;
                     curr_gamepad->button_Down = 0;
                  }
               }

            break;

         #endif

         case SDL_QUIT:
            quit = 1;
         break;
         
         //Mouse support if required
         #ifdef HAVE_MOUSE
         
            case SDL_MOUSEMOTION:
               // update mouse position
               Mouse.x = event.motion.x;
               Mouse.y = event.motion.y;
            break;
            case SDL_MOUSEBUTTONDOWN:
               // update button down state if left-clicking
               if (event.button.button == 1)
                 Mouse.leftButton = 1;
            break;
            
            case SDL_MOUSEBUTTONUP:
               // update button down state if left-clicking
               if (event.button.button == 1)
                 Mouse.leftButton = 0;
            break;
         
         #endif
         
      }
   }
}


Every input is stored in a structure as a flag (0/1), reachable from every where in the program.
The player input handling is like this:

{l Code}: {l Select All Code}
void movePlayerDynamic()
{
   /**
     * horizontal movement
     **/

    //Check for collision on X axis
   if(!tileCollision(Player.x+Player.hspeed, Player.y, Player.w, Player.h, SOLID, 0))
    {
      Player.x += Player.hspeed;
    }
    else
    {
        //Permette di non rimanere appicicati ai solidi durante le derapate
        Player.hspeed *= 0.89f;
    }
   
   if (curr_gamepad->button_Left)
   {
      Player.direction_x = -1;
        Player.status = MOVE;

        Player.hspeed += Player.speed * Player.direction_x;
   }
   
   if (curr_gamepad->button_Right)
   {
      Player.direction_x = +1;
        Player.status = MOVE;

        Player.hspeed += Player.speed * Player.direction_x;
   }

   if (!curr_gamepad->button_Left && !curr_gamepad->button_Right)
   {
      if(Player.hspeed > 0.0f)
      {
         Player.hspeed -= 0.02f;

         if(Player.hspeed < 0.0f)
         {
            Player.hspeed = 0.0f;
                curr_gamepad->button_Left = 0;
         }
      }
      else if(Player.hspeed < 0.0f)
      {
         Player.hspeed += 0.02f;

         if(Player.hspeed > 0.0f)
         {
            Player.hspeed = 0.0f;
                curr_gamepad->button_Right = 0;
         }
      }
   }

   if (Player.hspeed > MAX_H_SPEED) Player.hspeed = MAX_H_SPEED;
   if (Player.hspeed < MIN_H_SPEED) Player.hspeed = MIN_H_SPEED;

   /**
     * vertical movement
     **/
   if (curr_gamepad->button_A && isEntityOnFloor(&Player))
   {
        curr_gamepad->button_A = 0;
       
        //~ if(!isEntityOnFloor(&Player))
        //~ {
            //~ printf("Not on floor\n");
            //~ return;
        //~ }

        Player.vspeed = -3.6f;      //jump!
   }

   if (!curr_gamepad->button_A && !isEntityOnFloor(&Player))
   {   
      //if the player isn't jumping already
      Player.vspeed+=Player.gravity;
   }

    printf("Button A %d\n", curr_gamepad->button_A);

    doEntityGravity(&Player);
}


What kind of strategies do you use for input handling in your game?
What improvements can I make to this system?
http://www.pix3lworkshop.altervista.org/ - Your 8bit choice since 2006!
User avatar
Pix3l
 
Posts: 55
Joined: 10 Sep 2010, 21:00
Location: Italy

Re: [C SDL] Platform game help

Postby andrewj » 04 Apr 2015, 10:35

Problem here is that you prevent player jumping again by modifying curr_gamepad state (setting button_A to 0).

You don't want to modify that state outside of the code which handles keyboard and joystick events.

Instead you should add a field to the player which keeps track of if player is jumping, such as Player.in_jump. Set it to 1 when a jump begins, and prevent another jump if already set. Can clear it when player gets back on ground AND is not pressing any jump button.
User avatar
andrewj
 
Posts: 194
Joined: 15 Dec 2009, 16:32
Location: Tasmania

Re: [C SDL] Platform game help

Postby Pix3l » 04 Apr 2015, 13:42

andrewj {l Wrote}:Problem here is that you prevent player jumping again by modifying curr_gamepad state (setting button_A to 0).

You don't want to modify that state outside of the code which handles keyboard and joystick events.

Instead you should add a field to the player which keeps track of if player is jumping, such as Player.in_jump. Set it to 1 when a jump begins, and prevent another jump if already set. Can clear it when player gets back on ground AND is not pressing any jump button.


Yes, I did it in another example, but this time I want to implement generic logics, using generic structures for all the entity, without extra variables where possible.
Maybe it's a little tricky, but I think I can do this in some manner... :]
I will experience something and see what happens...
http://www.pix3lworkshop.altervista.org/ - Your 8bit choice since 2006!
User avatar
Pix3l
 
Posts: 55
Joined: 10 Sep 2010, 21:00
Location: Italy

Re: [C SDL] Platform game help

Postby Sauer2 » 04 Apr 2015, 15:00

@Pix3l: Would having components (as described in http://gameprogrammingpatterns.com/component.html) help?
User avatar
Sauer2
 
Posts: 430
Joined: 19 Jan 2010, 14:02

Re: [C SDL] Platform game help

Postby Pix3l » 05 Apr 2015, 14:31

Sauer2 {l Wrote}:@Pix3l: Would having components (as described in http://gameprogrammingpatterns.com/component.html) help?


Thanks, I already know this :]
But for now, I think I have cleared the collision issue with platforms, but I encountered some king of anomaly on SDL input system (or maybe, only mine).

Reading SDL documentation about SDL_GetKeyState(), I learned that this function return a pointer to an array with the keyboard state.
Since my function asks for this array at every game cycle, I noticed that if I keep pressing a key and after pressing other one, the state of the keyboard, switches to some kind of reset state, like "not pressed" for every keys, and reset to pressed when my internal function check for any keys pressure.
Since my function first checks for key pressure with SDL_KEYDOWN, and sets a flag in a internal structure to 1 for a specific key, and after checks for key releases with SDL_KEYUP.
The value setted in the structure should be maintained to 1 for the relative pressed key, and not reset every game cycle, the function should see the the button already pressed and so does not entering in the SDL_KEYUP events.
Or not?

{l Code}: {l Select All Code}
void inputHandler()
{
   while (SDL_PollEvent(&event))
   {
      keystate = SDL_GetKeyState( NULL );
      
      switch (event.type)
      {

         /***********************************************************
          * Keyboard input handling
          **********************************************************/

         case SDL_KEYDOWN:

            if (event.key.keysym.sym == SDLK_ESCAPE)
               quit = 1;
            
                /*******************************************************
                 * Generic gamepad buttons
                 ******************************************************/

                if(keystate[BUTTON_A] && curr_gamepad->button_A !=LOCKED)
                {
                    #ifdef DEBUG_INPUT
                        printf("Button A pressed\n");
                    #endif

                    curr_gamepad->button_A = 1;
                }
                [...]


I just made a little workaround for this, by setting a flag to -1 for sets "key locked", that it can be a repleacement for the "in_jump" variabile, andrewj suggests.
But I'm sure there's a better way for doing this, this workaround doesn't look too good to me... :think: :think:
http://www.pix3lworkshop.altervista.org/ - Your 8bit choice since 2006!
User avatar
Pix3l
 
Posts: 55
Joined: 10 Sep 2010, 21:00
Location: Italy

Re: [C SDL] Platform game help

Postby andrewj » 06 Apr 2015, 03:53

Yeah it is not a good idea to mix event handling (processing SDL_KEYDOWN and SDL_KEYUP) and the key state array (SDL_GetKeyState).

Use one or the other, and I suggest you use SDL_GetKeyState only, and do checks like this (pseudocode) :

gamepad.up = (key_state has UPARROW) || (key_state has 'W');
gamepad.left = (key_state has LEFTARROW) || (key_state has 'A');
gamepad.right = (key_state has RIGHTARROW) || (keystate has 'D');
User avatar
andrewj
 
Posts: 194
Joined: 15 Dec 2009, 16:32
Location: Tasmania

Re: [C SDL] Platform game help

Postby c_xong » 07 Apr 2015, 00:54

I've found that for any non-trivial SDL game, it's better to bite the bullet and go with a keyboard state module that only uses SDL_PollEvent. SDL_GetKeyState is fine for very simple things but you need the previous state in order to detect things like presses (up then down), releases (down then up), and key repeating. The latter are important for keyboard navigation of menus, typing and so on.

You can check out this for an example: https://github.com/cxong/cdogs-sdl/blob ... keyboard.c
User avatar
c_xong
 
Posts: 234
Joined: 06 Sep 2013, 04:33

Re: [C SDL] Platform game help

Postby andrewj » 07 Apr 2015, 09:56

For menus, using events is easier.

For in-game control, SDL_GetKeyState() is easier, and I don't see any major reason to roll your own version of it.
User avatar
andrewj
 
Posts: 194
Joined: 15 Dec 2009, 16:32
Location: Tasmania

Re: [C SDL] Platform game help

Postby Pix3l » 09 Apr 2015, 20:37

I experienced the problem with every game keys (directions and buttons), I think the problem it's that SDL treats every keys pressures as an event, saving and polling it in every cycle of my game (SDL_PollEvent).
I think I should restructure my control handling system...
Anyway, I fixed the platform game demo and committed it to the svn repository for now :]
http://www.pix3lworkshop.altervista.org/ - Your 8bit choice since 2006!
User avatar
Pix3l
 
Posts: 55
Joined: 10 Sep 2010, 21:00
Location: Italy

Re: [C SDL] Platform game help

Postby Pix3l » 10 Apr 2015, 18:54

c_xong {l Wrote}:I've found that for any non-trivial SDL game, it's better to bite the bullet and go with a keyboard state module that only uses SDL_PollEvent. SDL_GetKeyState is fine for very simple things but you need the previous state in order to detect things like presses (up then down), releases (down then up), and key repeating. The latter are important for keyboard navigation of menus, typing and so on.

You can check out this for an example: https://github.com/cxong/cdogs-sdl/blob ... keyboard.c


Interesting approch, I want to implement something like this but more simple and less memory and cpu consuming... :]
http://www.pix3lworkshop.altervista.org/ - Your 8bit choice since 2006!
User avatar
Pix3l
 
Posts: 55
Joined: 10 Sep 2010, 21:00
Location: Italy

Re: [C SDL] Platform game help

Postby Pix3l » 14 Aug 2015, 17:33

Well, I found a way for managing inputs!
Inspired by this old Dos tutorial, I saw that SDL use a very similar system for handling input events, and so, I handled them in the old way.

I saw that SDL_GetKeyState return a snapshot of the current keyboard state as an array, this mean that multiple inputs can be handled in one shot, but this has make me some troubles in some situations, so I opted for the old way, handling one input event a time, and works good!

The new code is here, I have only some minor bugs to fix with joystick interactions (If I keep press a direction and push a button, the program seems to get some wrong input in the axis...), but I have tested it on all of my tutorial and seems to works good enough.
controls.c

I hope this can be useful to others :]
http://www.pix3lworkshop.altervista.org/ - Your 8bit choice since 2006!
User avatar
Pix3l
 
Posts: 55
Joined: 10 Sep 2010, 21:00
Location: Italy

Who is online

Users browsing this forum: No registered users and 1 guest