Allocate path with object pool for pathfinding
This commit is contained in:
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include "breeze/utils/array.h"
|
#include "breeze/utils/array.h"
|
||||||
#include "breeze/utils/heap.h"
|
#include "breeze/utils/heap.h"
|
||||||
|
#include "breeze/utils/object_pool.h"
|
||||||
#include "breeze/utils/string.h"
|
#include "breeze/utils/string.h"
|
||||||
#include "breeze/utils/tokenizer.h"
|
#include "breeze/utils/tokenizer.h"
|
||||||
|
|
||||||
|
|||||||
@@ -21,9 +21,10 @@ typedef double f64;
|
|||||||
|
|
||||||
#define BZ_ASSERT(e) assert(e)
|
#define BZ_ASSERT(e) assert(e)
|
||||||
|
|
||||||
|
#define DEBUG_MODE
|
||||||
#ifndef DEBUG_MODE
|
#ifndef DEBUG_MODE
|
||||||
#undef BZ_ASSERT
|
#undef BZ_ASSERT
|
||||||
#define BZ_ASSERT(e) (void)(e)
|
#define BZ_ASSERT(e) BZ_UNUSDE(x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define BZ_UNUSED(x) (void)(x)
|
#define BZ_UNUSED(x) (void)(x)
|
||||||
|
|||||||
@@ -54,8 +54,9 @@ void *bzObjectPool(BzObjectPool *pool) {
|
|||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
void bzObjectPoolRelease(BzObjectPool *pool, void *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);
|
BZ_ASSERT(objectIdx < pool->numObjects);
|
||||||
*(i32 *) objectIdx = pool->firstFree;
|
*(i32 *) ((u8 *) pool->objects + objectIdx * pool->stride) = pool->firstFree;
|
||||||
pool->firstFree = (i32) objectIdx;
|
pool->firstFree = (i32) objectIdx;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,10 +62,15 @@ typedef struct Animation {
|
|||||||
} Animation;
|
} Animation;
|
||||||
extern ECS_COMPONENT_DECLARE(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 {
|
typedef struct Path {
|
||||||
Position *waypoints;
|
PathData *paths;
|
||||||
i32 maxWaypoints;
|
|
||||||
i32 numWaypoints;
|
|
||||||
i32 curWaypoint;
|
i32 curWaypoint;
|
||||||
} Path;
|
} Path;
|
||||||
extern ECS_COMPONENT_DECLARE(Path);
|
extern ECS_COMPONENT_DECLARE(Path);
|
||||||
|
|||||||
@@ -16,8 +16,6 @@ typedef struct Game {
|
|||||||
f32 frameDuration;
|
f32 frameDuration;
|
||||||
Vector2 targetPos;
|
Vector2 targetPos;
|
||||||
ecs_entity_t entity;
|
ecs_entity_t entity;
|
||||||
Path path;
|
|
||||||
Position waypoints[128];
|
|
||||||
struct {
|
struct {
|
||||||
int building;
|
int building;
|
||||||
Vector2 mouseDown;
|
Vector2 mouseDown;
|
||||||
@@ -30,6 +28,9 @@ typedef struct Game {
|
|||||||
i64 gold;
|
i64 gold;
|
||||||
i64 pop;
|
i64 pop;
|
||||||
} resources;
|
} resources;
|
||||||
|
struct {
|
||||||
|
BzObjectPool *pathData;
|
||||||
|
} pools;
|
||||||
f32 elapsed;
|
f32 elapsed;
|
||||||
} Game;
|
} Game;
|
||||||
|
|
||||||
|
|||||||
38
game/main.c
38
game/main.c
@@ -53,6 +53,12 @@ bool init(void *userData) {
|
|||||||
ecs_singleton_set(ECS, Game, {});
|
ecs_singleton_set(ECS, Game, {});
|
||||||
Game *game = ecs_singleton_get_mut(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 screenWidth = 1280;
|
||||||
int screenHeight = 720;
|
int screenHeight = 720;
|
||||||
@@ -207,21 +213,23 @@ void render(float dt, void *userData) {
|
|||||||
static PathNode *heap = NULL;
|
static PathNode *heap = NULL;
|
||||||
if (!heap)
|
if (!heap)
|
||||||
heap = bzHeapCreate(PathNode, game->map.width * game->map.height);
|
heap = bzHeapCreate(PathNode, game->map.width * game->map.height);
|
||||||
game->path.waypoints = game->waypoints;
|
if (!ecs_has(ECS, game->entity, Path)) {
|
||||||
game->path.maxWaypoints = 128;
|
Path path = {};
|
||||||
findPath(&(PathfindingDesc) {
|
const Position *start = ecs_get(ECS, game->entity, Position);
|
||||||
.start=(TilePosition){57, 24},
|
findPath(&(PathfindingDesc) {
|
||||||
.target=(TilePosition){tileX, tileY},
|
.start=(TilePosition) {
|
||||||
.map=&game->map,
|
(int) (start->x / game->map.tileWidth),
|
||||||
.heap=heap,
|
(int) (start->y / game->map.tileHeight)
|
||||||
.outPath=&game->path
|
},
|
||||||
});
|
.target=(TilePosition) {tileX, tileY},
|
||||||
if (game->path.numWaypoints > 0 && IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) {
|
.map=&game->map,
|
||||||
ecs_entity_t e = game->entity;
|
.heap=heap,
|
||||||
bzLogInfo("%d", ecs_is_alive(ECS, e));
|
.outPath=&path,
|
||||||
Position pos = worldPos;
|
.pool=game->pools.pathData
|
||||||
//ecs_set_ptr(ECS, e, Position, &pos);
|
});
|
||||||
ecs_set_ptr(ECS, e, Path, &game->path);
|
if (path.paths && IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) {
|
||||||
|
ecs_set_ptr(ECS, game->entity, Path, &path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ecs_progress(ECS, dt);
|
ecs_progress(ECS, dt);
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ static i32 dst(TilePosition a, TilePosition b) {
|
|||||||
bool findPath(const PathfindingDesc *desc) {
|
bool findPath(const PathfindingDesc *desc) {
|
||||||
BZ_ASSERT(desc->map);
|
BZ_ASSERT(desc->map);
|
||||||
BzTileMap *map = 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 {
|
typedef struct Visited {
|
||||||
bool visited : 1;
|
bool visited : 1;
|
||||||
i8 x : 3;
|
i8 x : 3;
|
||||||
@@ -81,37 +83,50 @@ bool findPath(const PathfindingDesc *desc) {
|
|||||||
i32 pathLen = 0;
|
i32 pathLen = 0;
|
||||||
if (foundPath && desc->outPath) {
|
if (foundPath && desc->outPath) {
|
||||||
TilePosition pos = desc->target;
|
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;
|
Path *out = desc->outPath;
|
||||||
out->curWaypoint = 0;
|
out->curWaypoint = 0;
|
||||||
pos = desc->target;
|
BZ_ASSERT(desc->pool);
|
||||||
i32 len = pathLen;
|
PathData *pathData = bzObjectPool(desc->pool);
|
||||||
// Skip positions
|
pathData->numWaypoints = 0;
|
||||||
while (len >= out->maxWaypoints) {
|
pathData->next = NULL;
|
||||||
Visited visit = visited[pos.y * map->width + pos.x];
|
i32 numWaypoints = 0;
|
||||||
pos.x -= visit.x;
|
|
||||||
pos.y -= visit.y;
|
|
||||||
len--;
|
|
||||||
}
|
|
||||||
// Write path
|
// Write path
|
||||||
for (i32 i = 0; i < len; i++) {
|
while (pos.x != desc->start.x || pos.y != desc->start.y) {
|
||||||
out->waypoints[len - i - 1] = (Position){
|
Position waypoint = {
|
||||||
pos.x * map->tileWidth + map->tileWidth * 0.5f,
|
pos.x * map->tileWidth + map->tileWidth * 0.5f,
|
||||||
pos.y * map->tileHeight + map->tileHeight * 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];
|
Visited visit = visited[pos.y * map->width + pos.x];
|
||||||
|
BZ_ASSERT(visit.x != 0 || visit.y != 0);
|
||||||
pos.x -= visit.x;
|
pos.x -= visit.x;
|
||||||
pos.y -= visit.y;
|
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) {
|
if (!desc->heap) {
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ typedef struct PathNode {
|
|||||||
typedef struct PathfindingDesc {
|
typedef struct PathfindingDesc {
|
||||||
TilePosition start;
|
TilePosition start;
|
||||||
TilePosition target;
|
TilePosition target;
|
||||||
|
BzObjectPool *pool;
|
||||||
BzTileMap *map;
|
BzTileMap *map;
|
||||||
PathNode *heap;
|
PathNode *heap;
|
||||||
Path *outPath;
|
Path *outPath;
|
||||||
|
|||||||
@@ -74,17 +74,24 @@ void updatePos(ecs_iter_t *it) {
|
|||||||
}
|
}
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
void targetFinish(ecs_iter_t *it) {
|
void targetFinish(ecs_iter_t *it) {
|
||||||
|
const Game *game = ecs_singleton_get(ECS, Game);
|
||||||
|
|
||||||
for (i32 i = 0; i < it->count; i++) {
|
for (i32 i = 0; i < it->count; i++) {
|
||||||
ecs_entity_t e = it->entities[i];
|
ecs_entity_t e = it->entities[i];
|
||||||
Path *path = ecs_get_mut(it->world, e, Path);
|
Path *path = ecs_get_mut(it->world, e, Path);
|
||||||
if (!path) continue;
|
if (path->curWaypoint >= path->paths->numWaypoints) {
|
||||||
path->curWaypoint++;
|
PathData *finished = path->paths;
|
||||||
if (path->curWaypoint >= path->numWaypoints) {
|
path->paths = finished->next;
|
||||||
|
path->curWaypoint = 0;
|
||||||
|
bzObjectPoolRelease(game->pools.pathData, finished);
|
||||||
// Finished
|
// Finished
|
||||||
ecs_remove(it->world, e, Path);
|
if (path->paths == NULL) {
|
||||||
continue;
|
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;
|
target.x += rand() % (4 + 1 + 2) -2;
|
||||||
ecs_set(it->world, e, TargetPosition, {target.x, target.y});
|
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++) {
|
for (i32 i = 0; i < it->count; i++) {
|
||||||
ecs_entity_t e = it->entities[i];
|
ecs_entity_t e = it->entities[i];
|
||||||
if (path->numWaypoints == 0) {
|
if (path->paths == NULL) {
|
||||||
ecs_remove(it->world, e, Path);
|
ecs_remove(it->world, e, Path);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ecs_set(it->world, e, TargetPosition, {path[i].waypoints[0].x, path[i].waypoints[0].y});
|
ecs_set(it->world, e, TargetPosition, {path[i].paths->waypoints[0].x, path[i].paths->waypoints[0].y});
|
||||||
path[i].curWaypoint++;
|
path[i].curWaypoint = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void drawDebugPath(ecs_iter_t *it) {
|
void drawDebugPath(ecs_iter_t *it) {
|
||||||
Path *path = ecs_field(it, Path, 1);
|
Path *path = ecs_field(it, Path, 1);
|
||||||
|
|
||||||
for (i32 i = 0; i < it->count; i++) {
|
for (i32 i = 0; i < it->count; i++) {
|
||||||
for (i32 iPath = 0; iPath < path[i].numWaypoints; iPath++) {
|
PathData *pathData = path->paths;
|
||||||
Color color = RED;
|
bool first = true;
|
||||||
if (iPath < path[i].curWaypoint - 1)
|
while (pathData) {
|
||||||
color = GREEN;
|
for (i32 iPath = 0; iPath < pathData->numWaypoints; iPath++) {
|
||||||
else if (iPath == path[i].curWaypoint - 1)
|
Color color = RED;
|
||||||
color = ORANGE;
|
if (first && iPath < path[i].curWaypoint - 1)
|
||||||
color.a = 180;
|
color = GREEN;
|
||||||
|
else if (first && iPath == path[i].curWaypoint - 1)
|
||||||
|
color = ORANGE;
|
||||||
|
color.a = 180;
|
||||||
|
|
||||||
Position pos = path[i].waypoints[iPath];
|
Position pos = pathData->waypoints[iPath];
|
||||||
DrawCircle(pos.x, pos.y, 3, color);
|
DrawCircle(pos.x, pos.y, 3, color);
|
||||||
|
}
|
||||||
|
first = false;
|
||||||
|
pathData = pathData->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user