summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSam Anthony <sam@samanthony.xyz>2024-09-25 17:06:56 -0400
committerSam Anthony <sam@samanthony.xyz>2024-09-25 17:06:56 -0400
commit50f5164c529d57aeaf5c435b33683afabfc25c40 (patch)
tree8af3aac1896196fceabc2daa5134e7b298d6c774
parent89e07aae62dae995faa7540fc38e66fa0c0f7369 (diff)
downloadballs-50f5164c529d57aeaf5c435b33683afabfc25c40.zip
refactor collisions
-rw-r--r--balls.c81
-rw-r--r--balls.h5
-rw-r--r--collision.c58
3 files changed, 78 insertions, 66 deletions
diff --git a/balls.c b/balls.c
index 92f1f2d..d742d67 100644
--- a/balls.c
+++ b/balls.c
@@ -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)
diff --git a/balls.h b/balls.h
index 8e66ae0..69adde9 100644
--- a/balls.h
+++ b/balls.h
@@ -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