summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--balls.c40
-rw-r--r--balls.h15
-rw-r--r--collision.c22
-rw-r--r--graphics.c13
4 files changed, 58 insertions, 32 deletions
diff --git a/balls.c b/balls.c
index 1a10e42..cadcb72 100644
--- a/balls.c
+++ b/balls.c
@@ -21,7 +21,7 @@ enum {
DEFAULT_NBALLS = 3,
VMAX = 3,
- MASS = 10,
+ G_PER_KG = 1000,
FPS = 60,
NS_PER_SEC = 1000000000,
@@ -44,6 +44,7 @@ typedef struct {
} BallArg;
static int ballcolors[] = { DRed, DGreen, DBlue };
+static uint radii[] = { 20, 30, 50 };
static Rectangle bounds = {{PAD, PAD}, {PAD+WIDTH, PAD+HEIGHT}};
int init(char *label, Mousectl **mctl, Keyboardctl **kctl);
@@ -52,9 +53,11 @@ void spawnballs(int n);
Channel **allocchans(int nchans, int elsize, int nel);
void mcopycolskip(Channel *vec[], Channel **matrix[], int n, int col, int skip);
void vcopyskip(Channel *dst[], Channel *src[], int n, int skip);
-void nooverlapcircles(Point centers[], int n);
+void nooverlapcircles(Point centers[], int n, uint radius);
Point randptinrect(Rectangle r);
int randint(int lo, int hi);
+uint maxelem(uint arr[], uint n);
+double mass(uint radius);
void ball(void *arg);
void broadcast(Point p, Channel *cs[], int n);
void frametick(void *arg);
@@ -143,7 +146,7 @@ spawnballs(int n) {
if ((ps = malloc(n*sizeof(Point))) == nil)
sysfatal("failed to allocate position array");
- nooverlapcircles(ps, n);
+ nooverlapcircles(ps, n, maxelem(radii, NELEMS(radii)));
if ((cs = malloc(n*sizeof(Channel **))) == nil)
sysfatal("failed to allocate channel matrix");
@@ -164,7 +167,8 @@ spawnballs(int n) {
arg->b.p = ps[i];
arg->b.v = V((double) randint(-VMAX, VMAX+1), (double) randint(-VMAX, VMAX+1));
- arg->b.m = MASS;
+ arg->b.r = radii[randint(0, NELEMS(radii))];
+ arg->b.m = mass(arg->b.r);
arg->color = ballcolors[randint(0, NELEMS(ballcolors))];
@@ -234,14 +238,14 @@ vcopyskip(Channel *dst[], Channel *src[], int n, int skip) {
}
void
-nooverlapcircles(Point centers[], int n) {
+nooverlapcircles(Point centers[], int n, uint radius) {
int i, j;
srand(time(0));
for (i = 0; i < n; i++) {
- centers[i] = randptinrect(insetrect(bounds, RADIUS));
+ centers[i] = randptinrect(insetrect(bounds, radius));
for (j = 0; j < i; j++)
- if (iscollision(centers[j], centers[i]))
+ if (iscollision(centers[j], radius, centers[i], radius))
break;
if (j < i) { /* overlapping */
i--;
@@ -260,6 +264,24 @@ randint(int lo, int hi) {
return (rand() % (hi-lo)) + lo;
}
+uint
+maxelem(uint arr[], uint n) {
+ uint max;
+
+ if (n == 0)
+ return 0;
+ max = arr[--n];
+ while (n-- > 0)
+ if (arr[n] > max)
+ max = arr[n];
+ return max;
+}
+
+double
+mass(uint radius) {
+ return (double) radius / 10 / G_PER_KG;
+}
+
void
ball(void *arg) {
BallArg *barg;
@@ -273,8 +295,8 @@ ball(void *arg) {
barg = (BallArg *) arg;
b = (Ball) barg->b;
- fill = alloccircle(barg->color, DTransparent);
- erase = alloccircle(BG, DTransparent);
+ fill = alloccircle(barg->color, DTransparent, b.r);
+ erase = alloccircle(BG, DTransparent, b.r);
if (fill == nil ||erase == nil)
sysfatal("failed to allocate image");
diff --git a/balls.h b/balls.h
index 0e98506..7b68ea1 100644
--- a/balls.h
+++ b/balls.h
@@ -4,10 +4,6 @@
#include <draw.h>
#include <cursor.h>
-enum {
- RADIUS = 20,
-};
-
typedef struct {
double x, y;
} Vec;
@@ -17,9 +13,10 @@ typedef struct {
} Line;
typedef struct {
- Point p; /* position */
- Vec v; /* velocity */
- double m; /* mass */
+ Point p; /* position [pixels] */
+ Vec v; /* velocity [m/s] */
+ uint r; /* radius [pixels] */
+ double m; /* mass [kg] */
} Ball;
Vec vsub(Vec v1, Vec v2);
@@ -33,9 +30,9 @@ Vec V(double x, double y);
Vec Vpt(Point p, Point q);
void drawbg(Image *walls, Image *bg);
-Image *alloccircle(int fg, int bg);
+Image *alloccircle(int fg, int bg, uint radius);
void drawcircle(Image *m, Point pos);
-int iscollision(Point p, Point q);
+int iscollision(Point p1, uint r1, Point p2, uint r2);
void collideball(Ball *b1, const Ball *b2);
void collidewall(Ball *b, Rectangle wall);
diff --git a/collision.c b/collision.c
index 1fa083b..bf359c0 100644
--- a/collision.c
+++ b/collision.c
@@ -5,12 +5,12 @@ static int min(int a, int b);
static int max(int a, int b);
int
-iscollision(Point p, Point q) {
+iscollision(Point p1, uint r1, Point p2, uint r2) {
int dx, dy;
- dx = p.x - q.x;
- dy = p.y - q.y;
- return (dx*dx + dy*dy) <= 4*RADIUS*RADIUS;
+ dx = p1.x - p2.x;
+ dy = p1.y - p2.y;
+ return (dx*dx + dy*dy) <= (r1+r2)*(r1+r2);
}
void
@@ -19,11 +19,11 @@ collideball(Ball *b1, const Ball *b2) {
Vec d, n;
double magnitude;
- if (!iscollision(b1->p, b2->p))
+ if (!iscollision(b1->p, b1->r, b2->p, b2->r))
return;
midpoint = divpt(addpt(b1->p, b2->p), 2);
d = Vpt(b2->p, b1->p);
- b1->p = ptaddv(midpoint, vmuls(unitnorm(d), RADIUS));
+ b1->p = ptaddv(midpoint, vmuls(unitnorm(d), b1->r));
printf("collision (%d,%d), (%d,%d)\n", b1->p.x, b1->p.y, b2->p.x, b2->p.y);
@@ -41,13 +41,15 @@ collideball(Ball *b1, const Ball *b2) {
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);
+ wall = insetrect(wall, b->r);
+
+ if (b->p.x < wall.min.x || b->p.x > wall.max.x) {
+ b->p.x = clamp(b->p.x, wall.min.x, wall.max.x);
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);
+ if (b->p.y < wall.min.y || b->p.y > wall.max.y) {
+ b->p.y = clamp(b->p.y, wall.min.y, wall.max.y);
b->v.y = -b->v.y;
}
}
diff --git a/graphics.c b/graphics.c
index c03dc8e..12ca8ea 100644
--- a/graphics.c
+++ b/graphics.c
@@ -8,10 +8,13 @@ drawbg(Image *walls, Image *bg) {
}
Image *
-alloccircle(int fg, int bg) {
+alloccircle(int fg, int bg, uint radius) {
Image *m, *fill;
+ uint d;
- m = allocimage(display, Rect(0, 0, 2*RADIUS, 2*RADIUS), RGBA32, 0, bg);
+ d = 2*radius; /* diameter */
+ printf("alloccircle: d=%u\n", d);
+ m = allocimage(display, Rect(0, 0, d, d), RGBA32, 0, bg);
if (m == nil)
return nil;
@@ -21,15 +24,17 @@ alloccircle(int fg, int bg) {
return nil;
}
- fillellipse(m, Pt(RADIUS, RADIUS), RADIUS, RADIUS, fill, ZP);
+ fillellipse(m, Pt(radius, radius), radius, radius, fill, ZP);
freeimage(fill);
return m;
}
void
drawcircle(Image *m, Point pos) {
+ uint radius;
Rectangle r;
- r = Rpt(subpt(pos, Pt(RADIUS, RADIUS)), addpt(pos, Pt(RADIUS, RADIUS)));
+ radius = Dx(m->r)/2;
+ r = Rpt(subpt(pos, Pt(radius, radius)), addpt(pos, Pt(radius, radius)));
draw(screen, r, m, nil, ZP);
}