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