#include #include #include "include/raylib.h" #include "include/raymath.h" #include "boids_game.h" #include "lib.h" // #define SCREEN_WIDTH 1300 // #define SCREEN_HEIGHT 1080 #define SCREEN_WIDTH 800 #define SCREEN_HEIGHT 600 #define TARGET_FPS 60 typedef struct Boid { Point position; Vector2 acceleration; Vector2 velocity; } Boid; typedef struct GameState { Boid *boids; PointOption target_pos; int num_boids; float max_speed; float max_force; } GameState; static GameState *init() { InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "Boids"); int monitor = GetCurrentMonitor(); int monitor_width = GetMonitorWidth(monitor); // int monitor_height = GetMonitorHeight(monitor); int win_pos_x = monitor_width - SCREEN_WIDTH - 7; int win_pos_y = 30; SetWindowPosition(win_pos_x, win_pos_y); SetTargetFPS(TARGET_FPS); GameState *state = malloc(sizeof(struct GameApi)); state->target_pos = (PointOption){ .tag = NONE }; state->num_boids = 16; state->max_speed = 5.0f; state->max_force = 0.05; Boid *boids = malloc(state->num_boids * sizeof(Boid)); state->boids = boids; for (int i = 0; i < state->num_boids; i++) { Boid *boid = &boids[i]; int rand_x = GetRandomValue(0, SCREEN_WIDTH); int rand_y = GetRandomValue(0, SCREEN_HEIGHT); boid->position = (Vector2){rand_x, rand_y}; int rand_vx = GetRandomValue(0, 100); int rand_vy = GetRandomValue(0, 100); boid->velocity = (Vector2){rand_vx * 0.01f - 0.5f, rand_vy * 0.01f - 0.5f}; // boid->velocity = Vector2Scale(boid->velocity, 10.0f); // int rand_ax = GetRandomValue(0, 100); // int rand_ay = GetRandomValue(0, 100); // boid->velocity = (Vector2){rand_ax * 0.01f - 0.5f, rand_ay * 0.01f - 0.5f}; boid->acceleration = (Vector2){0}; } printf("Initialized Game\n"); return state; } static void finalize(GameState *state) { free(state->boids); CloseWindow(); } static void reload(GameState *state) { (void)state; state->max_speed = 20.0f; state->max_force = 0.5; printf("Reloaded Game\n"); } static void unload(GameState *state) { (void)state; } // We need this so all the raylib state is in the right place static bool window_should_close() { return WindowShouldClose(); } static void step(GameState *state) { // Process Input if (IsMouseButtonPressed(0)) { Vector2 mouse_pos = GetMousePosition(); state->target_pos = (PointOption){.tag = SOME, .some.point = mouse_pos}; } // Update for (int i = 0; i < state->num_boids; i++) { Boid *boid = &state->boids[i]; if (state->target_pos.tag == SOME) { Vector2 desired = Vector2Subtract(state->target_pos.some.point, boid->position); desired = Vector2Normalize(desired); desired = Vector2Scale(desired, state->max_speed); Vector2 steer = Vector2Subtract(desired, boid->velocity); steer = Vector2ClampValue(steer, 0.0f, state->max_force); boid->acceleration = Vector2Add(boid->acceleration, steer); } boid->velocity = Vector2Add(boid->velocity, boid->acceleration); boid->velocity = Vector2ClampValue(boid->velocity, 0.0f, state->max_speed); boid->position = Vector2Add(boid->position, boid->velocity); } // Update BeginDrawing(); { ClearBackground(RAYWHITE); // You can draw a triangle but you'd need to rotate all 3 vectors, and I don't // want to get distracted with that // DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, GREEN); // DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, GREEN); for (int i = 0; i < state->num_boids; i++) { Boid *boid = &state->boids[i]; DrawCircle(boid->position.x, boid->position.y, 27, BLACK); DrawCircle(boid->position.x, boid->position.y, 20, GREEN); } DrawFPS(SCREEN_WIDTH - 80, 10); } EndDrawing(); } const struct GameApi GAME_API = { .init = init, .reload = reload, .step = step, .unload = unload, .finalize = finalize, .window_should_close = window_should_close, };