diff options
| author | Sam Anthony <sam@samanthony.xyz> | 2024-09-25 17:06:56 -0400 |
|---|---|---|
| committer | Sam Anthony <sam@samanthony.xyz> | 2024-09-25 17:06:56 -0400 |
| commit | 50f5164c529d57aeaf5c435b33683afabfc25c40 (patch) | |
| tree | 8af3aac1896196fceabc2daa5134e7b298d6c774 | |
| parent | 89e07aae62dae995faa7540fc38e66fa0c0f7369 (diff) | |
| download | balls-50f5164c529d57aeaf5c435b33683afabfc25c40.zip | |
refactor collisions
| -rw-r--r-- | balls.c | 81 | ||||
| -rw-r--r-- | balls.h | 5 | ||||
| -rw-r--r-- | collision.c | 58 |
3 files changed, 78 insertions, 66 deletions
@@ -1,6 +1,5 @@ #include "balls.h" -#include <stdio.h> #include <thread.h> #include <mouse.h> #include <keyboard.h> @@ -44,8 +43,8 @@ typedef struct { int nothers; /* number of other balls */ } BallArg; -int ballcolors[] = { DRed, DGreen, DBlue }; -Rectangle bounds = {{PAD, PAD}, {PAD+WIDTH, PAD+HEIGHT}}; +static int ballcolors[] = { DRed, DGreen, DBlue }; +static Rectangle bounds = {{PAD, PAD}, {PAD+WIDTH, PAD+HEIGHT}}; int init(char *label, Mousectl **mctl, Keyboardctl **kctl); void spawnball(void); @@ -60,9 +59,6 @@ int randint(int lo, int hi); void ball(void *arg); Image *alloccircle(int fg, int bg); void drawcircle(Image *m, Point pos); -int clamp(int v, int lo, int hi); -int min(int a, int b); -int max(int a, int b); void broadcast(Point p, Channel *cs[], int n); void frametick(void *arg); @@ -277,73 +273,43 @@ randint(int lo, int hi) { void ball(void *arg) { BallArg *barg; - Point p, oldp; - Vec v; - int m; + Ball b; Image *fill, *erase; + Point oldpos; int i; Ball other; - Point midpoint; - Vec d, n; - double magnitude; int t; barg = (BallArg *) arg; - p = oldp = barg->b.p; - v = barg->b.v; - m = barg->b.m; + b = (Ball) barg->b; fill = alloccircle(barg->color, DTransparent); erase = alloccircle(BG, DTransparent); if (fill == nil ||erase == nil) sysfatal("failed to allocate image"); + oldpos = b.p; for (;;) { - v.y += G; + b.v.y += G; - p = ptaddv(p, v); + b.p = ptaddv(b.p, b.v); - printf("(%d,%d) %f %f\n", p.x, p.y, v.x, v.y); + printf("(%d,%d) %f %f\n", b.p.x, b.p.y, b.v.x, b.v.y); - broadcast(p, barg->out, barg->nothers); + broadcast(b.p, barg->out, barg->nothers); /* check for ball collision */ for (i = 0; i < barg->nothers; i++) { recv(barg->in[i], &other); - if (iscollision(p, other.p)) { - midpoint = divpt(addpt(p, other.p), 2); - d = Vpt(other.p, p); - p = ptaddv(midpoint, vmuls(unitnorm(d), RADIUS)); - - printf("collision (%d,%d), (%d,%d)\n", p.x, p.y, other.p.x, other.p.y); - - printf("oldv: (%2.2f,%2.2f\n", v.x, v.y); - - n = unitnorm(Vpt(other.p, p)); - magnitude = 2*(vdot(v, n) - vdot(other.v, n)) / (m + other.m); - - printf("n: (%2.2f,%2.2f), magnitude: %2.2f\n", n.x, n.y, magnitude); - - v = vsub(v, vmuls(n, magnitude * m)); - - printf("newv: (%2.2f,%2.2f)\n", v.x, v.y); - } + collideball(&b, &other); } - /* check for wall collision */ - if (p.x < bounds.min.x+RADIUS || p.x > bounds.max.x-RADIUS) { - p.x = clamp(p.x, bounds.min.x+RADIUS, bounds.max.x-RADIUS); - printf("clamped to %d\n", p.x); - v.x = -v.x; - } - if (p.y < bounds.min.y+RADIUS || p.y > bounds.max.y-RADIUS) { - p.y = clamp(p.y, bounds.min.y+RADIUS, bounds.max.y-RADIUS); - v.y = -v.y; - } + collidewall(&b, bounds); + recv(barg->frametick, &t); - drawcircle(erase, oldp); - drawcircle(fill, p); - oldp = p; + drawcircle(erase, oldpos); + drawcircle(fill, b.p); + oldpos = b.p; } } @@ -372,21 +338,6 @@ drawcircle(Image *m, Point pos) { draw(screen, rectaddpt(bounds, subpt(pos, Pt(RADIUS, RADIUS))), m, nil, ZP); } -int -clamp(int v, int lo, int hi) { - return min(hi, max(v, lo)); -} - -int -min(int a, int b) { - return (a < b) ? a : b; -} - -int -max(int a, int b) { - return (a > b) ? a : b; -} - void broadcast(Point p, Channel *cs[], int n) { while (n-- > 0) @@ -1,5 +1,6 @@ #include <u.h> #include <libc.h> +#include <stdio.h> #include <draw.h> #include <cursor.h> @@ -31,4 +32,6 @@ Point ptaddv(Point p, Vec v); Vec V(double x, double y); Vec Vpt(Point p, Point q); -int iscollision(Point p, Point q);
\ No newline at end of file +int iscollision(Point p, Point q); +void collideball(Ball *b1, const Ball *b2); +void collidewall(Ball *b, Rectangle wall); diff --git a/collision.c b/collision.c index 3890f66..1fa083b 100644 --- a/collision.c +++ b/collision.c @@ -1,5 +1,9 @@ #include "balls.h" +static int clamp(int v, int lo, int hi); +static int min(int a, int b); +static int max(int a, int b); + int iscollision(Point p, Point q) { int dx, dy; @@ -8,3 +12,57 @@ iscollision(Point p, Point q) { dy = p.y - q.y; return (dx*dx + dy*dy) <= 4*RADIUS*RADIUS; } + +void +collideball(Ball *b1, const Ball *b2) { + Point midpoint; + Vec d, n; + double magnitude; + + if (!iscollision(b1->p, b2->p)) + return; + midpoint = divpt(addpt(b1->p, b2->p), 2); + d = Vpt(b2->p, b1->p); + b1->p = ptaddv(midpoint, vmuls(unitnorm(d), RADIUS)); + + printf("collision (%d,%d), (%d,%d)\n", b1->p.x, b1->p.y, b2->p.x, b2->p.y); + + printf("oldv: (%2.2f,%2.2f\n", b1->v.x, b1->v.y); + + n = unitnorm(Vpt(b2->p, b1->p)); + magnitude = 2*(vdot(b1->v, n) - vdot(b2->v, n)) / (b1->m + b2->m); + + printf("n: (%2.2f,%2.2f), magnitude: %2.2f\n", n.x, n.y, magnitude); + + b1->v = vsub(b1->v, vmuls(n, magnitude * b1->m)); + + printf("newv: (%2.2f,%2.2f)\n", b1->v.x, b1->v.y); +} + +void +collidewall(Ball *b, Rectangle wall) { + if (b->p.x < wall.min.x+RADIUS || b->p.x > wall.max.x-RADIUS) { + b->p.x = clamp(b->p.x, wall.min.x+RADIUS, wall.max.x-RADIUS); + printf("clamped to %d\n", b->p.x); + b->v.x = -b->v.x; + } + if (b->p.y < wall.min.y+RADIUS || b->p.y > wall.max.y-RADIUS) { + b->p.y = clamp(b->p.y, wall.min.y+RADIUS, wall.max.y-RADIUS); + b->v.y = -b->v.y; + } +} + +static int +clamp(int v, int lo, int hi) { + return min(hi, max(v, lo)); +} + +static int +min(int a, int b) { + return (a < b) ? a : b; +} + +static int +max(int a, int b) { + return (a > b) ? a : b; +}
\ No newline at end of file |