From a6bf015a06177fb09d5487796452afaf805ae983 Mon Sep 17 00:00:00 2001 From: Alvie Rahman Date: Wed, 8 Jun 2022 22:41:20 +0100 Subject: [PATCH] better collisions between sprites and map --- src/sprite.c | 127 ++++++++++++++++++++++----------------------------- 1 file changed, 54 insertions(+), 73 deletions(-) diff --git a/src/sprite.c b/src/sprite.c index 9a3b7a7..b40e682 100644 --- a/src/sprite.c +++ b/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; - } - } - } -}