tinyswords/boids_game.c

136 lines
4.1 KiB
C

#include <stdlib.h>
#include <stdio.h>
#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->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 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,
.should_close = should_close,
};