Implement terrain collisions

This commit is contained in:
Camden Dixie O'Brien 2024-12-28 18:57:29 +00:00
parent f17530af4a
commit c24cd75360

View File

@ -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);
}