summaryrefslogtreecommitdiff
path: root/simulations/boids.c
diff options
context:
space:
mode:
Diffstat (limited to 'simulations/boids.c')
-rw-r--r--simulations/boids.c237
1 files changed, 237 insertions, 0 deletions
diff --git a/simulations/boids.c b/simulations/boids.c
new file mode 100644
index 0000000..84afc21
--- /dev/null
+++ b/simulations/boids.c
@@ -0,0 +1,237 @@
+#ifdef _WIN32 // грубый способ определения; на деле разница не в ОС, а в компиляторe
+ #include <SDL.h>
+ #include <SDL_image.h>
+ #include <SDL_timer.h>
+#else
+ #include <SDL2/SDL.h>
+ #include <SDL2/SDL_image.h>
+ #include <SDL2/SDL_timer.h>
+#endif
+#include <time.h>
+#include <math.h>
+
+#define SCALE 1
+#define BOIDNUM 30
+#define SPEED 1
+#define CRANGE 30
+#define WIDTH 1280
+#define HEIGHT 640
+#define PI 3.1415926535
+
+struct boid { double x, y, dx, dy, th; };
+typedef struct vec { float x, y; } vector;
+struct boid B[BOIDNUM];
+char color[3] = {0, 255, 0};
+
+int init()
+{
+ srand(time(NULL));
+
+ for(int i = 0; i<BOIDNUM; i++) {
+ B[i].x = WIDTH/2 + rand() % 128 - 64;
+ B[i].y = HEIGHT/2 + rand() % 128 - 64;
+ B[i].th = rand() / (float)RAND_MAX * (PI/3) - PI/6;
+ B[i].dx = SPEED * cos(B[i].th);
+ B[i].dy = SPEED * sin(B[i].th);
+ // printf("%f",B[i].th);
+ }
+
+ return 0;
+}
+
+int processEvents(SDL_Window *window)
+{
+ SDL_Event event;
+
+ while(SDL_PollEvent(&event))
+ {
+ switch(event.type)
+ {
+ case SDL_WINDOWEVENT_CLOSE:
+ if(window)
+ {
+ SDL_DestroyWindow(window);
+ window = NULL;
+ return 1;
+ }
+ break;
+
+ case SDL_KEYDOWN:
+ switch(event.key.keysym.sym) {
+ case SDLK_ESCAPE:
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+void render(SDL_Renderer *renderer)
+{
+ SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); // фон
+ SDL_RenderClear(renderer);
+
+ SDL_Vertex arrow[BOIDNUM][3];
+ for(int i = 0; i<BOIDNUM; i++) {
+ arrow[i][0].position.x = (B[i].x+7 *cos(B[i].th-PI/2))/SCALE;
+ arrow[i][0].position.y = (B[i].y+7 *sin(B[i].th-PI/2))/SCALE;
+ arrow[i][1].position.x = (B[i].x+7 *cos(B[i].th+PI/2))/SCALE;
+ arrow[i][1].position.y = (B[i].y+7 *sin(B[i].th+PI/2))/SCALE;
+ arrow[i][2].position.x = (B[i].x+20*cos(B[i].th)) /SCALE;
+ arrow[i][2].position.y = (B[i].y+20*sin(B[i].th)) /SCALE;
+
+ for(int j = 0; j<3; j++) {
+ arrow[i][j].color.r = color[0];
+ arrow[i][j].color.g = color[1]+j*25;
+ arrow[i][j].color.b = color[2];
+ arrow[i][j].color.a = 255;
+ }
+ SDL_RenderGeometry(renderer, NULL, arrow[i], 3, NULL, 0);
+ }
+
+ SDL_RenderPresent(renderer);
+}
+
+float geomdist(int i, int j)
+{
+ return sqrt(pow( B[i].x - B[j].x, 2 ) + pow( B[i].y - B[j].y, 2 ));
+}
+
+vector cohesion(int n, int factor)
+{
+ vector sum = {0, 0};
+ for(int b = 0; b < BOIDNUM; b++) {
+ if(geomdist(n, b) > CRANGE) {continue;}
+ if(b == n) {continue;}
+ sum.x += B[b].x;
+ sum.y += B[b].y;
+ }
+
+ sum.x /= BOIDNUM - 1;
+ sum.y /= BOIDNUM - 1;
+
+ sum.x -= B[n].x;
+ sum.y -= B[n].y;
+ sum.x /= factor;
+ sum.y /= factor;
+
+ return sum;
+}
+
+vector separation(int n, float dist, int factor)
+{
+ vector c = {0, 0};
+ c.x = 0;
+ c.y = 0;
+
+ for(int b = 0; b < BOIDNUM; b++) {
+ if(geomdist(n, b) > CRANGE) {continue;}
+ if(b == n) {continue;}
+ if(geomdist(n, b) < dist) {
+ c.x -= B[b].x - B[n].x;
+ c.y -= B[b].y - B[n].y;
+ }
+ }
+
+ c.x /= factor;
+ c.y /= factor;
+
+ return c;
+}
+
+vector alignment(int n, int factor)
+{
+ vector pv = {0, 0};
+
+ for(int b = 0; b < BOIDNUM; b++) {
+ if(geomdist(n, b) > CRANGE) {continue;}
+ if(b == n) {continue;}
+ pv.x += B[b].dx;
+ pv.y += B[b].dy;
+ }
+
+ pv.x /= BOIDNUM - 1;
+ pv.y /= BOIDNUM - 1;
+
+ pv.x -= B[n].dx;
+ pv.y -= B[n].dy;
+ pv.x /= factor;
+ pv.y /= factor;
+
+ return pv;
+}
+
+int updatePos(SDL_Renderer *renderer) {
+ vector v[3];
+ for(int i = 0; i<BOIDNUM; i++) {
+ B[i].x += B[i].dx;
+ B[i].y += B[i].dy;
+ // B[i].th += PI/72;
+ if(B[i].x > WIDTH)
+ B[i].x -= WIDTH;
+ // B[i].dx = 0;
+ if(B[i].y > HEIGHT)
+ B[i].y -= HEIGHT;
+ // B[i].dy = 0;
+ if(B[i].x < 0)
+ B[i].x += WIDTH;
+ // B[i].dx = 0;
+ if(B[i].y < 0)
+ B[i].y += HEIGHT;
+ // B[i].dy = 0;
+
+ v[0] = cohesion(i, 40);
+ v[1] = separation(i, 20, 200);
+ // v[0].x = 0;
+ // v[0].y = 0;
+ v[2] = alignment(i, 80);
+ // v[2].x = 0;
+ // v[2].y = 0;
+
+ for(int j = 0; j<3; j++) {
+ if(i == 0) {
+ SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
+ SDL_RenderDrawLine(renderer, B[i].x, B[i].y, B[i].x-v[j].x, B[i].y - v[j].y);
+ SDL_RenderPresent(renderer);
+ printf("|vx = %f, vy = %f", v[j].x, v[j].y);
+ }
+
+ B[i].dx += v[j].x / 1000;
+ B[i].dy += v[j].y / 1000;
+ }
+ // if (B[i].dx > sqrt(50)) B[i].dx = sqrt(50);
+ // if (B[i].dy > sqrt(50)) B[i].dy = sqrt(50);
+ B[i].th = acos(B[i].dx / sqrt(B[i].dx * B[i].dx + B[i].dy * B[i].dy) + 0.0001);
+ // if(i == 0) {
+ // printf("%f|", B[i].th);
+ // }
+ }
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ SDL_Window *window = NULL;
+ SDL_Renderer *renderer = NULL;
+
+ init();
+ SDL_Init(SDL_INIT_VIDEO);
+
+ window = SDL_CreateWindow("Boids",
+ SDL_WINDOWPOS_CENTERED,
+ SDL_WINDOWPOS_CENTERED,
+ WIDTH,
+ HEIGHT,
+ 0);
+ renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
+
+ while(1) {
+ if(processEvents(window) == 1)
+ break;
+ render(renderer);
+ updatePos(renderer);
+ SDL_Delay(10);
+ }
+
+ return 0;
+} \ No newline at end of file