generated from rpuzonas/raylib-cpp-template
add gui for controlling parameters
This commit is contained in:
parent
1478084ab6
commit
892247d44b
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -7,3 +7,6 @@
|
|||||||
[submodule "depends/emsdk"]
|
[submodule "depends/emsdk"]
|
||||||
path = depends/emsdk
|
path = depends/emsdk
|
||||||
url = git@github.com:emscripten-core/emsdk.git
|
url = git@github.com:emscripten-core/emsdk.git
|
||||||
|
[submodule "depends/raygui"]
|
||||||
|
path = depends/raygui
|
||||||
|
url = git@github.com:raysan5/raygui.git
|
||||||
|
3
Makefile
3
Makefile
@ -8,7 +8,7 @@ EXECUTABLE := boids-playground
|
|||||||
WEB_SHELL := src/shell.html
|
WEB_SHELL := src/shell.html
|
||||||
SUBMODULES_PATH := depends
|
SUBMODULES_PATH := depends
|
||||||
|
|
||||||
COMPILER_FLAGS := -std=c++17
|
COMPILER_FLAGS := -std=c++17 -Wno-enum-compare
|
||||||
LINKER_FLAGS := -lraylib
|
LINKER_FLAGS := -lraylib
|
||||||
|
|
||||||
# SOURCES := $(wildcard src/*.cpp)
|
# SOURCES := $(wildcard src/*.cpp)
|
||||||
@ -20,6 +20,7 @@ EXT :=
|
|||||||
EMSDK_PATH := $(SUBMODULES_PATH)/emsdk
|
EMSDK_PATH := $(SUBMODULES_PATH)/emsdk
|
||||||
RAYLIB_PLATFORM := PLATFORM_DESKTOP
|
RAYLIB_PLATFORM := PLATFORM_DESKTOP
|
||||||
|
|
||||||
|
COMPILER_FLAGS += -I$(SUBMODULES_PATH)/raygui/src/
|
||||||
COMPILER_FLAGS += -I$(SUBMODULES_PATH)/raylib/src
|
COMPILER_FLAGS += -I$(SUBMODULES_PATH)/raylib/src
|
||||||
COMPILER_FLAGS += -I$(SUBMODULES_PATH)/raylib-cpp/include
|
COMPILER_FLAGS += -I$(SUBMODULES_PATH)/raylib-cpp/include
|
||||||
|
|
||||||
|
@ -1,2 +1,3 @@
|
|||||||
-Idepends/raylib-cpp/include/
|
-Idepends/raylib-cpp/include/
|
||||||
-Idepends/raylib/src/
|
-Idepends/raylib/src/
|
||||||
|
-Idepends/raygui/src/
|
||||||
|
1
depends/raygui
Submodule
1
depends/raygui
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 848569ce3399a8f6fe00091f968808f3ab042c4b
|
@ -46,16 +46,34 @@ struct World {
|
|||||||
|
|
||||||
float collision_avoidance_distance = 75;
|
float collision_avoidance_distance = 75;
|
||||||
float collision_avoidance_ray_angle = PI/1.5;
|
float collision_avoidance_ray_angle = PI/1.5;
|
||||||
int collision_avoidance_ray_count = 4;
|
int collision_avoidance_ray_count = 3;
|
||||||
|
|
||||||
// TODO: Function `get_boids_in_view_cone` doesn't work as expected with looping walls
|
// TODO: Function `get_boids_in_view_cone` doesn't work as expected with looping walls
|
||||||
bool looping_walls = false;
|
bool looping_walls = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Visuals {
|
struct Visuals {
|
||||||
float boid_edge_size = 15;
|
float boid_edge_size = 40;
|
||||||
|
|
||||||
|
Color boid_color = BLACK;
|
||||||
|
Color bg_color = RAYWHITE;
|
||||||
|
|
||||||
|
bool show_control_panel = true;
|
||||||
|
|
||||||
bool draw_boid_direction = false;
|
bool draw_boid_direction = false;
|
||||||
bool draw_view_cone = false;
|
bool draw_view_cone = false;
|
||||||
bool draw_collision_avoidance_rays = false;
|
bool draw_collision_avoidance_rays = false;
|
||||||
|
bool draw_separation_radius = false;
|
||||||
|
bool draw_pulling_forces = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UI {
|
||||||
|
bool min_speed_edit = false;
|
||||||
|
bool max_speed_edit = false;
|
||||||
|
bool steer_speed_edit = false;
|
||||||
|
|
||||||
|
bool alignment_strength_edit = false;
|
||||||
|
bool cohesion_strength_edit = false;
|
||||||
|
bool separation_strength_edit = false;
|
||||||
|
bool collision_avoidance_strength_edit = false;
|
||||||
};
|
};
|
||||||
|
150
src/main.cpp
150
src/main.cpp
@ -8,6 +8,9 @@
|
|||||||
#include <emscripten/emscripten.h>
|
#include <emscripten/emscripten.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define RAYGUI_IMPLEMENTATION
|
||||||
|
#include "raygui.h"
|
||||||
|
|
||||||
#include "boid-playground.hpp"
|
#include "boid-playground.hpp"
|
||||||
#include "raycast.cpp"
|
#include "raycast.cpp"
|
||||||
|
|
||||||
@ -16,6 +19,7 @@
|
|||||||
|
|
||||||
static World g_world;
|
static World g_world;
|
||||||
static Visuals g_visuals;
|
static Visuals g_visuals;
|
||||||
|
static UI g_ui;
|
||||||
|
|
||||||
static float vector2_atan2(Vector2 a) {
|
static float vector2_atan2(Vector2 a) {
|
||||||
return std::atan2(a.y, a.x);
|
return std::atan2(a.y, a.x);
|
||||||
@ -77,7 +81,7 @@ static void draw_obstacle(Obstacle *obstacle, Color color) {
|
|||||||
rlEnd();
|
rlEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void draw_debug_boid_obstacle_avoidance(Visuals *visuals, World *world, Boid *boid) {
|
static void draw_obstacle_avoidance_rays(Visuals *visuals, World *world, Boid *boid) {
|
||||||
Vector2 pos = boid->pos;
|
Vector2 pos = boid->pos;
|
||||||
|
|
||||||
int ray_count = world->collision_avoidance_ray_count * 2 + 1;
|
int ray_count = world->collision_avoidance_ray_count * 2 + 1;
|
||||||
@ -214,26 +218,20 @@ static void world_update(World *world, float dt) {
|
|||||||
flock_center = vector2_div_value(flock_center, local_boids_count);
|
flock_center = vector2_div_value(flock_center, local_boids_count);
|
||||||
|
|
||||||
Vector2 alignment_force = Vector2Normalize(flock_heading);
|
Vector2 alignment_force = Vector2Normalize(flock_heading);
|
||||||
alignment_force = vector2_mul_value(alignment_force, world->max_speed);
|
acc = Vector2Add(acc, vector2_mul_value(alignment_force, world->alignment_strength));
|
||||||
alignment_force = vector2_mul_value(alignment_force, world->alignment_strength);
|
|
||||||
acc = Vector2Add(acc, alignment_force);
|
|
||||||
|
|
||||||
Vector2 cohesion_force = Vector2Normalize(Vector2Subtract(flock_center, boid->pos));
|
Vector2 cohesion_force = Vector2Normalize(Vector2Subtract(flock_center, boid->pos));
|
||||||
cohesion_force = vector2_mul_value(cohesion_force, world->max_speed);
|
acc = Vector2Add(acc, vector2_mul_value(cohesion_force, world->cohesion_strength));
|
||||||
cohesion_force = vector2_mul_value(cohesion_force, world->cohesion_strength);
|
|
||||||
acc = Vector2Add(acc, cohesion_force);
|
|
||||||
|
|
||||||
separation_force = Vector2Normalize(separation_force);
|
separation_force = Vector2Normalize(separation_force);
|
||||||
separation_force = vector2_mul_value(separation_force, world->max_speed);
|
acc = Vector2Add(acc, vector2_mul_value(separation_force, world->separation_strength));
|
||||||
separation_force = vector2_mul_value(separation_force, world->separation_strength);
|
|
||||||
acc = Vector2Add(acc, separation_force);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply obstacle avoidance to accelaration
|
// Apply obstacle avoidance to accelaration
|
||||||
Vector2 collision_avoidance = get_collision_avoidance_dir(world, boid);
|
Vector2 collision_avoidance = get_collision_avoidance_dir(world, boid);
|
||||||
collision_avoidance = vector2_mul_value(collision_avoidance, world->max_speed);
|
acc = Vector2Add(acc, vector2_mul_value(collision_avoidance, world->collision_avoidance_strength));
|
||||||
collision_avoidance = vector2_mul_value(collision_avoidance, world->collision_avoidance_strength);
|
|
||||||
acc = Vector2Add(acc, collision_avoidance);
|
acc = vector2_mul_value(acc, world->max_speed);
|
||||||
|
|
||||||
// Clamp accelaration
|
// Clamp accelaration
|
||||||
Vector2 clamped_acc = acc;
|
Vector2 clamped_acc = acc;
|
||||||
@ -300,7 +298,11 @@ static void world_draw(World *world, Visuals *visuals) {
|
|||||||
Boid *boid = &world->boids[i];
|
Boid *boid = &world->boids[i];
|
||||||
|
|
||||||
if (visuals->draw_collision_avoidance_rays) {
|
if (visuals->draw_collision_avoidance_rays) {
|
||||||
draw_debug_boid_obstacle_avoidance(visuals, world, boid);
|
draw_obstacle_avoidance_rays(visuals, world, boid);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (visuals->draw_separation_radius) {
|
||||||
|
DrawCircleLines(boid->pos.x, boid->pos.y, world->separation_radius, MAGENTA);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2 triangle[] = {
|
Vector2 triangle[] = {
|
||||||
@ -314,20 +316,112 @@ static void world_draw(World *world, Visuals *visuals) {
|
|||||||
triangle[i] = Vector2Add(boid->pos, Vector2Rotate(triangle[i], facing));
|
triangle[i] = Vector2Add(boid->pos, Vector2Rotate(triangle[i], facing));
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawTriangle(triangle[0], triangle[1], triangle[2], BLACK);
|
DrawTriangle(triangle[0], triangle[1], triangle[2], visuals->boid_color);
|
||||||
|
|
||||||
if (visuals->draw_boid_direction) {
|
if (visuals->draw_boid_direction) {
|
||||||
DrawCircle(boid->pos.x, boid->pos.y, visuals->boid_edge_size * 0.05, RED);
|
DrawCircle(boid->pos.x, boid->pos.y, visuals->boid_edge_size * 0.05, RED);
|
||||||
Vector2 look_pos = Vector2Add(boid->pos, Vector2Multiply(boid->dir, { 30, 30 }));
|
Vector2 look_pos = Vector2Add(boid->pos, vector2_mul_value(boid->dir, visuals->boid_edge_size*1.5));
|
||||||
DrawLine(boid->pos.x, boid->pos.y, look_pos.x, look_pos.y, RED);
|
DrawLine(boid->pos.x, boid->pos.y, look_pos.x, look_pos.y, RED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateDrawFrame() {
|
static Rectangle rect_with_offset(Rectangle rect, Vector2 offset)
|
||||||
// TODO: Show this on screen
|
{
|
||||||
// LogTrace("%d", count_out_of_bounds_boids(&world));
|
return { rect.x + offset.x, rect.y + offset.y, rect.width, rect.height };
|
||||||
|
}
|
||||||
|
|
||||||
|
static Rectangle rect_with_offset(Rectangle rect, float x, float y)
|
||||||
|
{
|
||||||
|
return { rect.x + x, rect.y + y, rect.width, rect.height };
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gui_valuebox_float(Rectangle rect, const char *text, float *value, float min_value, float max_value, bool edit_mode) {
|
||||||
|
int int_value = *value;
|
||||||
|
int result = GuiValueBox(rect, text, &int_value, min_value, max_value, edit_mode);
|
||||||
|
*value = int_value;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gui_valuebox_float(Rectangle rect, const char *text, float *value, float min_value, float max_value, bool *edit_mode) {
|
||||||
|
if (gui_valuebox_float(rect, text, value, min_value, max_value, *edit_mode)) {
|
||||||
|
*edit_mode = !*edit_mode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct VerticalLayout {
|
||||||
|
float x, y;
|
||||||
|
float gap;
|
||||||
|
};
|
||||||
|
|
||||||
|
static Rectangle next_in_layout(VerticalLayout *layout, float width, float height, float offset_x = 0) {
|
||||||
|
Rectangle rect = { layout->x + offset_x, layout->y, width, height };
|
||||||
|
layout->y += height + layout->gap;
|
||||||
|
return rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ui_draw(World *world, Visuals *visuals, UI *ui) {
|
||||||
|
if (!visuals->show_control_panel) {
|
||||||
|
visuals->show_control_panel = GuiButton({ 20, 20, 30, 30 }, GuiIconText(ICON_PENCIL_BIG, ""));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float panel_height = 310;
|
||||||
|
visuals->show_control_panel = !GuiWindowBox({ 20, 20, 660, panel_height }, "Control panel");
|
||||||
|
|
||||||
|
float group_height = panel_height - 45;
|
||||||
|
|
||||||
|
GuiGroupBox({ 30, 55, 180, group_height }, "Visuals");
|
||||||
|
{
|
||||||
|
VerticalLayout layout = { .x = 40, .y = 65, .gap = 8 };
|
||||||
|
|
||||||
|
GuiCheckBox(next_in_layout(&layout, 15, 15), "Show direction", &visuals->draw_boid_direction);
|
||||||
|
GuiCheckBox(next_in_layout(&layout, 15, 15), "Show view cone", &visuals->draw_view_cone);
|
||||||
|
GuiCheckBox(next_in_layout(&layout, 15, 15), "Show separation radius", &visuals->draw_separation_radius);
|
||||||
|
GuiCheckBox(next_in_layout(&layout, 15, 15), "Show collision rays", &visuals->draw_collision_avoidance_rays);
|
||||||
|
GuiCheckBox(next_in_layout(&layout, 15, 15), "Show pulling forces", &visuals->draw_pulling_forces);
|
||||||
|
GuiSlider(next_in_layout(&layout, 100, 15), NULL, "Boid size", &visuals->boid_edge_size, 5, 150);
|
||||||
|
|
||||||
|
Rectangle boid_color_rect = next_in_layout(&layout, 50, 50);
|
||||||
|
GuiColorPicker(boid_color_rect, NULL, &visuals->boid_color);
|
||||||
|
GuiLabel(rect_with_offset({ 80, 10, 80, 16 }, boid_color_rect.x, boid_color_rect.y), "Boid color");
|
||||||
|
|
||||||
|
Rectangle bg_color_rect = next_in_layout(&layout, 50, 50);
|
||||||
|
GuiColorPicker(bg_color_rect, NULL, &visuals->bg_color);
|
||||||
|
GuiLabel(rect_with_offset({ 80, 10, 80, 16 }, bg_color_rect.x, bg_color_rect.y), "BG color");
|
||||||
|
|
||||||
|
// TODO: Add show FPS
|
||||||
|
// TODO: Add showing out of bounds boids
|
||||||
|
}
|
||||||
|
|
||||||
|
GuiGroupBox({ 220, 55, 220, group_height }, "Boid");
|
||||||
|
{
|
||||||
|
VerticalLayout layout = { .x = 230, .y = 65, .gap = 8 };
|
||||||
|
|
||||||
|
GuiSlider(next_in_layout(&layout, 100, 15), NULL, "Separation radius", &world->separation_radius, 10, 200);
|
||||||
|
GuiSlider(next_in_layout(&layout, 100, 15), NULL, "View radius", &world->view_radius, 10, 400);
|
||||||
|
GuiSlider(next_in_layout(&layout, 100, 15), NULL, "View angle", &world->view_angle, 0, 2*PI);
|
||||||
|
|
||||||
|
gui_valuebox_float(next_in_layout(&layout, 50, 15, 60), "Min speed", &world->min_speed, 0, world->max_speed, &ui->min_speed_edit);
|
||||||
|
gui_valuebox_float(next_in_layout(&layout, 50, 15, 60), "Max speed", &world->max_speed, 0, 1000, &ui->max_speed_edit);
|
||||||
|
gui_valuebox_float(next_in_layout(&layout, 50, 15, 60), "Steer speed", &world->max_steer_speed, 0, 1000, &ui->steer_speed_edit);
|
||||||
|
|
||||||
|
GuiSlider(next_in_layout(&layout, 100, 15), NULL, "Collision distance", &world->collision_avoidance_distance, 10, 200);
|
||||||
|
GuiSlider(next_in_layout(&layout, 100, 15), NULL, "Collision ray angle", &world->collision_avoidance_ray_angle, 0, PI);
|
||||||
|
GuiSpinner(next_in_layout(&layout, 100, 15, 95), "Collision ray count", &world->collision_avoidance_ray_count, 1, 10, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
GuiGroupBox({ 450, 55, 220, group_height }, "Flock");
|
||||||
|
{
|
||||||
|
VerticalLayout layout = { .x = 605, .y = 65, .gap = 8 };
|
||||||
|
gui_valuebox_float(next_in_layout(&layout, 50, 15), "Alignment strength", &world->alignment_strength, 0, 100, &ui->alignment_strength_edit);
|
||||||
|
gui_valuebox_float(next_in_layout(&layout, 50, 15), "Cohesion strength", &world->cohesion_strength, 0, 100, &ui->cohesion_strength_edit);
|
||||||
|
gui_valuebox_float(next_in_layout(&layout, 50, 15), "Separation strength", &world->separation_strength, 0, 100, &ui->separation_strength_edit);
|
||||||
|
gui_valuebox_float(next_in_layout(&layout, 50, 15), "Collision avoidance strength", &world->collision_avoidance_strength, 0, 100, &ui->collision_avoidance_strength_edit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateDrawFrame() {
|
||||||
float dt = GetFrameTime();
|
float dt = GetFrameTime();
|
||||||
|
|
||||||
#ifdef PLATFORM_WEB
|
#ifdef PLATFORM_WEB
|
||||||
@ -342,9 +436,10 @@ void UpdateDrawFrame() {
|
|||||||
|
|
||||||
// Draw
|
// Draw
|
||||||
BeginDrawing();
|
BeginDrawing();
|
||||||
ClearBackground(RAYWHITE);
|
ClearBackground(g_visuals.bg_color);
|
||||||
|
|
||||||
world_draw(&g_world, &g_visuals);
|
world_draw(&g_world, &g_visuals);
|
||||||
|
ui_draw(&g_world, &g_visuals, &g_ui);
|
||||||
|
|
||||||
EndDrawing();
|
EndDrawing();
|
||||||
}
|
}
|
||||||
@ -362,22 +457,13 @@ int main() {
|
|||||||
g_world.size = { (float)screen_width, (float)screen_height };
|
g_world.size = { (float)screen_width, (float)screen_height };
|
||||||
|
|
||||||
float border = g_visuals.boid_edge_size;
|
float border = g_visuals.boid_edge_size;
|
||||||
for (int i = 0; i < 100; i++) {
|
for (int i = 0; i < 50; i++) {
|
||||||
Boid boid;
|
Boid boid;
|
||||||
boid_rand_init(&g_world, &boid, border);
|
boid_rand_init(&g_world, &boid, border);
|
||||||
g_world.boids.push_back(boid);
|
g_world.boids.push_back(boid);
|
||||||
}
|
}
|
||||||
|
|
||||||
// world.boids.push_back({
|
GuiLoadStyleDefault();
|
||||||
// .pos = { 100, 100 },
|
|
||||||
// .dir = { 1, 0 },
|
|
||||||
// .speed = world.boid_min_speed
|
|
||||||
// });
|
|
||||||
// world.boids.push_back({
|
|
||||||
// .pos = { 100, 120 },
|
|
||||||
// .dir = { 1, 0 },
|
|
||||||
// .speed = world.boid_min_speed
|
|
||||||
// });
|
|
||||||
|
|
||||||
#ifdef PLATFORM_WEB
|
#ifdef PLATFORM_WEB
|
||||||
emscripten_set_main_loop(UpdateDrawFrame, 0, 1);
|
emscripten_set_main_loop(UpdateDrawFrame, 0, 1);
|
||||||
@ -388,5 +474,7 @@ int main() {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
window.Close();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user