From 3dddcd1ea022182fd58fa4712d1cb75eb347f718 Mon Sep 17 00:00:00 2001 From: Rodolfo Barcelli Jo Date: Thu, 22 Jan 2026 18:05:43 +0800 Subject: [PATCH] Fix: becs.h had a few bugs that I didn't catch around deleting entities Add: Particle sim test example1 Add: build script for example1 Add: raylib gitmodule for example1 --- .gitmodules | 3 + becs.h | 6 ++ examples/example1/build.bat | 16 ++++ examples/example1/example1.c | 123 ++++++++++++++++++++++++++++++ examples/example1/external/raylib | 1 + 5 files changed, 149 insertions(+) create mode 100644 .gitmodules create mode 100644 examples/example1/build.bat create mode 100644 examples/example1/example1.c create mode 160000 examples/example1/external/raylib diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..f82ad99 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "examples/example1/external/raylib"] + path = examples/example1/external/raylib + url = https://github.com/raysan5/raylib diff --git a/becs.h b/becs.h index 9497e36..8df4f4b 100644 --- a/becs.h +++ b/becs.h @@ -202,6 +202,11 @@ static void BECS_ComponentPoolRemove(BECS_ComponentPool *pool, BECS_Entity entit pool->denseEntityMapping[index] = last_entity; pool->sparseArray[last_entity] = index; + pool->count--; + } + else + { + pool->count--; } pool->sparseArray[entity] = UINT32_MAX; @@ -321,6 +326,7 @@ BECS_Entity BECS_EntityCreate(BECS_ECS *ecs) entity = ecs->freeEntities[--ecs->freeEntityCount]; ecs->entitySignatures[entity] = 0; ecs->aliveEntities[entity] = true; + ecs->entityCount++; return entity; } diff --git a/examples/example1/build.bat b/examples/example1/build.bat new file mode 100644 index 0000000..b3da528 --- /dev/null +++ b/examples/example1/build.bat @@ -0,0 +1,16 @@ +@echo off + +REM Build Script for Example 1 + +mkdir build + +git submodule update --init + +REM pushd ".\external\raylib\" +REM cmake -S . -B build +REM cmake --build build --config Release +REM popd + +pushd ".\build" +cl /Zi raylib.lib user32.lib opengl32.lib gdi32.lib winmm.lib msvcrt.lib shell32.lib "..\example1.c" -Ic:"\external\raylib\build\raylib\include" /link /libpath:c:"..\external\raylib\build\raylib\Release" /NODEFAULTLIB:libcmt /NODEFAULTLIB:msvcrt /NODEFAULTLIB:libcmtd +popd diff --git a/examples/example1/example1.c b/examples/example1/example1.c new file mode 100644 index 0000000..a45af71 --- /dev/null +++ b/examples/example1/example1.c @@ -0,0 +1,123 @@ +#define BECS_MAX_ENTITIES 20 +#define BECS_MAX_COMPONENTS 4 +#define BECS_IMPLEMENTATION +#include "../../becs.h" +#include +#include "external/raylib/src/raylib.h" + +// Component structs +typedef struct { + float x, y; +} Position; + +typedef struct { + float vx, vy; +} Velocity; + +typedef struct { + float ax, ay; +} Acceleration; + +typedef struct { + float radius; + float lifetime; +} ParticleData; + +// Function to spawn a particle +void SpawnParticle(BECS_ECS *ecs, BECS_ComponentID posID, BECS_ComponentID velID, BECS_ComponentID accID, BECS_ComponentID dataID, float x, float y) { + BECS_Entity entity = BECS_EntityCreate(ecs); + if (entity == BECS_NULL_ENTITY) return; + + Position *pos = (Position *)BECS_ComponentAdd(ecs, entity, posID); + pos->x = x; + pos->y = y; + + Velocity *vel = (Velocity *)BECS_ComponentAdd(ecs, entity, velID); + vel->vx = GetRandomValue(-100, 100); + vel->vy = GetRandomValue(-200, -50); + + Acceleration *acc = (Acceleration *)BECS_ComponentAdd(ecs, entity, accID); + acc->ax = 0.0f; + acc->ay = 100.0f; // Gravity + + ParticleData *data = (ParticleData *)BECS_ComponentAdd(ecs, entity, dataID); + data->radius = 5.0f; + data->lifetime = 2.0f; +} + +int main(void) { + // Initialize ECS + size_t componentSizes[4] = {sizeof(Position), sizeof(Velocity), sizeof(Acceleration), sizeof(ParticleData)}; + size_t memSize = BECS_GetMinMemoryArenaSize(componentSizes, 4); + char *memory = (char *)malloc(memSize); + BECS_ECS ecs = BECS_InitECS(memory, memSize); + + // Register components + BECS_ComponentID posID = BECS_ComponentRegister(&ecs, sizeof(Position), BECS_MAX_ENTITIES); + BECS_ComponentID velID = BECS_ComponentRegister(&ecs, sizeof(Velocity), BECS_MAX_ENTITIES); + BECS_ComponentID accID = BECS_ComponentRegister(&ecs, sizeof(Acceleration), BECS_MAX_ENTITIES); + BECS_ComponentID dataID = BECS_ComponentRegister(&ecs, sizeof(ParticleData), BECS_MAX_ENTITIES); + + InitWindow(800, 400, "2D Particle System with BECS"); + + while (!WindowShouldClose()) { + float dt = GetFrameTime(); + + // Update lifetimes and despawn + for (BECS_Entity entity = 0; entity < BECS_MAX_ENTITIES; entity++) { + if (!BECS_IsEntityAlive(&ecs, entity)) continue; + if (BECS_ComponentHas(&ecs, entity, dataID)) { + ParticleData *data = (ParticleData *)BECS_ComponentGet(&ecs, entity, dataID); + data->lifetime -= dt; + if (data->lifetime <= 0.0f) { + BECS_EntityDestroy(&ecs, entity); + } + } + } + + // Spawn particle on mouse click + if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) { + Vector2 mousePos = GetMousePosition(); + SpawnParticle(&ecs, posID, velID, accID, dataID, mousePos.x, mousePos.y); + } + + // Physics system: update position and velocity + for (BECS_Entity entity = 0; entity < BECS_MAX_ENTITIES; entity++) { + if (!BECS_IsEntityAlive(&ecs, entity)) continue; + if (BECS_ComponentHas(&ecs, entity, posID) && + BECS_ComponentHas(&ecs, entity, velID) && + BECS_ComponentHas(&ecs, entity, accID)) { + Position *pos = (Position *)BECS_ComponentGet(&ecs, entity, posID); + Velocity *vel = (Velocity *)BECS_ComponentGet(&ecs, entity, velID); + Acceleration *acc = (Acceleration *)BECS_ComponentGet(&ecs, entity, accID); + + vel->vx += acc->ax * dt; + vel->vy += acc->ay * dt; + pos->x += vel->vx * dt; + pos->y += vel->vy * dt; + } + } + + BeginDrawing(); + ClearBackground(BLACK); + + // Render system: draw particles + for (BECS_Entity entity = 0; entity < BECS_MAX_ENTITIES; entity++) { + if (!BECS_IsEntityAlive(&ecs, entity)) continue; + if (BECS_ComponentHas(&ecs, entity, posID) && BECS_ComponentHas(&ecs, entity, dataID)) { + Position *pos = (Position *)BECS_ComponentGet(&ecs, entity, posID); + ParticleData *data = (ParticleData *)BECS_ComponentGet(&ecs, entity, dataID); + float alpha = data->lifetime / 2.0f; + Color color = {255, 255, 255, (unsigned char)(alpha * 255)}; + DrawCircle((int)pos->x, (int)pos->y, data->radius, color); + } + } + + DrawText(TextFormat("Particles: %u", ecs.entityCount), 10, 10, 20, WHITE); + EndDrawing(); + } + + CloseWindow(); + free(memory); + return 0; +} diff --git a/examples/example1/external/raylib b/examples/example1/external/raylib new file mode 160000 index 0000000..c610d22 --- /dev/null +++ b/examples/example1/external/raylib @@ -0,0 +1 @@ +Subproject commit c610d228a244f930ad53492604640f39584c66da