|
|
0805bd |
|
|
|
0805bd |
#include <math.h></math.h>
|
|
|
0805bd |
#include <stdlib.h></stdlib.h>
|
|
|
0805bd |
#include <helianthus.h></helianthus.h>
|
|
|
0805bd |
|
|
|
0805bd |
|
|
|
0805bd |
|
|
|
0805bd |
#define MAX_BALLS 1000
|
|
|
0805bd |
#define MAX_LINKS 10000
|
|
|
0805bd |
#define BALL_RADIUS 1.0
|
|
|
0805bd |
#define BALL_FADE 0.8
|
|
|
0805bd |
#define LINK_K 0.05
|
|
|
0805bd |
#define GRID_SIZE 5
|
|
|
0805bd |
|
|
|
0805bd |
|
|
|
0805bd |
|
|
|
0805bd |
typedef struct {
|
|
|
0805bd |
double x, y;
|
|
|
0805bd |
double vx, vy;
|
|
|
0805bd |
} Ball;
|
|
|
0805bd |
|
|
|
0805bd |
|
|
|
0805bd |
typedef struct {
|
|
|
0805bd |
double dx, dy;
|
|
|
0805bd |
Ball *a, *b;
|
|
|
0805bd |
} Link;
|
|
|
0805bd |
|
|
|
0805bd |
|
|
|
0805bd |
|
|
|
0805bd |
Ball balls[MAX_BALLS];
|
|
|
0805bd |
Link links[MAX_LINKS];
|
|
|
0805bd |
int ballsCount = 0;
|
|
|
0805bd |
int linksCount = 0;
|
|
|
0805bd |
|
|
|
0805bd |
double remainDt;
|
|
|
0805bd |
|
|
|
0805bd |
Ball *mball;
|
|
|
0805bd |
double mdx, mdy;
|
|
|
0805bd |
double mx, my;
|
|
|
0805bd |
|
|
|
0805bd |
|
|
|
0805bd |
|
|
|
0805bd |
void ballUpdate(Ball *ball, double dt) {
|
|
|
0805bd |
double fade = pow(BALL_FADE, dt);
|
|
|
0805bd |
ball->x += ball->vx*dt;
|
|
|
0805bd |
ball->y += ball->vy*dt;
|
|
|
0805bd |
ball->vx *= fade;
|
|
|
0805bd |
ball->vy *= fade;
|
|
|
0805bd |
}
|
|
|
0805bd |
|
|
|
0805bd |
|
|
|
0805bd |
void linkUpdate(Link *link, double dt) {
|
|
|
0805bd |
double dx = link->b->x - link->a->x;
|
|
|
0805bd |
double dy = link->b->y - link->a->y;
|
|
|
0805bd |
|
|
|
0805bd |
double dvx = (dx - link->dx)*0.5*LINK_K;
|
|
|
0805bd |
double dvy = (dy - link->dy)*0.5*LINK_K;
|
|
|
0805bd |
|
|
|
0805bd |
link->a->vx += dvx; link->b->vx -= dvx;
|
|
|
0805bd |
link->a->vy += dvy; link->b->vy -= dvy;
|
|
|
0805bd |
}
|
|
|
0805bd |
|
|
|
0805bd |
|
|
|
0805bd |
void update(double dt) {
|
|
|
0805bd |
remainDt += dt;
|
|
|
0805bd |
while(remainDt > 0.001) {
|
|
|
0805bd |
remainDt -= 0.001;
|
|
|
0805bd |
for(int i = 0; i < linksCount; ++i)
|
|
|
0805bd |
linkUpdate(&links[i], dt);
|
|
|
0805bd |
for(int i = 0; i < ballsCount; ++i)
|
|
|
0805bd |
ballUpdate(&balls[i], dt);
|
|
|
0805bd |
}
|
|
|
0805bd |
}
|
|
|
0805bd |
|
|
|
0805bd |
|
|
|
0805bd |
void init() {
|
|
|
0805bd |
double dist = 3*BALL_RADIUS;
|
|
|
0805bd |
for(int i = 0; i < GRID_SIZE; ++i) {
|
|
|
0805bd |
for(int j = 0; j < GRID_SIZE; ++j) {
|
|
|
0805bd |
Ball *ball = &balls[ballsCount++];
|
|
|
0805bd |
ball->x = (i - 0.5*(GRID_SIZE - 1))*dist;
|
|
|
0805bd |
ball->y = (j - 0.5*(GRID_SIZE - 1))*dist;
|
|
|
0805bd |
if (i > 0) {
|
|
|
0805bd |
Link *link = &links[linksCount++];
|
|
|
0805bd |
link->a = ball - GRID_SIZE;
|
|
|
0805bd |
link->b = ball;
|
|
|
0805bd |
link->dx = dist;
|
|
|
0805bd |
}
|
|
|
0805bd |
if (j > 0) {
|
|
|
0805bd |
Link *link = &links[linksCount++];
|
|
|
0805bd |
link->a = ball - 1;
|
|
|
0805bd |
link->b = ball;
|
|
|
0805bd |
link->dy = dist;
|
|
|
0805bd |
}
|
|
|
0805bd |
}
|
|
|
0805bd |
}
|
|
|
0805bd |
}
|
|
|
0805bd |
|
|
|
0805bd |
|
|
|
0805bd |
void draw() {
|
|
|
0805bd |
double dt = windowGetFrameTime();
|
|
|
0805bd |
double w = windowGetWidth();
|
|
|
0805bd |
double h = windowGetHeight();
|
|
|
0805bd |
|
|
|
0805bd |
saveState();
|
|
|
0805bd |
translate(w/2, h/2);
|
|
|
0805bd |
zoom(20);
|
|
|
0805bd |
|
|
|
0805bd |
mx = mouseTransformedX();
|
|
|
0805bd |
my = mouseTransformedY();
|
|
|
0805bd |
if (mouseDown("left")) {
|
|
|
0805bd |
if (!mball) {
|
|
|
0805bd |
for(int i = ballsCount-1; i >= 0; --i) {
|
|
|
0805bd |
Ball *ball = &balls[i];
|
|
|
0805bd |
double dx = mx - ball->x;
|
|
|
0805bd |
double dy = my - ball->y;
|
|
|
0805bd |
if (dx*dx + dy*dy <= BALL_RADIUS*BALL_RADIUS) {
|
|
|
0805bd |
mball = ball;
|
|
|
0805bd |
mdx = dx;
|
|
|
0805bd |
mdy = dy;
|
|
|
0805bd |
break;
|
|
|
0805bd |
}
|
|
|
0805bd |
}
|
|
|
0805bd |
}
|
|
|
0805bd |
} else {
|
|
|
0805bd |
mball = NULL;
|
|
|
0805bd |
}
|
|
|
0805bd |
|
|
|
0805bd |
|
|
|
0805bd |
update(dt);
|
|
|
0805bd |
|
|
|
0805bd |
if (mball) {
|
|
|
0805bd |
mball->x = mx - mdx;
|
|
|
0805bd |
mball->y = my - mdy;
|
|
|
0805bd |
mball->vx = 0;
|
|
|
0805bd |
mball->vy = 0;
|
|
|
0805bd |
}
|
|
|
0805bd |
|
|
|
0805bd |
stroke(COLOR_BLACK);
|
|
|
0805bd |
strokeWidth(BALL_RADIUS*0.1);
|
|
|
0805bd |
noFill();
|
|
|
0805bd |
for(int i = 0; i < linksCount; ++i) {
|
|
|
0805bd |
Link *link = &links[i];
|
|
|
0805bd |
line(link->a->x, link->a->y, link->b->x, link->b->y);
|
|
|
0805bd |
}
|
|
|
0805bd |
|
|
|
0805bd |
noStroke();
|
|
|
0805bd |
fill(COLOR_BLUE);
|
|
|
0805bd |
for(int i = 0; i < ballsCount; ++i) {
|
|
|
0805bd |
Ball *ball = &balls[i];
|
|
|
0805bd |
circle(ball->x, ball->y, BALL_RADIUS);
|
|
|
0805bd |
}
|
|
|
0805bd |
|
|
|
0805bd |
restoreState();
|
|
|
0805bd |
}
|
|
|
0805bd |
|
|
|
0805bd |
|
|
|
0805bd |
int main() {
|
|
|
31a989 |
windowSetTitle("Rubber");
|
|
|
0805bd |
windowSetResizable(TRUE);
|
|
|
0805bd |
windowSetVariableFrameRate();
|
|
|
0805bd |
windowSetInit(&init);
|
|
|
0805bd |
windowSetDraw(&draw);
|
|
|
0805bd |
windowRun();
|
|
|
0805bd |
return 0;
|
|
|
0805bd |
}
|