From b39189b6d151bc8259302e361e85e316754133f0 Mon Sep 17 00:00:00 2001 From: Camden Dixie O'Brien Date: Tue, 31 Dec 2024 13:01:48 +0000 Subject: [PATCH] Create entity_t struct and define entityupdate() and entitydraw() --- app/main.c | 161 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 102 insertions(+), 59 deletions(-) diff --git a/app/main.c b/app/main.c index 5d8a91b..c40cf1f 100644 --- a/app/main.c +++ b/app/main.c @@ -62,14 +62,32 @@ typedef struct { bool left, right, up, down; } input_state_t; +typedef struct { + int x, y; +} ivec_t; + typedef struct { double x, y; } dvec_t; +typedef struct { + dvec_t off, ext; +} dbox_t; + +typedef struct { + int svar, animlen; + double speed; + dvec_t pos, dir; + ivec_t animstep, svarstep; + dbox_t fbox; + SDL_Texture *tex; + SDL_Rect src; +} entity_t; + static SDL_Window *window; static SDL_Renderer *renderer; static unsigned map[MAPWIDTH][MAPHEIGHT]; -static SDL_Texture *tstex, *pidle, *pwalk, *ptex; +static SDL_Texture *tstex, *pidle, *pwalk; static input_state_t input; static dvec_t vpos = { -128, -96 }; static const unsigned impassable[] = { 284 }; @@ -104,6 +122,58 @@ static inline bool tilepassable(int x, int y) return true; } +static void entityupdate(entity_t *e, double dt) +{ + if (0 == e->speed) + return; + + // Update sprite variant + if (e->dir.y >= 0) { + if (e->dir.x > 0) + e->svar = SPRITE_DIR_RIGHT_DOWN; + else if (e->dir.x < 0) + e->svar = SPRITE_DIR_LEFT_DOWN; + else + e->svar = SPRITE_DIR_DOWN; + } else if (e->dir.y < 0) { + if (e->dir.x > 0) + e->svar = SPRITE_DIR_RIGHT_UP; + else if (e->dir.x < 0) + e->svar = SPRITE_DIR_LEFT_UP; + else + e->svar = SPRITE_DIR_UP; + } + + // Apply velocity (handling map collisions) + const double nextx = e->pos.x + dt * e->speed * e->dir.x; + const double nexty = e->pos.y + dt * e->speed * e->dir.y; + const dvec_t pfb + = { .x = nextx + e->fbox.off.x, .y = nexty + e->fbox.off.y }; + bool valid = true; + valid &= tilepassable(pfb.x, pfb.y); + valid &= tilepassable(pfb.x + e->fbox.ext.x, pfb.y); + valid &= tilepassable(pfb.x, pfb.y + e->fbox.ext.y); + valid &= tilepassable(pfb.x + e->fbox.ext.x, pfb.y + e->fbox.ext.y); + if (valid) { + e->pos.x = nextx; + e->pos.y = nexty; + } +} + +static void entitydraw(entity_t *e, uint64_t t) +{ + const unsigned frame = (t / BASEANIMPERIOD) % e->animlen; + e->src.x = e->animstep.x * frame + e->svarstep.x * e->svar; + e->src.y = e->animstep.y * frame + e->svarstep.y * e->svar; + SDL_Rect dest = { + .x = SCALE * (int)(e->pos.x - vpos.x - e->src.w / 2), + .y = SCALE * (int)(e->pos.y - vpos.y - e->src.h / 2), + .w = SCALE * e->src.w, + .h = SCALE * e->src.h, + }; + SDL_RenderCopy(renderer, e->tex, &e->src, &dest); +} + int main(int argc, char *argv[]) { char path[MAX_PATH_LEN]; @@ -214,18 +284,26 @@ int main(int argc, char *argv[]) assert(NULL != pwalk); // 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 = { 0, 0 }; - sprite_dir_t pdir = SPRITE_DIR_DOWN; - ptex = pidle; + entity_t p = { + .svar = SPRITE_DIR_DOWN, + .animlen = PANIMLEN, + .tex = pidle, + .animstep = { .x = PWIDTH }, + .svarstep = { .y = PHEIGHT }, + .fbox = { + .off = { .x = PFBOFFX, .y = PFBOFFY }, + .ext = { .x = PFBWIDTH, .y = PFBHEIGHT }, + }, + .src = { .w = PWIDTH, .h = PHEIGHT }, + }; SDL_Event event; uint64_t prevt = SDL_GetTicks64(); while (1) { // Calculate dt const uint64_t t = SDL_GetTicks64(); - const uint64_t dt = t - prevt; + const uint64_t dt_ms = t - prevt; + const double dt = dt_ms / 1000.0; prevt = t; // Handle events @@ -277,58 +355,28 @@ int main(int argc, char *argv[]) } // Calculate and apply velocity - pvel.x = (input.left ? -1 : 0) + (input.right ? 1 : 0); - pvel.y = (input.up ? -1 : 0) + (input.down ? 1 : 0); - const double pspeed = mag(pvel); - if (pspeed != 0) { - pvel.x *= WALKSPEED / pspeed; - pvel.y *= WALKSPEED / pspeed; - - // 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) { - if (pvel.x > 0) - pdir = SPRITE_DIR_RIGHT_DOWN; - else if (pvel.x < 0) - pdir = SPRITE_DIR_LEFT_DOWN; - else - pdir = SPRITE_DIR_DOWN; - } else if (pvel.y < 0) { - if (pvel.x > 0) - pdir = SPRITE_DIR_RIGHT_UP; - else if (pvel.x < 0) - pdir = SPRITE_DIR_LEFT_UP; - else - pdir = SPRITE_DIR_UP; - } - - ptex = pwalk; + p.dir.x = (input.left ? -1 : 0) + (input.right ? 1 : 0); + p.dir.y = (input.up ? -1 : 0) + (input.down ? 1 : 0); + const double dmag = mag(p.dir); + if (dmag != 0) { + p.dir.x /= dmag; + p.dir.y /= dmag; + p.tex = pwalk; + p.speed = WALKSPEED; } else { - ptex = pidle; + p.tex = pidle; + p.speed = 0; } + entityupdate(&p, dt); // Update view const dvec_t pvdisp = { - .x = ppos.x - (vpos.x + VIEWWIDTH / 2), - .y = ppos.y - (vpos.y + VIEWHEIGHT / 2), + .x = p.pos.x - (vpos.x + VIEWWIDTH / 2), + .y = p.pos.y - (vpos.y + VIEWHEIGHT / 2), }; - if (mag(pvdisp) > 72 && dot(pvdisp, pvel) > 0) { - const double nextx = vpos.x + (double)dt / 1000.0 * pvel.x; - const double nexty = vpos.y + (double)dt / 1000.0 * pvel.y; + if (mag(pvdisp) > 72 && dot(pvdisp, p.dir) > 0) { + const double nextx = vpos.x + dt * p.speed * p.dir.x; + const double nexty = vpos.y + dt * p.speed * p.dir.y; const bool validx = nextx >= MAPMINX && nextx < MAPMAXX; const bool validy = nexty >= MAPMINY && nexty < MAPMAXY; if (validx && validy) { @@ -364,12 +412,7 @@ int main(int argc, char *argv[]) } // Draw player - const unsigned piframe = (t / BASEANIMPERIOD) % PANIMLEN; - psrc.x = PWIDTH * piframe; - psrc.y = PHEIGHT * pdir; - 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); + entitydraw(&p, t); SDL_RenderPresent(renderer); }