diff --git a/src/boid-playground.hpp b/src/boid-playground.hpp new file mode 100644 index 0000000..0ffda13 --- /dev/null +++ b/src/boid-playground.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include +#include +#include + +#define ARRAY_LEN(arr) (sizeof(arr)/sizeof(arr[0])) +#define LogTrace(...) TraceLog(LOG_TRACE, __VA_ARGS__) +#define ASSERT(...) assert(__VA_ARGS__) + +struct Boid { + Vector2 pos; + Vector2 dir; +}; + +struct Obstacle { + Vector2 center; + std::vector points; +}; + +struct RayHitResult { + float hit = -1; + + // TODO: `line1` and `line2` are not used, maybe remove them? + Vector2 line1; + Vector2 line2; +}; + +struct World { + std::vector boids; + std::vector obstacles; + + float boid_view_radius = 100; + float boid_view_angle = PI*2; + float boid_speed = 80; + float boid_turn_speed = PI*2; + + float avoidance_distance = 75; + float avoidance_ray_angle = PI/1.5; + int avoidance_ray_count = 4; + + Vector2 size; +}; + +struct Visuals { + float boid_edge_size = 20; +}; diff --git a/src/main.cpp b/src/main.cpp index 2d7071d..8abf649 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,51 +2,10 @@ #include "raymath.h" #include "rlgl.h" #include -#include #include -#include -#define ARRAY_LEN(arr) (sizeof(arr)/sizeof(arr[0])) -#define LogTrace(...) TraceLog(LOG_TRACE, __VA_ARGS__) -#define ASSERT(...) assert(__VA_ARGS__) - -struct Boid { - Vector2 pos; - Vector2 dir; -}; - -struct Obstacle { - Vector2 center; - std::vector points; -}; - -struct RayHitResult { - float hit = -1; - - // TODO: `line1` and `line2` are not used, maybe remove them? - Vector2 line1; - Vector2 line2; -}; - -struct World { - std::vector boids; - std::vector obstacles; - - float boid_view_radius = 100; - float boid_view_angle = PI*2; - float boid_speed = 80; - float boid_turn_speed = PI*2; - - float avoidance_distance = 75; - float avoidance_ray_angle = PI/1.5; - int avoidance_ray_count = 4; - - Vector2 size; -}; - -struct Visuals { - float boid_edge_size = 20; -}; +#include "boid-playground.hpp" +#include "raycast.cpp" static void boid_rand_init(Boid *boid, int min_x, int max_x, int min_y, int max_y) { @@ -92,82 +51,6 @@ static void draw_obstacle(Obstacle *obstacle, Color color) rlEnd(); } -static float get_intersect_point(Vector2 ray_origin, Vector2 ray_dir, Vector2 line1, Vector2 line2) { - Vector2 line_dir = Vector2Subtract(line2, line1); - float D = ray_dir.x * line_dir.y - ray_dir.y * line_dir.x; - float u = ((line1.x - ray_origin.x) * ray_dir.y - (line1.y - ray_origin.y) * ray_dir.x) / D; - float t = ((line1.x - ray_origin.x) * line_dir.y - (line1.y - ray_origin.y) * line_dir.x) / D; - if (0 <= u && u <= 1 && t >= 0) { - return t; - } else { - return -1; - } -} - -static void set_nearest_hit(RayHitResult *nearest_hit, float hit, Vector2 line1, Vector2 line2) { - bool got_hit = hit >= 0; - bool is_gotten_hit_better = (nearest_hit->hit < 0 || nearest_hit->hit > hit); - if (got_hit && is_gotten_hit_better) { - nearest_hit->hit = hit; - nearest_hit->line1 = line1; - nearest_hit->line2 = line2; - } -} - -static void get_intersect_with_polygon(RayHitResult *result, Vector2 ray_origin, Vector2 ray_dir, Vector2 *points, int point_count) { - if (point_count < 2) return; - - for (int i = 0; i < point_count-1; i++) { - Vector2 p1 = points[i]; - Vector2 p2 = points[i+1]; - float hit = get_intersect_point(ray_origin, ray_dir, p1, p2); - set_nearest_hit(result, hit, p1, p2); - } - - if (point_count > 2) { - Vector2 p1 = points[0]; - Vector2 p2 = points[point_count-1]; - float hit = get_intersect_point(ray_origin, ray_dir, p1, p2); - set_nearest_hit(result, hit, p1, p2); - } -} - -static void get_intersect_with_obstacles(RayHitResult *result, Vector2 ray_origin, Vector2 ray_dir, std::vector *obstacles) { - for (int i = 0; i < (*obstacles).size(); i++) { - Obstacle *obstacle = &(*obstacles)[i]; - get_intersect_with_polygon(result, ray_origin, ray_dir, obstacle->points.data(), obstacle->points.size()); - } -} - -static void get_intersect_with_world(RayHitResult *result, Vector2 ray_origin, Vector2 ray_dir, World *world) { - get_intersect_with_obstacles(result, ray_origin, ray_dir, &world->obstacles); - - if (result->hit == -1) { - Vector2 lines[] = { - { 0 , 0 }, - { world->size.x, 0 }, - { world->size.x, world->size.y }, - { 0 , world->size.y } - }; - - get_intersect_with_polygon(result, ray_origin, ray_dir, lines, 4); - } -} - -static void fill_avoidance_ray_angles(float *rays, int ray_count, float ray_angle) { - ASSERT(ray_count >= 1 && "Ray count must be at least 1"); - ASSERT(((ray_count - 1) % 2 == 0) && "Ray count must be a multiple of 2n+1"); - - rays[0] = 0; - - int side_ray_count = ((ray_count-1)/2); - float ray_angle_step = ray_angle / side_ray_count; - for (int i = 0; i < side_ray_count; i++) { - rays[2*i+0 + 1] = ray_angle_step * (i+1); - rays[2*i+1 + 1] = -ray_angle_step * (i+1); - } -} - static void draw_debug_boid_obstacle_avoidance(Visuals *visuals, World *world, Boid *boid) { Vector2 pos = boid->pos; @@ -271,8 +154,7 @@ static int get_boids_in_view_cone(Boid **boids_in_view, Boid *boid, float view_r Vector2 dir_to_boid = Vector2Normalize(Vector2Subtract(boids[i].pos, boid->pos)); float dot = Vector2DotProduct(boid->dir, dir_to_boid); - // TODO: if (dot >= dot_threshold && Vector2Distance(boids[i].pos, boid->pos) <= view_radius) { - if (Vector2Distance(boids[i].pos, boid->pos) <= view_radius) { + if (dot >= dot_threshold && Vector2Distance(boids[i].pos, boid->pos) <= view_radius) { boids_in_view[count] = &boids[i]; count++; } @@ -311,14 +193,12 @@ int main() { // world.boids.push_back({ .pos = { 200, 180 }, .dir = { 0, -1 }}); // Main game loop - while (!window.ShouldClose()) - { + while (!window.ShouldClose()) { // TODO: Show this on screen // LogTrace("%d", count_out_of_bounds_boids(&world)); float dt = GetFrameTime(); for (int i = 0; i < world.boids.size(); i++) { - LogTrace("i:%d", i); Boid *boid = &world.boids[i]; Vector2 step = Vector2Multiply(boid->dir, { world.boid_speed * dt, world.boid_speed * dt }); diff --git a/src/raycast.cpp b/src/raycast.cpp new file mode 100644 index 0000000..1b10675 --- /dev/null +++ b/src/raycast.cpp @@ -0,0 +1,77 @@ +#include "boid-playground.hpp" + +static float get_intersect_point(Vector2 ray_origin, Vector2 ray_dir, Vector2 line1, Vector2 line2) { + Vector2 line_dir = Vector2Subtract(line2, line1); + float D = ray_dir.x * line_dir.y - ray_dir.y * line_dir.x; + float u = ((line1.x - ray_origin.x) * ray_dir.y - (line1.y - ray_origin.y) * ray_dir.x) / D; + float t = ((line1.x - ray_origin.x) * line_dir.y - (line1.y - ray_origin.y) * line_dir.x) / D; + if (0 <= u && u <= 1 && t >= 0) { + return t; + } else { + return -1; + } +} + +static void set_nearest_hit(RayHitResult *nearest_hit, float hit, Vector2 line1, Vector2 line2) { + bool got_hit = hit >= 0; + bool is_gotten_hit_better = (nearest_hit->hit < 0 || nearest_hit->hit > hit); + if (got_hit && is_gotten_hit_better) { + nearest_hit->hit = hit; + nearest_hit->line1 = line1; + nearest_hit->line2 = line2; + } +} + +static void get_intersect_with_polygon(RayHitResult *result, Vector2 ray_origin, Vector2 ray_dir, Vector2 *points, int point_count) { + if (point_count < 2) return; + + for (int i = 0; i < point_count-1; i++) { + Vector2 p1 = points[i]; + Vector2 p2 = points[i+1]; + float hit = get_intersect_point(ray_origin, ray_dir, p1, p2); + set_nearest_hit(result, hit, p1, p2); + } + + if (point_count > 2) { + Vector2 p1 = points[0]; + Vector2 p2 = points[point_count-1]; + float hit = get_intersect_point(ray_origin, ray_dir, p1, p2); + set_nearest_hit(result, hit, p1, p2); + } +} + +static void get_intersect_with_obstacles(RayHitResult *result, Vector2 ray_origin, Vector2 ray_dir, std::vector *obstacles) { + for (int i = 0; i < (*obstacles).size(); i++) { + Obstacle *obstacle = &(*obstacles)[i]; + get_intersect_with_polygon(result, ray_origin, ray_dir, obstacle->points.data(), obstacle->points.size()); + } +} + +static void get_intersect_with_world(RayHitResult *result, Vector2 ray_origin, Vector2 ray_dir, World *world) { + get_intersect_with_obstacles(result, ray_origin, ray_dir, &world->obstacles); + + if (result->hit == -1) { + Vector2 lines[] = { + { 0 , 0 }, + { world->size.x, 0 }, + { world->size.x, world->size.y }, + { 0 , world->size.y } + }; + + get_intersect_with_polygon(result, ray_origin, ray_dir, lines, 4); + } +} + +static void fill_avoidance_ray_angles(float *rays, int ray_count, float ray_angle) { + ASSERT(ray_count >= 1 && "Ray count must be at least 1"); + ASSERT(((ray_count - 1) % 2 == 0) && "Ray count must be a multiple of 2n+1"); + + rays[0] = 0; + + int side_ray_count = ((ray_count-1)/2); + float ray_angle_step = ray_angle / side_ray_count; + for (int i = 0; i < side_ray_count; i++) { + rays[2*i+0 + 1] = ray_angle_step * (i+1); + rays[2*i+1 + 1] = -ray_angle_step * (i+1); + } +}