sprite-better-collision #1
127
src/sprite.c
127
src/sprite.c
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user