aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrodri <rgl@antares-labs.eu>2023-05-22 09:00:42 +0000
committerrodri <rgl@antares-labs.eu>2023-05-22 09:00:42 +0000
commite095f65376894dcdef067b63103f2e17e55a1f14 (patch)
treea941d8ed6b6c6149aa1eee503b11a955fdcf7213
parent1baca76aaf266a2d071af4a173aee5b85efeffd6 (diff)
downloadmusw-e095f65376894dcdef067b63103f2e17e55a1f14.tar.gz
musw-e095f65376894dcdef067b63103f2e17e55a1f14.tar.bz2
musw-e095f65376894dcdef067b63103f2e17e55a1f14.zip
improvements to show a bullet's explosion upon ttl consumption.
implemented a vfx subsystem to handle localized, async animations.
-rw-r--r--assets/vfx/bullet.explosion.pngbin0 -> 10209 bytes
-rw-r--r--dat.h14
-rw-r--r--fns.h8
-rw-r--r--mkfile1
-rw-r--r--musw.c49
-rw-r--r--muswd.c4
-rw-r--r--sprite.c9
-rw-r--r--todo5
-rw-r--r--universe.c15
-rw-r--r--vfx.c69
10 files changed, 156 insertions, 18 deletions
diff --git a/assets/vfx/bullet.explosion.png b/assets/vfx/bullet.explosion.png
new file mode 100644
index 0000000..ba6bfa8
--- /dev/null
+++ b/assets/vfx/bullet.explosion.png
Binary files differ
diff --git a/dat.h b/dat.h
index 4c9e019..024c1c9 100644
--- a/dat.h
+++ b/dat.h
@@ -59,6 +59,7 @@ enum {
typedef struct VModel VModel;
typedef struct Sprite Sprite;
+typedef struct Vfx Vfx;
typedef struct Keymap Keymap;
typedef struct State State;
typedef struct Particle Particle;
@@ -101,6 +102,18 @@ struct Sprite
void (*step)(Sprite*, ulong);
void (*draw)(Sprite*, Image*, Point);
+ Sprite *(*clone)(Sprite*);
+};
+
+struct Vfx
+{
+ Sprite *a; /* animation */
+ Point p;
+ int times; /* to repeat. -1 loops forever */
+ Vfx *prev, *next;
+
+ void (*step)(Vfx*, ulong);
+ void (*draw)(Vfx*, Image*);
};
struct Keymap
@@ -133,7 +146,6 @@ struct Bullet
struct Ship
{
Particle;
- Kind kind;
int fuel;
Bullet rounds[10];
VModel *mdl;
diff --git a/fns.h b/fns.h
index 039081d..20a58f6 100644
--- a/fns.h
+++ b/fns.h
@@ -50,6 +50,14 @@ Sprite *readpngsprite(char*, Point, Rectangle, int, ulong);
void delsprite(Sprite*);
/*
+ * vfx
+ */
+Vfx *newvfx(Sprite*, Point, int);
+void delvfx(Vfx*);
+void addvfx(Vfx*, Vfx*);
+void initvfx(Vfx*);
+
+/*
* net
*/
void dhgenpg(ulong*, ulong*);
diff --git a/mkfile b/mkfile
index 123c050..f30d877 100644
--- a/mkfile
+++ b/mkfile
@@ -14,6 +14,7 @@ OFILES=\
party.$O\
universe.$O\
sprite.$O\
+ vfx.$O\
net.$O\
fmt.$O\
diff --git a/musw.c b/musw.c
index 836a56c..ef5d331 100644
--- a/musw.c
+++ b/musw.c
@@ -20,6 +20,11 @@ enum {
NGAMESTATES
};
+enum {
+ VFX_BULLET_EXPLOSION,
+ NVFX
+};
+
Keymap kmap[] = {
{.key = Kup, .op = K↑},
{.key = Kleft, .op = K↺},
@@ -35,11 +40,13 @@ Keymap kmap[] = {
ulong kdown;
RFrame screenrf;
-Universe *universe;
+Universe *universe, *olduniverse;
VModel *needlemdl, *wedgemdl;
Image *screenb;
Image *skymap;
Sprite *intro;
+Sprite *vfxtab[NVFX];
+Vfx vfxqueue;
State gamestates[NGAMESTATES];
State *gamestate;
Channel *ingress;
@@ -65,6 +72,16 @@ fromscreen(Point p)
return rframexform(Pt2(p.x,p.y,1), screenrf);
}
+void
+swapuniverses(void)
+{
+ Universe *u;
+
+ u = universe;
+ universe = olduniverse;
+ olduniverse = u;
+}
+
/*
* readvmodel and drawship are testing routines
* that will later be implemented as VModel methods.
@@ -166,10 +183,11 @@ drawbullets(Ship *ship, Image *dst)
Point2 v;
for(i = 0; i < nelem(ship->rounds); i++){
- if(!ship->rounds[i].fired)
+ b = &ship->rounds[i];
+
+ if(!b->fired)
continue;
- b = &ship->rounds[i];
v = Vec2(-1,0); /* it's pointing backwards to paint the tail */
Matrix R = {
cos(b->θ), -sin(b->θ), 0,
@@ -406,6 +424,8 @@ threadnetppu(void *)
case NSsimstate:
weplaying = 1;
+ swapuniverses();
+
bufp = frame->data;
bufp += unpack(bufp, frame->len, "PdPdP",
&universe->ships[0].p, &universe->ships[0].θ,
@@ -431,6 +451,11 @@ threadnetppu(void *)
&universe->ships[i].rounds[bi].p, &universe->ships[i].rounds[bi].θ);
universe->ships[i].rounds[bi].fired++;
}
+
+ for(i = 0; i < nelem(universe->ships); i++)
+ for(j = 0; j < nelem(universe->ships[i].rounds); j++)
+ if(!universe->ships[i].rounds[j].fired && olduniverse->ships[i].rounds[j].fired)
+ addvfx(&vfxqueue, newvfx(vfxtab[VFX_BULLET_EXPLOSION]->clone(vfxtab[VFX_BULLET_EXPLOSION]), toscreen(universe->ships[i].rounds[j].p), 1));
break;
case NSnudge:
newf = newframe(nil, NCnudge, frame->seq+1, frame->seq, 0, nil);
@@ -557,6 +582,8 @@ drawprogressing(char *s)
void
redraw(void)
{
+ Vfx *vfx;
+
lockdisplay(display);
if(doghosting)
@@ -581,6 +608,9 @@ redraw(void)
break;
}
+ for(vfx = vfxqueue.next; vfx != &vfxqueue; vfx = vfx->next)
+ vfx->draw(vfx, screenb);
+
draw(screen, screen->r, screenb, nil, ZP);
flushimage(display, 1);
@@ -659,6 +689,7 @@ threadmain(int argc, char *argv[])
double frametime;
char *server;
int fd;
+ Vfx *vfx;
Mousectl *mc;
Ioproc *io;
@@ -704,18 +735,22 @@ threadmain(int argc, char *argv[])
sysfatal("dial: %r");
universe = newuniverse();
+ olduniverse = newuniverse();
needlemdl = readvmodel("assets/mdl/needle.vmdl");
if(needlemdl == nil)
sysfatal("readvmodel: %r");
wedgemdl = readvmodel("assets/mdl/wedge.vmdl");
if(wedgemdl == nil)
sysfatal("readvmodel: %r");
- universe->ships[0].mdl = needlemdl;
- universe->ships[1].mdl = wedgemdl;
- universe->star.spr = readpngsprite("assets/spr/pulsar.png", ZP, Rect(0,0,64,64), 9, 50);
+ olduniverse->ships[0].mdl = universe->ships[0].mdl = needlemdl;
+ olduniverse->ships[1].mdl = universe->ships[1].mdl = wedgemdl;
+ olduniverse->star.spr = universe->star.spr = readpngsprite("assets/spr/pulsar.png", ZP, Rect(0,0,64,64), 9, 50);
intro = readpngsprite("assets/spr/intro.png", ZP, Rect(0,0,640,480), 28, 100);
+ vfxtab[VFX_BULLET_EXPLOSION] = readpngsprite("assets/vfx/bullet.explosion.png", ZP, Rect(0, 0, 32, 32), 12, 100);
+ initvfx(&vfxqueue);
+
gamestates[GSIntro].δ = intro_δ;
gamestates[GSConnecting].δ = connecting_δ;
gamestates[GSMatching].δ = matching_δ;
@@ -740,6 +775,8 @@ threadmain(int argc, char *argv[])
switch(gamestate-gamestates){
case GSPlaying:
universe->star.spr->step(universe->star.spr, frametime/1e6);
+ for(vfx = vfxqueue.next; vfx != &vfxqueue; vfx = vfx->next)
+ vfx->step(vfx, frametime/1e6);
/* fallthrough */
default:
if(netconn.state == NCSConnecting)
diff --git a/muswd.c b/muswd.c
index 65c1af0..4f871d8 100644
--- a/muswd.c
+++ b/muswd.c
@@ -418,8 +418,8 @@ fprintstates(int fd)
for(p = theparty.next; p != &theparty; p = p->next, i++){
for(s = &p->u->ships[0]; s-p->u->ships < nelem(p->u->ships); s++){
- fprint(fd, "%ld s%lld k%d p %v v %v θ %g ω %g m %g f %d\n",
- i, s-p->u->ships, s->kind, s->p, s->v, s->θ, s->ω, s->mass, s->fuel);
+ fprint(fd, "%ld s%lld p %v v %v θ %g ω %g m %g f %d\n",
+ i, s-p->u->ships, s->p, s->v, s->θ, s->ω, s->mass, s->fuel);
}
fprint(fd, "%ld S p %v m %g\n", i, p->u->star.p, p->u->star.mass);
}
diff --git a/sprite.c b/sprite.c
index d000768..4af7c54 100644
--- a/sprite.c
+++ b/sprite.c
@@ -35,6 +35,12 @@ sprite_draw(Sprite *spr, Image *dst, Point dp)
draw(dst, rectaddpt(spr->r, dp), spr->sheet, nil, sp);
}
+static Sprite *
+sprite_clone(Sprite *spr)
+{
+ return newsprite(spr->sheet, spr->sp, spr->r, spr->nframes, spr->period);
+}
+
Sprite *
newsprite(Image *sheet, Point sp, Rectangle r, int nframes, ulong period)
{
@@ -50,6 +56,7 @@ newsprite(Image *sheet, Point sp, Rectangle r, int nframes, ulong period)
spr->elapsed = 0;
spr->step = sprite_step;
spr->draw = sprite_draw;
+ spr->clone = sprite_clone;
return spr;
}
@@ -111,6 +118,6 @@ readpngsprite(char *sheetfile, Point sp, Rectangle r, int nframes, ulong period)
void
delsprite(Sprite *spr)
{
- freeimage(spr->sheet);
+ //freeimage(spr->sheet);
free(spr);
}
diff --git a/todo b/todo
index 093309a..a2cd2b9 100644
--- a/todo
+++ b/todo
@@ -1,17 +1,20 @@
[ ] collision detection
[✓] toroidal warping
-[✓] respect bullets's ttl
+[ ] respect bullets's ttl
[✓] communicate this event to the clients (δ: fired 1 → 0)
[ ] explode when the time comes
[ ] fuel consumption
[ ] hyperjump
[ ] minskytron effect
[ ] engine damage on every jump
+[ ] nozzle exhaust plume rendering
[✓] different screens for each game state
[✓] intro
[✓] connecting to server
[✓] waiting for a player
[✓] main game
+[ ] keep a score
+[ ] manage health
[ ] reduce the amount of data sent on every NSsimstate packet
[✓] only send the fired bullets
[ ] bit packing
diff --git a/universe.c b/universe.c
index ceb3f1d..0278493 100644
--- a/universe.c
+++ b/universe.c
@@ -103,12 +103,15 @@ universe_collide(Universe *u)
Bullet *b;
for(s = u->ships; s < u->ships+nelem(u->ships); s++){
- for(b = s->rounds; b < s->rounds+nelem(s->rounds); b++){
- if(b->fired && b->ttl <= 0)
- b->fired = 0;
- if(b->fired)
+ for(b = s->rounds; b < s->rounds+nelem(s->rounds); b++)
+ if(b->fired){
+ if(b->ttl <= 0){
+ b->fired = 0;
+ continue;
+ }
warp(b);
- }
+
+ }
warp(s);
}
}
@@ -152,11 +155,9 @@ inituniverse(Universe *u)
}
u->ships[0].mass = 10e3; /* 10 tons */
- u->ships[0].kind = NEEDLE;
u->ships[0].fuel = 100;
u->ships[1].mass = 40e3; /* 40 tons */
- u->ships[1].kind = WEDGE;
u->ships[1].fuel = 200;
u->ships[0].forward = u->ships[1].forward = ship_forward;
diff --git a/vfx.c b/vfx.c
new file mode 100644
index 0000000..69f292f
--- /dev/null
+++ b/vfx.c
@@ -0,0 +1,69 @@
+#include <u.h>
+#include <libc.h>
+#include <ip.h>
+#include <mp.h>
+#include <libsec.h>
+#include <thread.h>
+#include <draw.h>
+#include <geometry.h>
+#include "dat.h"
+#include "fns.h"
+
+static void
+vfx_step(Vfx *v, ulong Δt)
+{
+ if(v->times == 0 && v->a->curframe == 0){
+ delvfx(v);
+ return;
+ }
+
+ v->a->step(v->a, Δt);
+
+ if(v->times > 0 && v->a->curframe == v->a->nframes-1)
+ v->times--;
+}
+
+static void
+vfx_draw(Vfx *v, Image *dst)
+{
+ v->a->draw(v->a, dst, v->p);
+}
+
+Vfx *
+newvfx(Sprite *spr, Point dp, int repeat)
+{
+ Vfx *v;
+
+ v = emalloc(sizeof(Vfx));
+ v->a = spr;
+ v->p = dp;
+ v->times = repeat;
+ v->step = vfx_step;
+ v->draw = vfx_draw;
+
+ return v;
+}
+
+void
+delvfx(Vfx *v)
+{
+ v->next->prev = v->prev;
+ v->prev->next = v->next;
+ delsprite(v->a);
+ free(v);
+}
+
+void
+addvfx(Vfx *v, Vfx *nv)
+{
+ nv->prev = v->prev;
+ nv->next = v;
+ v->prev->next = nv;
+ v->prev = nv;
+}
+
+void
+initvfx(Vfx *v)
+{
+ v->next = v->prev = v;
+}