From e1cb9df9355a6ae67aac76dbcde209b8f70796ee Mon Sep 17 00:00:00 2001 From: rodri Date: Thu, 20 Feb 2020 21:56:37 +0000 Subject: git release. --- dat.h | 73 +++++++++ fns.h | 18 +++ main.c | 509 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ mkfile | 13 ++ notes | 3 + triangle.c | 58 +++++++ util.c | 40 +++++ vector.c | 54 +++++++ 8 files changed, 768 insertions(+) create mode 100644 dat.h create mode 100644 fns.h create mode 100644 main.c create mode 100644 mkfile create mode 100644 notes create mode 100644 triangle.c create mode 100644 util.c create mode 100644 vector.c diff --git a/dat.h b/dat.h new file mode 100644 index 0000000..0d1c3b3 --- /dev/null +++ b/dat.h @@ -0,0 +1,73 @@ +#define DEG 0.01745329251994330 + +enum { + STACKSZ = 8192, + SEC = 1000, + THRUST = 50, + BSPEED = 300, + FPS = 60, + Maxbisect = 4 +}; + +enum { + K↑, + K←, + K→, + Kfire, + Knav, + Kquit, + Ke +}; + +enum { + Casteroid, + Cthrust, + Cbullet, + Cprov, + Cretrov, + Cend +}; + +enum { + Sscore, + Sshield, + Sammo, + Se +}; + +typedef struct Vector Vector; +typedef struct Triangle Triangle; +typedef struct Particle Particle; +typedef struct Asteroid Asteroid; +typedef struct Bullet Bullet; +typedef struct Spacecraft Spacecraft; + +struct Vector { + double x, y; +}; + +struct Triangle { + Point p0, p1, p2; +}; + +struct Particle { + Vector p, v; + double yaw; +}; + +struct Asteroid { + Particle; + int stillin, bisectno; + Asteroid *prev, *next; +}; + +struct Bullet { + Particle; + int fired; +}; + +struct Spacecraft { + Particle; + int shields; + Bullet ammo[5]; +}; diff --git a/fns.h b/fns.h new file mode 100644 index 0000000..516fbb5 --- /dev/null +++ b/fns.h @@ -0,0 +1,18 @@ +Triangle Trian(int, int, int, int, int, int); +Triangle Trianpt(Point, Point, Point); +Point centroid(Triangle); +void triangle(Image *, Triangle, int, Image *, Point); +void filltriangle(Image *, Triangle, Image *, Point); +Triangle rotatriangle(Triangle, double, Point); +Vector Vec(double, double); +Vector Vpt(Point); +Vector addvec(Vector, Vector); +Vector subvec(Vector, Vector); +Vector mulvec(Vector, double); +double dotvec(Vector, Vector); +Vector normvec(Vector); +double round(double); +Point rotatept(Point, double, Point); +int ptincircle(Point, Point, double); +int triangleXcircle(Triangle, Point, double); +void *emalloc(ulong); diff --git a/main.c b/main.c new file mode 100644 index 0000000..f06ffcf --- /dev/null +++ b/main.c @@ -0,0 +1,509 @@ +#include +#include +#include +#include +#include +#include +#include "dat.h" +#include "fns.h" + +Rune keys[Ke] = { + [K↑] Kup, + [K←] Kleft, + [K→] Kright, + [Kfire] ' ', + [Knav] 'n', + [Kquit] 'q' +}; + +Mousectl *mctl; +int kdown; +Channel *scrsync; +Point orig; +Vector basis; +Spacecraft ship; +Asteroid asteroids; +int nasteroid; +Triangle shipmdl, thrustmdl; +Point asteroidmdl[Maxbisect][16]; +Image *colors[Cend]; +double t0, Δt; +int shownav, showthrust; +QLock pauselk; +int paused; +int ∞flag; + +char stats[Se][32]; +int score; + +void * +emalloc(ulong n) +{ + void *p; + + p = malloc(n); + if(p == nil) + sysfatal("malloc: %r"); + memset(p, 0, n); + setmalloctag(p, getcallerpc(&n)); + return p; +} + +void +addasteroid(Asteroid *a) +{ + asteroids.prev->next = a; + a->prev = asteroids.prev; + a->next = &asteroids; + asteroids.prev = a; +} + +Asteroid * +delasteroid(Asteroid *a) +{ + Asteroid *an; + + an = a->next; + a->prev->next = an; + an->prev = a->prev; + free(a); + return an; +} + +void +splitasteroid(Asteroid *a) +{ + Asteroid *newa; + + newa = emalloc(sizeof(Asteroid)); + newa->p = a->p; + newa->v.x = a->v.x*cos(PI/2) - a->v.y*sin(PI/2); + newa->v.y = a->v.x*sin(PI/2) + a->v.y*cos(PI/2); + newa->bisectno = a->bisectno; + addasteroid(newa); + newa = emalloc(sizeof(Asteroid)); + newa->p = a->p; + newa->v.x = a->v.x*cos(-PI/2) - a->v.y*sin(-PI/2); + newa->v.y = a->v.x*sin(-PI/2) + a->v.y*cos(-PI/2); + newa->bisectno = a->bisectno; + addasteroid(newa); + nasteroid += 2; +} + +Point +vectopt(Vector v) +{ + return Pt(v.x, v.y); +} + +Point +toscreen(Vector p) +{ + return addpt(orig, Pt(p.x*basis.x, p.y*basis.y)); +} + +Vector +fromscreen(Point p) +{ + return Vec(p.x-screen->r.min.x, screen->r.max.y-p.y); +} + +void +wrapcoord(Vector *p) +{ + if(p->x > Dx(screen->r)) + p->x = 0; + if(p->y > Dy(screen->r)) + p->y = 0; + if(p->x < 0) + p->x = Dx(screen->r); + if(p->y < 0) + p->y = Dy(screen->r); +} + +void +drawstats(void) +{ + int i, nfired; + + snprint(stats[Sscore], sizeof(stats[Sscore]), "SCORE %d", score); + if(∞flag) + snprint(stats[Sshield], sizeof(stats[Sshield]), "SHIELDS ∞"); + else + snprint(stats[Sshield], sizeof(stats[Sshield]), "SHIELDS %d", ship.shields); + for(i = nfired = 0; i < nelem(ship.ammo); i++) + if(ship.ammo[i].fired) + nfired++; + snprint(stats[Sammo], sizeof(stats[Sammo]), "AMMO %d/%d", nelem(ship.ammo)-nfired, nelem(ship.ammo)); + for(i = 0; i < Se; i++) + stringn(screen, addpt(screen->r.min, Pt(10, 10 + i*font->height)), display->white, ZP, font, stats[i], strlen(stats[i])); +} + +void +drawship(void) +{ + Triangle shipmdltrans, thrustmdltrans; + int i; + + shipmdltrans = rotatriangle(shipmdl, ship.yaw, Pt(0, 0)); + triangle(screen, Trianpt( + toscreen(addvec(ship.p, Vpt(shipmdltrans.p0))), + toscreen(addvec(ship.p, Vpt(shipmdltrans.p1))), + toscreen(addvec(ship.p, Vpt(shipmdltrans.p2))) + ), 0, display->white, ZP); + if(showthrust){ + thrustmdltrans = rotatriangle(thrustmdl, ship.yaw, Pt(0, 0)); + filltriangle(screen, Trianpt( + toscreen(addvec(ship.p, Vpt(thrustmdltrans.p0))), + toscreen(addvec(ship.p, Vpt(thrustmdltrans.p1))), + toscreen(addvec(ship.p, Vpt(thrustmdltrans.p2))) + ), colors[Cthrust], ZP); + } + for(i = 0; i < nelem(ship.ammo); i++) + if(ship.ammo[i].fired) + line(screen, toscreen(ship.ammo[i].p), toscreen(subvec(ship.ammo[i].p, Vec(cos(ship.ammo[i].yaw)*8, sin(ship.ammo[i].yaw)*8))), 0, 0, 0, colors[Cbullet], ZP); +} + +void +drawasteroids(void) +{ + Asteroid *ap; + Point asteroidmdltrans[16]; + int i; + + for(ap = asteroids.next; ap != &asteroids; ap = ap->next){ + for(i = 0; i < nelem(asteroidmdl[ap->bisectno]); i++) + asteroidmdltrans[i] = toscreen(addvec(ap->p, Vpt(asteroidmdl[ap->bisectno][i]))); + poly(screen, asteroidmdltrans, nelem(asteroidmdltrans), 0, 0, 0, colors[Casteroid], ZP); + } +} + +void +redraw(void) +{ + + lockdisplay(display); + draw(screen, screen->r, display->black, nil, ZP); + if(shownav){ + line(screen, toscreen(ship.p), toscreen(addvec(ship.p, ship.v)), 0, 0, 0, colors[Cprov], ZP); + line(screen, toscreen(ship.p), toscreen(addvec(ship.p, mulvec(ship.v, -1))), 0, 0, 0, colors[Cretrov], ZP); + } + drawship(); + drawasteroids(); + drawstats(); + if(paused) + stringn(screen, addpt(screen->r.min, Pt(Dx(screen->r)/2-3*font->width, Dy(screen->r)/2)), display->white, ZP, font, "PAUSED", 6); + flushimage(display, 1); + unlockdisplay(display); +} + +void +congrats(void) +{ + char *s[] = { + "CONGRATS!", + "YOU DID IT!" + }; + int i; + + lockdisplay(display); + draw(screen, screen->r, display->black, nil, ZP); + for(i = 0; i < nelem(s); i++) + stringn(screen, addpt(divpt(addpt(screen->r.min, screen->r.max), 2), Pt(-strlen(s[i])/2*font->width, i*font->height)), colors[Cprov], ZP, font, s[i], strlen(s[i])); + flushimage(display, 1); + unlockdisplay(display); + sleep(5*SEC); + threadexitsall(nil); +} + +void +gameover(void) +{ + char s[] = "GAME OVER"; + char ss[48]; + + snprint(ss, sizeof ss, "FINAL SCORE %d", score); + lockdisplay(display); + draw(screen, screen->r, display->black, nil, ZP); + stringn(screen, addpt(divpt(addpt(screen->r.min, screen->r.max), 2), Pt(-strlen(s)/2*font->width, 0)), colors[Cretrov], ZP, font, s, strlen(s)); + stringn(screen, addpt(divpt(addpt(screen->r.min, screen->r.max), 2), Pt(-strlen(ss)/2*font->width, font->height)), colors[Cretrov], ZP, font, ss, strlen(ss)); + flushimage(display, 1); + unlockdisplay(display); + sleep(5*SEC); + threadexitsall(nil); +} + +void +fire(void) +{ + int i; + + for(i = 0; i < nelem(ship.ammo); i++) + if(!ship.ammo[i].fired){ + ship.ammo[i].p = ship.p; + ship.ammo[i].v = addvec(ship.v, Vec(cos(ship.yaw)*BSPEED, sin(ship.yaw)*BSPEED)); + ship.ammo[i].yaw = ship.yaw; + ship.ammo[i].fired++; + break; + } +} + +void +scrsynproc(void *) +{ + for(;;){ + send(scrsync, nil); + sleep(SEC/FPS); + } +} + +void +mouse(void) +{ + Vector p; + + Δt = (nsec()-t0)/1e9; + kdown &= ~(1<buttons & 1){ + p = subvec(fromscreen(mctl->xy), ship.p); + ship.yaw = atan2(p.y, p.x); + kdown |= 1<r.min.x, screen->r.max.y); + redraw(); +} + +Image * +rgb(u32int c) +{ + Image *i; + + if((i = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, c)) == nil) + sysfatal("allocimage: %r"); + return i; +} + +void +initcolors(void) +{ + colors[Casteroid] = rgb(0xcc8844ff); + colors[Cthrust] = rgb(DYellow); + colors[Cbullet] = rgb(DRed); + colors[Cprov] = rgb(DGreen); + colors[Cretrov] = rgb(DYellow); +} + +void +usage(void) +{ + fprint(2, "usage: %s\n", argv0); + threadexitsall("usage"); +} + +void +threadmain(int argc, char *argv[]) +{ + Asteroid *ap, *newa; + char *s; + double elev, avgelev[Maxbisect]; + int i, j, waspaused; + + nasteroid = 4; + ARGBEGIN{ + case 'n': + nasteroid = strtol(EARGF(usage()), &s, 0); + if(s != nil) + usage(); + break; + case L'∞': ∞flag++; break; + default: usage(); + }ARGEND; + + if(initdraw(nil, nil, "asteroids") < 0) + sysfatal("initdraw: %r"); + if((mctl = initmouse(nil, screen)) == nil) + sysfatal("initmouse: %r"); + initcolors(); + srand(time(0)); + orig = Pt(screen->r.min.x, screen->r.max.y); + basis = Vec(1, -1); + memset(avgelev, 0, sizeof avgelev); + for(i = 0; i < Maxbisect; i++){ + for(j = 0; j < nelem(asteroidmdl[i])-1; j++){ + elev = frand()*(80-16*i) + (75-16*i); + asteroidmdl[i][j] = Pt( + elev*cos(((double)j/nelem(asteroidmdl[i])) * 2*PI), + elev*sin(((double)j/nelem(asteroidmdl[i])) * 2*PI) + ); + avgelev[i] += elev; + } + asteroidmdl[i][j] = asteroidmdl[i][0]; + avgelev[i] /= j; + } + shipmdl = Trian( + 8, 0, + -4, 4, + -4, -4 + ); + thrustmdl = Trian( + -12, 0, + -4, 2, + -4, -2 + ); + ship.p = Vec(Dx(screen->r)/2, Dy(screen->r)/2); + ship.yaw = 90*DEG; + ship.shields = 5; + asteroids.prev = asteroids.next = &asteroids; + for(i = 0; i < nasteroid; i++){ + srand(nsec()); + newa = emalloc(sizeof(Asteroid)); + newa->p = Vec( + ntruerand(Dx(screen->r)), + ntruerand(Dy(screen->r)) + ); + newa->v = Vec(cos(frand() * 2*PI)*50+10, sin(frand() * 2*PI)*50+10); + addasteroid(newa); + } + display->locking = 1; + unlockdisplay(display); + scrsync = chancreate(1, 0); + proccreate(scrsynproc, nil, STACKSZ); + proccreate(kbdproc, nil, STACKSZ); + t0 = nsec(); + for(;;){ + enum{MOUSE, RESIZE, SCRSYN}; + Alt a[] = { + {mctl->c, &mctl->Mouse, CHANRCV}, + {mctl->resizec, nil, CHANRCV}, + {scrsync, nil, CHANRCV}, + {nil, nil, CHANEND} + }; + switch(alt(a)){ + case MOUSE: mouse(); break; + case RESIZE: resized(); break; + case SCRSYN: redraw(); break; + } + waspaused = paused; + qlock(&pauselk); + if(waspaused) + t0 = nsec(); + Δt = (nsec()-t0)/1e9; + handlekeys(); + ship.p = addvec(ship.p, mulvec(ship.v, Δt)); + wrapcoord(&ship.p); + for(i = 0; i < nelem(ship.ammo); i++) + if(ship.ammo[i].fired){ + ship.ammo[i].p = addvec(ship.ammo[i].p, mulvec(ship.ammo[i].v, Δt)); + if(!ptinrect(vectopt(ship.ammo[i].p), Rect(0, 0, Dx(screen->r), Dy(screen->r)))) + ship.ammo[i].fired--; + } + for(ap = asteroids.next; ap != &asteroids; ap = ap->next){ + ap->p = addvec(ap->p, mulvec(ap->v, Δt)); + wrapcoord(&ap->p); + if(!∞flag && triangleXcircle(Trianpt( + addpt(vectopt(ship.p), shipmdl.p0), + addpt(vectopt(ship.p), shipmdl.p1), + addpt(vectopt(ship.p), shipmdl.p2) + ), vectopt(ap->p), avgelev[ap->bisectno])){ + if(!ap->stillin && --ship.shields == 0) + gameover(); + ap->stillin = 1; + }else + ap->stillin = 0; + for(i = 0; i < nelem(ship.ammo); i++) + if(ship.ammo[i].fired && ptincircle(vectopt(ship.ammo[i].p), vectopt(ap->p), avgelev[ap->bisectno])){ + ship.ammo[i].fired--; + score += 50*ap->bisectno; + if(++ap->bisectno < Maxbisect) + splitasteroid(ap); + ap = delasteroid(ap); + if(--nasteroid == 0) + congrats(); + } + } + t0 += Δt*1e9; + qunlock(&pauselk); + } +} diff --git a/mkfile b/mkfile new file mode 100644 index 0000000..781be02 --- /dev/null +++ b/mkfile @@ -0,0 +1,13 @@ + +#include +#include +#include "dat.h" +#include "fns.h" + +Triangle +Trian(int x0, int y0, int x1, int y1, int x2, int y2) +{ + return (Triangle){Pt(x0, y0), Pt(x1, y1), Pt(x2, y2)}; +} + +Triangle +Trianpt(Point p0, Point p1, Point p2) +{ + return (Triangle){p0, p1, p2}; +}; + +Point +centroid(Triangle t) +{ + return divpt(addpt(t.p0, addpt(t.p1, t.p2)), 3); +} + +void +triangle(Image *dst, Triangle t, int thick, Image *src, Point sp) +{ + Point pl[4]; + + pl[0] = t.p0; + pl[1] = t.p1; + pl[2] = t.p2; + pl[3] = pl[0]; + + poly(dst, pl, nelem(pl), 0, 0, thick, src, sp); +} + +void +filltriangle(Image *dst, Triangle t, Image *src, Point sp) +{ + Point pl[4]; + + pl[0] = t.p0; + pl[1] = t.p1; + pl[2] = t.p2; + pl[3] = pl[0]; + + fillpoly(dst, pl, nelem(pl), 0, src, sp); +} + +Triangle +rotatriangle(Triangle t, double θ, Point c) +{ + t.p0 = rotatept(t.p0, θ, c); + t.p1 = rotatept(t.p1, θ, c); + t.p2 = rotatept(t.p2, θ, c); + return t; +} diff --git a/util.c b/util.c new file mode 100644 index 0000000..ef31bde --- /dev/null +++ b/util.c @@ -0,0 +1,40 @@ +#include +#include +#include +#include "dat.h" +#include "fns.h" + +double +round(double n) +{ + return floor(n + 0.5); +} + +Point +rotatept(Point p, double θ, Point c) +{ + Point r; + + p = subpt(p, c); + r.x = round(p.x*cos(θ) - p.y*sin(θ)); + r.y = round(p.x*sin(θ) + p.y*cos(θ)); + r = addpt(r, c); + return r; +} + +int +ptincircle(Point p, Point c, double r) +{ + Point d; + + d = subpt(c, p); + return hypot(d.x, d.y) < r; +} + +int +triangleXcircle(Triangle t, Point c, double r) +{ + return ptincircle(t.p0, c, r) || + ptincircle(t.p1, c, r) || + ptincircle(t.p2, c, r); +} diff --git a/vector.c b/vector.c new file mode 100644 index 0000000..21a3711 --- /dev/null +++ b/vector.c @@ -0,0 +1,54 @@ +#include +#include +#include +#include "dat.h" +#include "fns.h" + +Vector +Vec(double x, double y) +{ + return (Vector){x, y}; +} + +Vector +Vpt(Point p) +{ + return (Vector){p.x, p.y}; +} + +Vector +addvec(Vector v, Vector u) +{ + return (Vector){v.x+u.x, v.y+u.y}; +} + +Vector +subvec(Vector v, Vector u) +{ + return (Vector){v.x-u.x, v.y-u.y}; +} + +Vector +mulvec(Vector v, double s) +{ + return (Vector){v.x*s, v.y*s}; +} + +double +dotvec(Vector v, Vector u) +{ + return v.x*u.x + v.y*u.y; +} + +Vector +normvec(Vector v) +{ + double len; + + len = hypot(v.x, v.y); + if(len == 0) + return (Vector){0, 0}; + v.x /= len; + v.y /= len; + return v; +} -- cgit v1.2.3