From 1546beac329d017b86331d0acd2dd0dd86101506 Mon Sep 17 00:00:00 2001 From: rodri Date: Fri, 12 Mar 2021 11:37:09 +0000 Subject: implemented fixed-time dynamics stepper, animated sprites and cleaned things up. --- assets/sheets/NpcCemet.pic | Bin 0 -> 8672 bytes dat.h | 19 +++++- fns.h | 12 ++++ main.c | 144 +++++++++++++++------------------------------ mkfile | 2 + physics.c | 100 +++++++++++++++++++++++++++++++ sprite.c | 72 +++++++++++++++++++++++ 7 files changed, 249 insertions(+), 100 deletions(-) create mode 100644 assets/sheets/NpcCemet.pic create mode 100644 physics.c create mode 100644 sprite.c diff --git a/assets/sheets/NpcCemet.pic b/assets/sheets/NpcCemet.pic new file mode 100644 index 0000000..7faaa29 Binary files /dev/null and b/assets/sheets/NpcCemet.pic differ diff --git a/dat.h b/dat.h index 4dd4250..a3065ee 100644 --- a/dat.h +++ b/dat.h @@ -1,6 +1,7 @@ -typedef struct State State; +typedef struct GameState GameState; typedef struct Derivative Derivative; typedef struct Stats Stats; +typedef struct Sprite Sprite; struct Stats { @@ -12,7 +13,7 @@ struct Stats void (*update)(Stats*, double); }; -struct State +struct GameState { double x, v; Stats stats; @@ -22,3 +23,17 @@ struct Derivative { double dx, dv; }; + +struct Sprite +{ + Image *sheet; + Point sp; + Rectangle r; + int nframes; + int curframe; + ulong period; + ulong elapsed; + + void (*step)(Sprite*, ulong); + void (*draw)(Sprite*, Image*, Point); +}; diff --git a/fns.h b/fns.h index 2325ae1..6898eec 100644 --- a/fns.h +++ b/fns.h @@ -9,3 +9,15 @@ Image *eallocimage(Display*, Rectangle, ulong, int, ulong); * stats */ void statsupdate(Stats*, double); + +/* + * physics + */ +void integrate(GameState*, double, double); + +/* + * sprite + */ +Sprite *newsprite(Image*, Point, Rectangle, int, ulong); +Sprite *readsprite(char*, Point, Rectangle, int, ulong); +void delsprite(Sprite*); diff --git a/main.c b/main.c index c7ae3a3..0610921 100644 --- a/main.c +++ b/main.c @@ -9,100 +9,11 @@ #include "fns.h" RFrame screenrf; -State state; +GameState state; double t, Δt; +Sprite *ghoul, *ghoulbig; -/* - * Dynamics stepper - * - * Currently set to a basic spring-damper system. - */ -double -accel(State *s, double t) -{ - static double k = 15, b = 0.1; - - USED(t); - return -k*s->x - b*s->v; -} - -Derivative -eval(State *s0, double t, double Δt, Derivative *d) -{ - State s; - Derivative res; - - s.x = s0->x + d->dx*Δt; - s.v = s0->v + d->dv*Δt; - - res.dx = s.v; - res.dv = accel(&s, t+Δt); - return res; -} - -/* - * Explicit Euler Integrator - */ -void -euler0(State *s, double t, double Δt) -{ - static Derivative ZD = {0,0}; - Derivative d; - - d = eval(s, t, Δt, &ZD); - - s->x += d.dx*Δt; - s->v += d.dv*Δt; -} - -/* - * Semi-implicit Euler Integrator - */ -void -euler1(State *s, double t, double Δt) -{ - static Derivative ZD = {0,0}; - Derivative d; - - d = eval(s, t, Δt, &ZD); - - s->v += d.dv*Δt; - s->x += s->v*Δt; -} - -/* - * RK4 Integrator - */ -void -rk4(State *s, double t, double Δt) -{ - static Derivative ZD = {0,0}; - Derivative a, b, c, d; - double dxdt, dvdt; - - a = eval(s, t, 0, &ZD); - b = eval(s, t, Δt/2, &a); - c = eval(s, t, Δt/2, &b); - d = eval(s, t, Δt, &c); - - dxdt = 1.0/6 * (a.dx + 2*(b.dx + c.dx) + d.dx); - dvdt = 1.0/6 * (a.dv + 2*(b.dv + c.dv) + d.dv); - - s->x += dxdt*Δt; - s->v += dvdt*Δt; -} - -/* - * The Integrator - */ -void -integrate(State *s, double t, double Δt) -{ - //euler0(s, t, Δt); - //euler1(s, t, Δt); - rk4(s, t, Δt); -} Point toscreen(Point2 p) @@ -117,6 +28,20 @@ fromscreen(Point p) return rframexform(Pt2(p.x,p.y,1), screenrf); } +//void +//drawsimstats(void) +//{ +// char buf[128]; +// int i; +// +// for(i = 0; i < NSTATS; i++){ +// snprint(buf, sizeof buf, "%.3f/%.3f/%.3f[%.3f]", +// simstats[i].min, simstats[i].avg, simstats[i].max, +// simstats[i].cur); +// string(screen, addpt(screen->r.min, Pt(10,30+i*font->height)), display->white, ZP, font, buf); +// } +//} + void drawtimestep(double t) { @@ -153,6 +78,9 @@ redraw(void) drawbar(state.stats.min); drawbar(state.stats.max); drawbar(state.stats.avg); fillellipse(screen, toscreen(Pt2(0,state.x,1)), 2, 2, display->white, ZP); + ghoul->draw(ghoul, screen, toscreen(Pt2(100,-100,1))); + ghoulbig->draw(ghoulbig, screen, toscreen(Pt2(-100,-100,1))); + flushimage(display, 1); unlockdisplay(display); } @@ -171,7 +99,7 @@ resized(void) void resetsim(void) { - memset(&state, 0, sizeof(State)); + memset(&state, 0, sizeof(GameState)); state.x = 100; state.stats.update = statsupdate; t = 0; @@ -226,6 +154,8 @@ threadmain(int argc, char *argv[]) Mousectl *mc; Keyboardctl *kc; Rune r; + uvlong then, now; + double frametime, timeacc; ARGBEGIN{ default: usage(); @@ -239,15 +169,22 @@ threadmain(int argc, char *argv[]) sysfatal("initmouse: %r"); if((kc = initkeyboard(nil)) == nil) sysfatal("initkeyboard: %r"); + + display->locking = 1; + unlockdisplay(display); + screenrf.p = Pt2(screen->r.min.x+Dx(screen->r)/2,screen->r.max.y-Dy(screen->r)/2,1); screenrf.bx = Vec2(1, 0); screenrf.by = Vec2(0,-1); + ghoul = readsprite("assets/sheets/NpcCemet.pic", Pt(48,0), Rect(0,0,16,16), 5, 150); + ghoulbig = newsprite(ghoul->sheet, Pt(144,64), Rect(0,0,24,24), 5, 120); + Δt = 0.01; + then = nsec(); + timeacc = 0; resetsim(); - display->locking = 1; - unlockdisplay(display); redraw(); for(;;){ @@ -271,13 +208,24 @@ threadmain(int argc, char *argv[]) break; } - integrate(&state, t, Δt); + now = nsec(); + frametime = now - then; + then = now; + timeacc += frametime/1e9; - state.stats.update(&state.stats, state.x); + while(timeacc >= Δt){ + integrate(&state, t, Δt); - redraw(); + state.stats.update(&state.stats, state.x); + + timeacc -= Δt; + t += Δt; + } - t += Δt; + ghoul->step(ghoul, frametime/1e6); + ghoulbig->step(ghoulbig, frametime/1e6); + + redraw(); sleep(66); } diff --git a/mkfile b/mkfile index 278bf28..2b07c93 100644 --- a/mkfile +++ b/mkfile @@ -5,6 +5,8 @@ TARG=physics OFILES=\ alloc.$O\ stats.$O\ + physics.$O\ + sprite.$O\ main.$O\ HFILES=\ diff --git a/physics.c b/physics.c new file mode 100644 index 0000000..5f45fd9 --- /dev/null +++ b/physics.c @@ -0,0 +1,100 @@ +#include +#include +#include +#include "dat.h" +#include "fns.h" + +//enum { DYNTIME, RENTIME, NSTATS }; +//Stats simstats[NSTATS]; + + +/* + * Dynamics stepper + * + * Currently set to a basic spring-damper system. + */ +static double +accel(GameState *s, double t) +{ + static double k = 15, b = 0.1; + + USED(t); + return -k*s->x - b*s->v; +} + +static Derivative +eval(GameState *s0, double t, double Δt, Derivative *d) +{ + GameState s; + Derivative res; + + s.x = s0->x + d->dx*Δt; + s.v = s0->v + d->dv*Δt; + + res.dx = s.v; + res.dv = accel(&s, t+Δt); + return res; +} + +/* + * Explicit Euler Integrator + */ +static void +euler0(GameState *s, double t, double Δt) +{ + static Derivative ZD = {0,0}; + Derivative d; + + d = eval(s, t, Δt, &ZD); + + s->x += d.dx*Δt; + s->v += d.dv*Δt; +} + +/* + * Semi-implicit Euler Integrator + */ +static void +euler1(GameState *s, double t, double Δt) +{ + static Derivative ZD = {0,0}; + Derivative d; + + d = eval(s, t, Δt, &ZD); + + s->v += d.dv*Δt; + s->x += s->v*Δt; +} + +/* + * RK4 Integrator + */ +static void +rk4(GameState *s, double t, double Δt) +{ + static Derivative ZD = {0,0}; + Derivative a, b, c, d; + double dxdt, dvdt; + + a = eval(s, t, 0, &ZD); + b = eval(s, t, Δt/2, &a); + c = eval(s, t, Δt/2, &b); + d = eval(s, t, Δt, &c); + + dxdt = 1.0/6 * (a.dx + 2*(b.dx + c.dx) + d.dx); + dvdt = 1.0/6 * (a.dv + 2*(b.dv + c.dv) + d.dv); + + s->x += dxdt*Δt; + s->v += dvdt*Δt; +} + +/* + * The Integrator + */ +void +integrate(GameState *s, double t, double Δt) +{ + //euler0(s, t, Δt); + //euler1(s, t, Δt); + rk4(s, t, Δt); +} diff --git a/sprite.c b/sprite.c new file mode 100644 index 0000000..a2bf290 --- /dev/null +++ b/sprite.c @@ -0,0 +1,72 @@ +#include +#include +#include +#include "dat.h" +#include "fns.h" + +static void +sprite_step(Sprite *spr, ulong Δt) +{ + if(spr->nframes < 2) + return; + + spr->elapsed += Δt; + + if(spr->elapsed >= spr->period){ + spr->elapsed -= spr->period; + spr->curframe = ++spr->curframe % spr->nframes; + } +} + +static void +sprite_draw(Sprite *spr, Image *dst, Point dp) +{ + Point sp = (Point){ + spr->curframe * Dx(spr->r), + 0 + }; + sp = addpt(spr->sp, sp); + + draw(dst, rectaddpt(spr->r, dp), spr->sheet, nil, sp); +} + +Sprite * +newsprite(Image *sheet, Point sp, Rectangle r, int nframes, ulong period) +{ + Sprite *spr; + + spr = emalloc(sizeof(Sprite)); + spr->sheet = sheet; + spr->sp = sp; + spr->r = r; + spr->nframes = nframes; + spr->curframe = 0; + spr->period = period; + spr->elapsed = 0; + spr->step = sprite_step; + spr->draw = sprite_draw; + + return spr; +} + +Sprite * +readsprite(char *sheetfile, Point sp, Rectangle r, int nframes, ulong period) +{ + Image *sheet; + int fd; + + fd = open(sheetfile, OREAD); + if(fd < 0) + sysfatal("readsprite: %r"); + sheet = readimage(display, fd, 1); + close(fd); + + return newsprite(sheet, sp, r, nframes, period); +} + +void +delsprite(Sprite *spr) +{ + freeimage(spr->sheet); + free(spr); +} -- cgit v1.2.3