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:
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.