diff options
author | rodri <rgl@antares-labs.eu> | 2020-06-09 22:39:37 +0000 |
---|---|---|
committer | rodri <rgl@antares-labs.eu> | 2020-06-09 22:39:37 +0000 |
commit | 6572c456f7cdf6f8aaaf361e618b41816084a7ae (patch) | |
tree | 26f1fbccbcff272f9b8207bf36d584c4c476a54b | |
download | boids-6572c456f7cdf6f8aaaf361e618b41816084a7ae.tar.gz boids-6572c456f7cdf6f8aaaf361e618b41816084a7ae.tar.bz2 boids-6572c456f7cdf6f8aaaf361e618b41816084a7ae.zip |
initial commit. first stages of simulation, per-second steps avoiding the jail bars.
-rw-r--r-- | main.c | 259 | ||||
-rw-r--r-- | mkfile | 24 | ||||
-rw-r--r-- | readme.md | 6 | ||||
-rw-r--r-- | resources | 3 |
4 files changed, 292 insertions, 0 deletions
@@ -0,0 +1,259 @@ +#include <u.h> +#include <libc.h> +#include <thread.h> +#include <draw.h> +#include <mouse.h> +#include <keyboard.h> +#include <geometry.h> + +enum { + TERMINALV = 20 +}; + +enum { + Cbg, + Cfg, + NCOLOR +}; + +typedef struct Bird Bird; +typedef struct Flock Flock; + +struct Bird +{ + Point2 p, v; + Image *color; +}; + +struct Flock +{ + Bird *birds; + int nbirds; + Rectangle jail; + + void (*separate)(Flock*); + void (*align)(Flock*); + void (*cohesion)(Flock*); + void (*step)(Flock*); +}; + +RFrame worldrf; +Image *pal[NCOLOR]; +Flock *flock; + +void flockseparate(Flock*); +void flockalign(Flock*); +void flockcohesion(Flock*); +void flockstep(Flock*); + +Flock* +newflock(int nbirds, Rectangle jail) +{ + Flock *f; + Bird *b; + + f = malloc(sizeof(Flock)); + if(f == nil) + sysfatal("malloc: %r"); + setmalloctag(f, getcallerpc(&nbirds)); + f->birds = nil; + f->nbirds = 0; + f->jail = jail; + f->separate = flockseparate; + f->align = flockalign; + f->cohesion = flockcohesion; + f->step = flockstep; + + while(nbirds--){ + f->birds = realloc(f->birds, ++f->nbirds*sizeof(Bird)); + if(f->birds == nil) + sysfatal("realloc: %r"); + setrealloctag(f->birds, getcallerpc(&nbirds)); + b = &f->birds[f->nbirds-1]; + b->p = Pt2(frand()*Dx(jail),frand()*Dy(jail),1); + b->v = Vec2(cos(frand()*2*PI),sin(frand()*2*PI)); + b->v = mulpt2(b->v, TERMINALV); + b->color = pal[Cfg]; + } + + return f; +} + +void +flockseparate(Flock *) +{ +} + +void +flockalign(Flock *) +{ +} + +void +flockcohesion(Flock *) +{ +} + +void +flockstep(Flock *f) +{ + static double Δt = 1; + Bird *b; + + //f->separate(f); + //f->align(f); + //f->cohesion(f); + for(b = f->birds; b < f->birds + f->nbirds; b++){ + b->p = addpt2(b->p, mulpt2(b->v, Δt)); + if(b->p.x < 0){ + b->p.x = 0; + b->v.x = -b->v.x; + } + if(b->p.y < 0){ + b->p.y = 0; + b->v.y = -b->v.y; + } + if(b->p.x > Dx(f->jail)){ + b->p.x = Dx(f->jail); + b->v.x = -b->v.x; + } + if(b->p.y > Dy(f->jail)){ + b->p.y = Dy(f->jail); + b->v.y = -b->v.y; + } + } +} + +Point +toscreen(Point2 p) +{ + p = invrframexform(p, worldrf); + return Pt(p.x,p.y); +} + +Point2 +fromscreen(Point p) +{ + return rframexform(Pt2(p.x,p.y,1), worldrf); +} + +void +initpalette(void) +{ + pal[Cbg] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x000000ff); + pal[Cfg] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xffffffff); +} + +void +redraw(void) +{ + Bird *b; + + lockdisplay(display); + draw(screen, screen->r, pal[Cbg], nil, ZP); + for(b = flock->birds; b < flock->birds + flock->nbirds; b++){ + ellipse(screen, toscreen(b->p), 2, 2, 0, b->color, ZP); + } + flushimage(display, 1); + unlockdisplay(display); +} + +void +resized(void) +{ + lockdisplay(display); + if(getwindow(display, Refnone) < 0) + sysfatal("resize failed"); + unlockdisplay(display); + worldrf.p = Pt2(screen->r.min.x,screen->r.max.y,1); + flock->jail = Rect(0,0,Dx(screen->r),Dy(screen->r)); + redraw(); +} + +void +mouse(Mouse) +{ +} + +void +key(Rune r) +{ + switch(r){ + case Kdel: + case 'q': + threadexitsall(nil); + case ' ': + flock->step(flock); + break; + } +} + +void +usage(void) +{ + fprint(2, "usage: %s [-n nbirds]\n", argv0); + exits("usage"); +} + +void +threadmain(int argc, char *argv[]) +{ + Mousectl *mc; + Keyboardctl *kc; + Rune r; + char *s; + int nbirds; + + nbirds = 10; + ARGBEGIN{ + case 'n': + nbirds = strtol(EARGF(usage()), &s, 10); + if(*s != 0) + usage(); + break; + default: usage(); + }ARGEND; + if(argc > 0) + usage(); + + if(initdraw(nil, nil, nil) < 0) + sysfatal("initdraw: %r"); + if((mc = initmouse(nil, screen)) == nil) + sysfatal("initmouse: %r"); + if((kc = initkeyboard(nil)) == nil) + sysfatal("initkeyboard: %r"); + initpalette(); + worldrf.p = Pt2(screen->r.min.x,screen->r.max.y,1); + worldrf.bx = Vec2(1, 0); + worldrf.by = Vec2(0,-1); + + flock = newflock(nbirds, Rect(0,0,Dx(screen->r),Dy(screen->r))); + + display->locking = 1; + unlockdisplay(display); + redraw(); + + for(;;){ + enum { MOUSE, RESIZE, KEYBOARD }; + Alt a[] = { + {mc->c, &mc->Mouse, CHANRCV}, + {mc->resizec, nil, CHANRCV}, + {kc->c, &r, CHANRCV}, + {nil, nil, CHANEND} + }; + + switch(alt(a)){ + case MOUSE: + mouse(mc->Mouse); + break; + case RESIZE: + resized(); + break; + case KEYBOARD: + key(r); + break; + } + + redraw(); + } +} @@ -0,0 +1,24 @@ +</$objtype/mkfile + +BIN=/$objtype/bin/games +TARG=boids +OFILES=\ + main.$O\ + +HFILES=\ + libgeometry/geometry.h\ + +LIB=\ + libgeometry/libgeometry.a$O\ + +CFLAGS=$CFLAGS -Ilibgeometry + +</sys/src/cmd/mkone + +libgeometry/libgeometry.a$O: + cd libgeometry + mk install + +clean nuke:V: + rm -f *.[$OS] [$OS].??* $TARG + @{cd libgeometry; mk $target} diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..89cb4fd --- /dev/null +++ b/readme.md @@ -0,0 +1,6 @@ +# Bird flock simulator + +This program shows the emergent behavior observed in bird flocks, +mammal herds, fish schools and other such animal groups. It's based +on Craig W. Reynolds' “Flocks, Herds and Schools: A Distributed +Behavioral Model.” diff --git a/resources b/resources new file mode 100644 index 0000000..63deb84 --- /dev/null +++ b/resources @@ -0,0 +1,3 @@ +http://www.red3d.com/cwr/boids/ +http://www.red3d.com/cwr/papers/1987/boids.html +http://www.red3d.com/cwr/boids/RipOff_Flocking.html |