aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrodri <rgl@antares-labs.eu>2021-03-12 11:37:09 +0000
committerrodri <rgl@antares-labs.eu>2021-03-12 11:37:09 +0000
commit1546beac329d017b86331d0acd2dd0dd86101506 (patch)
treeddd8c59a8cd0244db1730ba91ba860078205ab51
parentc35a8302c6275a1ba71dcdff15f58310d064a909 (diff)
downloadgamephysics-1546beac329d017b86331d0acd2dd0dd86101506.tar.gz
gamephysics-1546beac329d017b86331d0acd2dd0dd86101506.tar.bz2
gamephysics-1546beac329d017b86331d0acd2dd0dd86101506.zip
implemented fixed-time dynamics stepper, animated sprites and cleaned things up.
-rw-r--r--assets/sheets/NpcCemet.picbin0 -> 8672 bytes
-rw-r--r--dat.h19
-rw-r--r--fns.h12
-rw-r--r--main.c144
-rw-r--r--mkfile2
-rw-r--r--physics.c100
-rw-r--r--sprite.c72
7 files changed, 249 insertions, 100 deletions
diff --git a/assets/sheets/NpcCemet.pic b/assets/sheets/NpcCemet.pic
new file mode 100644
index 0000000..7faaa29
--- /dev/null
+++ b/assets/sheets/NpcCemet.pic
Binary files 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 <u.h>
+#include <libc.h>
+#include <draw.h>
+#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 <u.h>
+#include <libc.h>
+#include <draw.h>
+#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);
+}