diff --git a/engine/breeze.h b/engine/breeze.h index c7685a2..d825498 100644 --- a/engine/breeze.h +++ b/engine/breeze.h @@ -8,6 +8,7 @@ #include "breeze/utils/array.h" #include "breeze/utils/heap.h" +#include "breeze/utils/object_pool.h" #include "breeze/utils/string.h" #include "breeze/utils/tokenizer.h" diff --git a/engine/breeze/defines.h b/engine/breeze/defines.h index 7387878..a182b46 100644 --- a/engine/breeze/defines.h +++ b/engine/breeze/defines.h @@ -21,9 +21,10 @@ typedef double f64; #define BZ_ASSERT(e) assert(e) +#define DEBUG_MODE #ifndef DEBUG_MODE #undef BZ_ASSERT -#define BZ_ASSERT(e) (void)(e) +#define BZ_ASSERT(e) BZ_UNUSDE(x) #endif #define BZ_UNUSED(x) (void)(x) diff --git a/engine/breeze/utils/object_pool.c b/engine/breeze/utils/object_pool.c index 1ffbfeb..e6545be 100644 --- a/engine/breeze/utils/object_pool.c +++ b/engine/breeze/utils/object_pool.c @@ -54,8 +54,9 @@ void *bzObjectPool(BzObjectPool *pool) { return object; } void bzObjectPoolRelease(BzObjectPool *pool, void *object) { - size_t objectIdx = (size_t) object - (size_t)pool->objects; + size_t objectIdx = (size_t) object - (size_t) pool->objects; + objectIdx /= pool->stride; BZ_ASSERT(objectIdx < pool->numObjects); - *(i32 *) objectIdx = pool->firstFree; + *(i32 *) ((u8 *) pool->objects + objectIdx * pool->stride) = pool->firstFree; pool->firstFree = (i32) objectIdx; } diff --git a/game/components.h b/game/components.h index 371c544..4804367 100644 --- a/game/components.h +++ b/game/components.h @@ -62,10 +62,15 @@ typedef struct Animation { } Animation; extern ECS_COMPONENT_DECLARE(Animation); +#define PATH_DATA_SIZE 8 +typedef struct PathData { + Position waypoints[PATH_DATA_SIZE]; + size_t numWaypoints; + struct PathData *next; +} PathData; + typedef struct Path { - Position *waypoints; - i32 maxWaypoints; - i32 numWaypoints; + PathData *paths; i32 curWaypoint; } Path; extern ECS_COMPONENT_DECLARE(Path); diff --git a/game/game_state.h b/game/game_state.h index 21d41ca..df984df 100644 --- a/game/game_state.h +++ b/game/game_state.h @@ -16,8 +16,6 @@ typedef struct Game { f32 frameDuration; Vector2 targetPos; ecs_entity_t entity; - Path path; - Position waypoints[128]; struct { int building; Vector2 mouseDown; @@ -30,6 +28,9 @@ typedef struct Game { i64 gold; i64 pop; } resources; + struct { + BzObjectPool *pathData; + } pools; f32 elapsed; } Game; diff --git a/game/main.c b/game/main.c index c9cebfd..98db29b 100644 --- a/game/main.c +++ b/game/main.c @@ -53,6 +53,12 @@ bool init(void *userData) { ecs_singleton_set(ECS, Game, {}); Game *game = ecs_singleton_get_mut(ECS, Game); + // init pools + game->pools.pathData = bzObjectPoolCreate(&(BzObjectPoolDesc) { + .objectSize=sizeof(PathData), + .numObjects=512 + }); + int screenWidth = 1280; int screenHeight = 720; @@ -207,21 +213,23 @@ void render(float dt, void *userData) { static PathNode *heap = NULL; if (!heap) heap = bzHeapCreate(PathNode, game->map.width * game->map.height); - game->path.waypoints = game->waypoints; - game->path.maxWaypoints = 128; - findPath(&(PathfindingDesc) { - .start=(TilePosition){57, 24}, - .target=(TilePosition){tileX, tileY}, - .map=&game->map, - .heap=heap, - .outPath=&game->path - }); - if (game->path.numWaypoints > 0 && IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) { - ecs_entity_t e = game->entity; - bzLogInfo("%d", ecs_is_alive(ECS, e)); - Position pos = worldPos; - //ecs_set_ptr(ECS, e, Position, &pos); - ecs_set_ptr(ECS, e, Path, &game->path); + if (!ecs_has(ECS, game->entity, Path)) { + Path path = {}; + const Position *start = ecs_get(ECS, game->entity, Position); + findPath(&(PathfindingDesc) { + .start=(TilePosition) { + (int) (start->x / game->map.tileWidth), + (int) (start->y / game->map.tileHeight) + }, + .target=(TilePosition) {tileX, tileY}, + .map=&game->map, + .heap=heap, + .outPath=&path, + .pool=game->pools.pathData + }); + if (path.paths && IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) { + ecs_set_ptr(ECS, game->entity, Path, &path); + } } ecs_progress(ECS, dt); diff --git a/game/pathfinding.c b/game/pathfinding.c index ef1a80a..85dac73 100644 --- a/game/pathfinding.c +++ b/game/pathfinding.c @@ -17,6 +17,8 @@ static i32 dst(TilePosition a, TilePosition b) { bool findPath(const PathfindingDesc *desc) { BZ_ASSERT(desc->map); BzTileMap *map = desc->map; + BZ_ASSERT(desc->start.x >= 0 && desc->start.x < map->width); + BZ_ASSERT(desc->start.y >= 0 && desc->start.y < map->height); typedef struct Visited { bool visited : 1; i8 x : 3; @@ -81,37 +83,50 @@ bool findPath(const PathfindingDesc *desc) { i32 pathLen = 0; if (foundPath && desc->outPath) { TilePosition pos = desc->target; - while (pos.x != desc->start.x || pos.y != desc->start.y) { - Visited *visit = &visited[pos.y * map->width + pos.x]; - BZ_ASSERT(visit->x != 0 && visit->y != 0); - pos.x -= visit->x; - pos.y -= visit->y; - pathLen++; - } Path *out = desc->outPath; out->curWaypoint = 0; - pos = desc->target; - i32 len = pathLen; - // Skip positions - while (len >= out->maxWaypoints) { - Visited visit = visited[pos.y * map->width + pos.x]; - pos.x -= visit.x; - pos.y -= visit.y; - len--; - } + BZ_ASSERT(desc->pool); + PathData *pathData = bzObjectPool(desc->pool); + pathData->numWaypoints = 0; + pathData->next = NULL; + i32 numWaypoints = 0; // Write path - for (i32 i = 0; i < len; i++) { - out->waypoints[len - i - 1] = (Position){ - pos.x * map->tileWidth + map->tileWidth * 0.5f, - pos.y * map->tileHeight + map->tileHeight * 0.5f + while (pos.x != desc->start.x || pos.y != desc->start.y) { + Position waypoint = { + pos.x * map->tileWidth + map->tileWidth * 0.5f, + pos.y * map->tileHeight + map->tileHeight * 0.5f }; - out->numWaypoints++; + + if (pathData->numWaypoints + 1 > PATH_DATA_SIZE) { + PathData *newPathData = bzObjectPool(desc->pool); + newPathData->numWaypoints = 0; + newPathData->next = pathData; + pathData = newPathData; + numWaypoints = 0; + } + pathData->waypoints[numWaypoints++] = waypoint; + pathData->numWaypoints = numWaypoints; + Visited visit = visited[pos.y * map->width + pos.x]; + BZ_ASSERT(visit.x != 0 || visit.y != 0); pos.x -= visit.x; pos.y -= visit.y; + pathLen++; + } + out->paths = pathData; + + // Reverse paths + while (pathData) { + for (i32 i = 0; i < pathData->numWaypoints / 2; i++) { + i32 left = i; + i32 right = (i32) (pathData->numWaypoints - 1 - i); + + Position tmp = pathData->waypoints[left]; + pathData->waypoints[left] = pathData->waypoints[right]; + pathData->waypoints[right] = tmp; + } + pathData = pathData->next; } - BZ_ASSERT(len == out->maxWaypoints); - out->numWaypoints = len; } if (!desc->heap) { diff --git a/game/pathfinding.h b/game/pathfinding.h index 0df3a64..7785489 100644 --- a/game/pathfinding.h +++ b/game/pathfinding.h @@ -20,6 +20,7 @@ typedef struct PathNode { typedef struct PathfindingDesc { TilePosition start; TilePosition target; + BzObjectPool *pool; BzTileMap *map; PathNode *heap; Path *outPath; diff --git a/game/systems_entity.c b/game/systems_entity.c index 261dcf9..3459ba5 100644 --- a/game/systems_entity.c +++ b/game/systems_entity.c @@ -74,17 +74,24 @@ void updatePos(ecs_iter_t *it) { } #include void targetFinish(ecs_iter_t *it) { + const Game *game = ecs_singleton_get(ECS, Game); + for (i32 i = 0; i < it->count; i++) { ecs_entity_t e = it->entities[i]; Path *path = ecs_get_mut(it->world, e, Path); - if (!path) continue; - path->curWaypoint++; - if (path->curWaypoint >= path->numWaypoints) { + if (path->curWaypoint >= path->paths->numWaypoints) { + PathData *finished = path->paths; + path->paths = finished->next; + path->curWaypoint = 0; + bzObjectPoolRelease(game->pools.pathData, finished); // Finished - ecs_remove(it->world, e, Path); - continue; + if (path->paths == NULL) { + ecs_remove(it->world, e, Path); + continue; + } } - TargetPosition target = path->waypoints[path->curWaypoint - 1]; + TargetPosition target = path->paths->waypoints[path->curWaypoint]; + path->curWaypoint++; target.x += rand() % (4 + 1 + 2) -2; ecs_set(it->world, e, TargetPosition, {target.x, target.y}); } @@ -95,28 +102,34 @@ void startPath(ecs_iter_t *it) { for (i32 i = 0; i < it->count; i++) { ecs_entity_t e = it->entities[i]; - if (path->numWaypoints == 0) { + if (path->paths == NULL) { ecs_remove(it->world, e, Path); continue; } - ecs_set(it->world, e, TargetPosition, {path[i].waypoints[0].x, path[i].waypoints[0].y}); - path[i].curWaypoint++; + ecs_set(it->world, e, TargetPosition, {path[i].paths->waypoints[0].x, path[i].paths->waypoints[0].y}); + path[i].curWaypoint = 1; } } void drawDebugPath(ecs_iter_t *it) { Path *path = ecs_field(it, Path, 1); for (i32 i = 0; i < it->count; i++) { - for (i32 iPath = 0; iPath < path[i].numWaypoints; iPath++) { - Color color = RED; - if (iPath < path[i].curWaypoint - 1) - color = GREEN; - else if (iPath == path[i].curWaypoint - 1) - color = ORANGE; - color.a = 180; + PathData *pathData = path->paths; + bool first = true; + while (pathData) { + for (i32 iPath = 0; iPath < pathData->numWaypoints; iPath++) { + Color color = RED; + if (first && iPath < path[i].curWaypoint - 1) + color = GREEN; + else if (first && iPath == path[i].curWaypoint - 1) + color = ORANGE; + color.a = 180; - Position pos = path[i].waypoints[iPath]; - DrawCircle(pos.x, pos.y, 3, color); + Position pos = pathData->waypoints[iPath]; + DrawCircle(pos.x, pos.y, 3, color); + } + first = false; + pathData = pathData->next; } } }