From c24cd753604fa73c8c77cec9886f6a6835b4a03d Mon Sep 17 00:00:00 2001 From: Camden Dixie O'Brien Date: Sat, 28 Dec 2024 18:57:29 +0000 Subject: [PATCH] Implement terrain collisions --- app/main.c | 56 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 46 insertions(+), 10 deletions(-) diff --git a/app/main.c b/app/main.c index cc6cf93..ae8e8c3 100644 --- a/app/main.c +++ b/app/main.c @@ -34,11 +34,17 @@ #define PWIDTH 48 #define PHEIGHT 64 #define PANIMLEN 8 +#define PFBWIDTH 12 +#define PFBHEIGHT 6 +#define PFBOFFX -6 +#define PFBOFFY 6 #define WALKSPEED 72 // pixels per second #define BASEANIMPERIOD 100 +#define NELEMS(a) (sizeof(a) / sizeof(a[0])) + typedef enum { SPRITE_DIR_DOWN = 0, SPRITE_DIR_LEFT_DOWN = 1, @@ -61,12 +67,34 @@ static SDL_Renderer *renderer; static unsigned map[MAPWIDTH][MAPHEIGHT]; static SDL_Texture *tstex, *pidle, *pwalk, *ptex; static input_state_t input; +static dvec_t vpos = { 512, 0 }; +static const unsigned passable[] = { 118, 178 }; static inline double mag(dvec_t v) { return sqrt(v.x * v.x + v.y * v.y); } +static inline unsigned tileat(double x, double y) +{ + const unsigned row = (unsigned)floor(x / TILESIZE) + MAPSHIFTX; + const unsigned col = (unsigned)floor(y / TILESIZE) + MAPSHIFTY; + if (row >= MAPWIDTH || col >= MAPHEIGHT) + return 0; + else + return map[row][col]; +} + +static inline bool tilepassable(int x, int y) +{ + const unsigned id = tileat(x, y); + for (unsigned i = 0; i < NELEMS(passable); ++i) { + if (passable[i] == id) + return true; + } + return false; +} + int main(int argc, char *argv[]) { char path[MAX_PATH_LEN]; @@ -176,8 +204,7 @@ int main(int argc, char *argv[]) pwalk = IMG_LoadTexture(renderer, path); assert(NULL != pwalk); - // Initialize view and player - dvec_t vpos = { 512, 0 }; + // Initialize player SDL_Rect psrc = { .y = 0, .w = PWIDTH, .h = PHEIGHT }; SDL_Rect pdest = { .w = SCALE * PWIDTH, .h = SCALE * PHEIGHT }; dvec_t pvel = { 0, 0 }, ppos = { 640, 96 }; @@ -247,8 +274,21 @@ int main(int argc, char *argv[]) if (pspeed != 0) { pvel.x *= WALKSPEED / pspeed; pvel.y *= WALKSPEED / pspeed; - ppos.x += (double)dt / 1000.0 * pvel.x; - ppos.y += (double)dt / 1000.0 * pvel.y; + + // Check for terrain collision, update position if none + const double nextx = ppos.x + (double)dt / 1000.0 * pvel.x; + const double nexty = ppos.y + (double)dt / 1000.0 * pvel.y; + const dvec_t pfb + = { .x = nextx + PFBOFFX, .y = nexty + PFBOFFY }; + bool valid = true; + valid &= tilepassable(pfb.x, pfb.y); + valid &= tilepassable(pfb.x + PFBWIDTH, pfb.y); + valid &= tilepassable(pfb.x, pfb.y + PFBHEIGHT); + valid &= tilepassable(pfb.x + PFBWIDTH, pfb.y + PFBHEIGHT); + if (valid) { + ppos.x = nextx; + ppos.y = nexty; + } // Update direction if (pvel.y >= 0) { @@ -267,7 +307,6 @@ int main(int argc, char *argv[]) pdir = SPRITE_DIR_UP; } - // Set walkikng texture ptex = pwalk; } else { ptex = pidle; @@ -290,11 +329,7 @@ int main(int argc, char *argv[]) const int starty = TILESIZE * floor(vpos.y / TILESIZE); for (int y = starty; y < vpos.y + VIEWHEIGHT; y += TILESIZE) { for (int x = startx; x < vpos.x + VIEWWIDTH; x += TILESIZE) { - const unsigned row = x / TILESIZE + MAPSHIFTX; - const unsigned col = y / TILESIZE + MAPSHIFTY; - if (row >= MAPWIDTH || col >= MAPHEIGHT) - continue; - const unsigned tileid = map[row][col]; + const unsigned tileid = tileat(x, y); if (0 == tileid) continue; const SDL_Rect src = { @@ -320,6 +355,7 @@ int main(int argc, char *argv[]) pdest.x = SCALE * (int)(ppos.x - vpos.x - PWIDTH / 2); pdest.y = SCALE * (int)(ppos.y - vpos.y - PHEIGHT / 2); SDL_RenderCopy(renderer, ptex, &psrc, &pdest); + SDL_RenderPresent(renderer); }