better collisions between sprites and map
This commit is contained in:
parent
dafb14a70a
commit
a6bf015a06
127
src/sprite.c
127
src/sprite.c
@ -14,6 +14,14 @@ typedef struct Sprites {
|
|||||||
} Sprite;
|
} 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);
|
void sprite_iter_frame(Sprite *sprite, unsigned char map[], int joypad, unsigned int *fc);
|
||||||
int getTileIndexByCoord(unsigned int x, unsigned int y);
|
int getTileIndexByCoord(unsigned int x, unsigned int y);
|
||||||
unsigned int sprite_internal_collision(unsigned char map[], Sprite *sprite);
|
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
|
// update a sprite for stuff that changes every frame
|
||||||
void sprite_iter_frame(Sprite *sprite, unsigned char map[], int joypad, unsigned int *fc)
|
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_jump <= JUMP_TIMEOUT_FRAMES) sprite->frames_since_last_jump++;
|
||||||
if (sprite->frames_since_last_dash <= DASH_TIMEOUT_FRAMES) sprite->frames_since_last_dash++;
|
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_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; }
|
if (((c & SC_LT) | (c & SC_LB)) && (sprite->vel.x < 0)) { sprite->vel.x = 0; }
|
||||||
|
|
||||||
sprite->pos.x += sprite->vel.x;
|
int absvelx = abs(sprite->vel.x);
|
||||||
sprite->pos.y += sprite->vel.y;
|
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
|
// 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
|
// calculate internal collisions
|
||||||
unsigned int sprite_internal_collision(unsigned char map[], Sprite *sprite)
|
unsigned int sprite_internal_collision(unsigned char map[], Sprite *sprite)
|
||||||
{
|
{
|
||||||
unsigned int rv = 0;
|
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;
|
if (map[getTileIndexByCoord(sc->itl.x, sc->itl.y)]) rv = rv | SC_ITL;
|
||||||
itr.x = sprite->pos.x-1; itr.y = sprite->pos.y-16;
|
if (map[getTileIndexByCoord(sc->itr.x, sc->itr.y)]) rv = rv | SC_ITR;
|
||||||
ibl.x = sprite->pos.x-8; ibl.y = sprite->pos.y-9;
|
if (map[getTileIndexByCoord(sc->ibl.x, sc->ibl.y)]) rv = rv | SC_IBL;
|
||||||
ibr.x = sprite->pos.x-1; ibr.y = sprite->pos.y-9;
|
if (map[getTileIndexByCoord(sc->ibr.x, sc->ibr.y)]) rv = rv | SC_IBR;
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
return rv;
|
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 sprite_collision(unsigned char map[], Sprite *sprite)
|
||||||
{
|
{
|
||||||
unsigned int rv = 0;
|
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;
|
|
||||||
|
|
||||||
// check if corners are in a non 0 tile
|
// check if corners are in a non 0 tile
|
||||||
if (map[getTileIndexByCoord(itl.x, itl.y-1)]) rv = rv | SC_TL;
|
if (map[getTileIndexByCoord(sc->itl.x, sc->itl.y-1)]) rv = rv | SC_TL;
|
||||||
if (map[getTileIndexByCoord(itr.x, itr.y-1)]) rv = rv | SC_TR;
|
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(ibl.x, ibl.y+1)]) rv = rv | SC_BL;
|
if (map[getTileIndexByCoord(sc->ibr.x, sc->ibr.y+1)]) rv = rv | SC_BR;
|
||||||
if (map[getTileIndexByCoord(ibr.x, 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(itl.x-1, itl.y)]) rv = rv | SC_LT;
|
if (map[getTileIndexByCoord(sc->itr.x+1, sc->itr.y)]) rv = rv | SC_RT;
|
||||||
if (map[getTileIndexByCoord(ibl.x-1, ibl.y)]) rv = rv | SC_LB;
|
if (map[getTileIndexByCoord(sc->ibr.x+1, sc->ibr.y)]) rv = rv | SC_RB;
|
||||||
|
|
||||||
if (map[getTileIndexByCoord(itr.x+1, itr.y)]) rv = rv | SC_RT;
|
|
||||||
if (map[getTileIndexByCoord(ibr.x+1, ibr.y)]) rv = rv | SC_RB;
|
|
||||||
|
|
||||||
return rv;
|
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user