From 0805bd88071528bbc4799353c4b05cd68f84b50b Mon Sep 17 00:00:00 2001 From: Ivan Mahonin Date: Jul 21 2021 10:45:46 +0000 Subject: rubber --- diff --git a/rubber.c b/rubber.c new file mode 100644 index 0000000..2835752 --- /dev/null +++ b/rubber.c @@ -0,0 +1,165 @@ + +#include +#include +#include + + + +#define MAX_BALLS 1000 +#define MAX_LINKS 10000 +#define BALL_RADIUS 1.0 +#define BALL_FADE 0.8 +#define LINK_K 0.05 +#define GRID_SIZE 5 + + + +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() { + double dist = 3*BALL_RADIUS; + for(int i = 0; i < GRID_SIZE; ++i) { + for(int j = 0; j < GRID_SIZE; ++j) { + Ball *ball = &balls[ballsCount++]; + ball->x = (i - 0.5*(GRID_SIZE - 1))*dist; + ball->y = (j - 0.5*(GRID_SIZE - 1))*dist; + if (i > 0) { + Link *link = &links[linksCount++]; + link->a = ball - GRID_SIZE; + 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(COLOR_BLACK); + 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(COLOR_BLUE); + 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(); + return 0; +}