better collisions between sprites and map

This commit is contained in:
Akbar Rahman 2022-06-08 22:41:20 +01:00
parent dafb14a70a
commit a6bf015a06
Signed by: alvierahman90
GPG Key ID: 20609519444A1269

View File

@ -14,6 +14,14 @@ typedef struct Sprites {
} Sprite;
typedef struct SpriteCorners {
UVec itl;
UVec itr;
UVec ibl;
UVec ibr;
} SpriteCorners;
void sprite_iter_frame(Sprite *sprite, unsigned char map[], int joypad, unsigned int *fc);
int getTileIndexByCoord(unsigned int x, unsigned int y);
unsigned int sprite_internal_collision(unsigned char map[], Sprite *sprite);
@ -23,7 +31,11 @@ void sprite_decollide(unsigned char map[], Sprite *sprite);
// update a sprite for stuff that changes every frame
void sprite_iter_frame(Sprite *sprite, unsigned char map[], int joypad, unsigned int *fc)
{
int c;
int c, collision_check_steps;
// target displacement is sprite->vel but may collide, giving actual displacment
Vec displacement = {.x = 0, .y = 0};
UVec original_position;
if (sprite->frames_since_last_jump <= JUMP_TIMEOUT_FRAMES) sprite->frames_since_last_jump++;
if (sprite->frames_since_last_dash <= DASH_TIMEOUT_FRAMES) sprite->frames_since_last_dash++;
@ -94,11 +106,22 @@ void sprite_iter_frame(Sprite *sprite, unsigned char map[], int joypad, unsigned
if (((c & SC_RT) | (c & SC_RB)) && (sprite->vel.x > 0)) { sprite->vel.x = 0; }
if (((c & SC_LT) | (c & SC_LB)) && (sprite->vel.x < 0)) { sprite->vel.x = 0; }
sprite->pos.x += sprite->vel.x;
sprite->pos.y += sprite->vel.y;
int absvelx = abs(sprite->vel.x);
int absvely = abs(sprite->vel.y);
collision_check_steps = (absvelx > absvely) ? absvelx : absvely;
original_position.x = sprite->pos.x;
original_position.y = sprite->pos.y;
// check if following the path by the velocity will lead to a collision
for (int step = collision_check_steps; step >= 0; step--) {
sprite->pos.x = original_position.x + ((step * sprite->vel.x)/collision_check_steps);
sprite->pos.y = original_position.y + ((step * sprite->vel.y)/collision_check_steps);
if (!sprite_internal_collision(map, sprite)) break;
}
// holy shit it's so crunchy
sprite_decollide(map, sprite);
//sprite_decollide(map, sprite);
}
@ -108,21 +131,29 @@ int getTileIndexByCoord(unsigned int x, unsigned int y)
}
SpriteCorners *getSpriteCorners(Sprite *sprite)
{
SpriteCorners r = {
.itl = { .x = sprite->pos.x-8, .y = sprite->pos.y-16 },
.itr = { .x = sprite->pos.x-1, .y = sprite->pos.y-16 },
.ibl = { .x = sprite->pos.x-8, .y = sprite->pos.y-9 },
.ibr = { .x = sprite->pos.x-1, .y = sprite->pos.y-9 }
};
return &r;
}
// calculate internal collisions
unsigned int sprite_internal_collision(unsigned char map[], Sprite *sprite)
{
unsigned int rv = 0;
UVec itl, itr, ibl, ibr;
SpriteCorners *sc = getSpriteCorners(sprite);
itl.x = sprite->pos.x-8; itl.y = sprite->pos.y-16;
itr.x = sprite->pos.x-1; itr.y = sprite->pos.y-16;
ibl.x = sprite->pos.x-8; ibl.y = sprite->pos.y-9;
ibr.x = sprite->pos.x-1; ibr.y = sprite->pos.y-9;
if (map[getTileIndexByCoord(itl.x, itl.y)]) rv = rv | SC_ITL;
if (map[getTileIndexByCoord(itr.x, itr.y)]) rv = rv | SC_ITR;
if (map[getTileIndexByCoord(ibl.x, ibl.y)]) rv = rv | SC_IBL;
if (map[getTileIndexByCoord(ibr.x, ibr.y)]) rv = rv | SC_IBR;
if (map[getTileIndexByCoord(sc->itl.x, sc->itl.y)]) rv = rv | SC_ITL;
if (map[getTileIndexByCoord(sc->itr.x, sc->itr.y)]) rv = rv | SC_ITR;
if (map[getTileIndexByCoord(sc->ibl.x, sc->ibl.y)]) rv = rv | SC_IBL;
if (map[getTileIndexByCoord(sc->ibr.x, sc->ibr.y)]) rv = rv | SC_IBR;
return rv;
}
@ -132,67 +163,17 @@ unsigned int sprite_internal_collision(unsigned char map[], Sprite *sprite)
unsigned int sprite_collision(unsigned char map[], Sprite *sprite)
{
unsigned int rv = 0;
UVec itl, itr, ibl, ibr;
itl.x = sprite->pos.x-8; itl.y = sprite->pos.y-16;
itr.x = sprite->pos.x-1; itr.y = sprite->pos.y-16;
ibl.x = sprite->pos.x-8; ibl.y = sprite->pos.y-9;
ibr.x = sprite->pos.x-1; ibr.y = sprite->pos.y-9;
SpriteCorners *sc = getSpriteCorners(sprite);
// check if corners are in a non 0 tile
if (map[getTileIndexByCoord(itl.x, itl.y-1)]) rv = rv | SC_TL;
if (map[getTileIndexByCoord(itr.x, itr.y-1)]) rv = rv | SC_TR;
if (map[getTileIndexByCoord(ibl.x, ibl.y+1)]) rv = rv | SC_BL;
if (map[getTileIndexByCoord(ibr.x, ibr.y+1)]) rv = rv | SC_BR;
if (map[getTileIndexByCoord(itl.x-1, itl.y)]) rv = rv | SC_LT;
if (map[getTileIndexByCoord(ibl.x-1, ibl.y)]) rv = rv | SC_LB;
if (map[getTileIndexByCoord(itr.x+1, itr.y)]) rv = rv | SC_RT;
if (map[getTileIndexByCoord(ibr.x+1, ibr.y)]) rv = rv | SC_RB;
if (map[getTileIndexByCoord(sc->itl.x, sc->itl.y-1)]) rv = rv | SC_TL;
if (map[getTileIndexByCoord(sc->itr.x, sc->itr.y-1)]) rv = rv | SC_TR;
if (map[getTileIndexByCoord(sc->ibl.x, sc->ibl.y+1)]) rv = rv | SC_BL;
if (map[getTileIndexByCoord(sc->ibr.x, sc->ibr.y+1)]) rv = rv | SC_BR;
if (map[getTileIndexByCoord(sc->itl.x-1, sc->itl.y)]) rv = rv | SC_LT;
if (map[getTileIndexByCoord(sc->ibl.x-1, sc->ibl.y)]) rv = rv | SC_LB;
if (map[getTileIndexByCoord(sc->itr.x+1, sc->itr.y)]) rv = rv | SC_RT;
if (map[getTileIndexByCoord(sc->ibr.x+1, sc->ibr.y)]) rv = rv | SC_RB;
return rv;
}
// move player out of tiles by brute force searching :eyes:
// TODO redo decollision function because this is really stupid and bad and i
// think it will have to be changed when there are more players moving around
void sprite_decollide(unsigned char map[], Sprite *sprite)
{
Vec search_pos;
for (int ysearch = 0; ysearch <= SPRITE_HEIGHT; ysearch++) {
for (int xsearch = 0; xsearch <= SPRITE_WIDTH; xsearch++) {
search_pos.x = sprite->pos.x + xsearch;
search_pos.y = sprite->pos.y + ysearch;
if(sprite_internal_collision(map, sprite) == 0) {
sprite->pos.x = search_pos.x;
sprite->pos.y = search_pos.y;
return;
}
search_pos.x = sprite->pos.x - xsearch;
search_pos.y = sprite->pos.y + ysearch;
if(sprite_internal_collision(map, sprite) == 0) {
sprite->pos.x = search_pos.x;
sprite->pos.y = search_pos.y;
return;
}
search_pos.x = sprite->pos.x - xsearch;
search_pos.y = sprite->pos.y - ysearch;
if(sprite_internal_collision(map, sprite) == 0) {
sprite->pos.x = search_pos.x;
sprite->pos.y = search_pos.y;
return;
}
search_pos.x = sprite->pos.x + xsearch;
search_pos.y = sprite->pos.y - ysearch;
if(sprite_internal_collision(map, sprite) == 0) {
sprite->pos.x = search_pos.x;
sprite->pos.y = search_pos.y;
return;
}
}
}
}