From 4c376222408208166f228601849998609b167dc3 Mon Sep 17 00:00:00 2001 From: Klemen Plestenjak Date: Wed, 15 Nov 2023 18:32:43 +0100 Subject: [PATCH] Add entity map --- CMakeLists.txt | 2 + engine/CMakeLists.txt | 2 - engine/breeze/utils/array.h | 2 +- game/buildings.c | 5 -- game/components.c | 2 + game/components.h | 3 +- game/entity_map.c | 150 ++++++++++++++++++++++++++++++++++++ game/entity_map.h | 60 +++++++++++++++ game/game_state.h | 4 +- game/main.c | 6 ++ game/map_init.c | 7 -- game/pathfinding.c | 2 +- game/systems.h | 17 ++++ game/systems_entity.c | 9 +++ 14 files changed, 253 insertions(+), 18 deletions(-) create mode 100644 game/entity_map.c create mode 100644 game/entity_map.h diff --git a/CMakeLists.txt b/CMakeLists.txt index ff54160..2e5eaf8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,6 +15,8 @@ add_executable(PixelDefense game/buildings.h game/components.c game/components.h + game/entity_map.c + game/entity_map.h game/entrypoint.c game/main.c game/map_init.c diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index c784446..17604dd 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -36,7 +36,6 @@ set(BreezeSources breeze/map/tileset.c breeze/utils/array.c - breeze/utils/object_pool.c breeze/utils/heap.c breeze/utils/tokenizer.c ) @@ -51,7 +50,6 @@ set(BreezeHeaders breeze/map/tileset.h breeze/utils/array.h - breeze/utils/object_pool.h breeze/utils/heap.h breeze/utils/string.h breeze/utils/tokenizer.h diff --git a/engine/breeze/utils/array.h b/engine/breeze/utils/array.h index aa98d27..3b3118f 100644 --- a/engine/breeze/utils/array.h +++ b/engine/breeze/utils/array.h @@ -49,6 +49,6 @@ do { \ (arr)[_bzArrayIns(arr, idx)] = (e); \ } while (0) #define bzArraySet(arr, idx, e) (arr)[_bzArraySet(arr, idx)] = e -#define bzArrayPop(arr) (arr)[_bzArrayPop(arr)] (arr)[_bzArrayPop(arr)] +#define bzArrayPop(arr) (arr)[_bzArrayPop(arr)] #endif //BREEZE_ARRAY_H diff --git a/game/buildings.c b/game/buildings.c index f4aed9a..29eea25 100644 --- a/game/buildings.c +++ b/game/buildings.c @@ -73,9 +73,6 @@ ecs_entity_t placeBuilding(BzTileMap *map, BuildingType type, BzTile tileX, BzTi Game *game = ecs_singleton_get_mut(ECS, Game); i32 sizeX, sizeY; getBuildingSize(type, &sizeX, &sizeY); - ECS_COMPONENT(ECS, TilePosition); - ECS_COMPONENT(ECS, TileSize); - ECS_COMPONENT(ECS, Owner); BzTileLayer *buildingLayer = bzTileMapGetLayer(map, LAYER_BUILDINGS); BzTileset *buildingTileset = bzTileLayerGetTileset(map, buildingLayer); @@ -95,8 +92,6 @@ ecs_entity_t placeBuilding(BzTileMap *map, BuildingType type, BzTile tileX, BzTi bzTileLayerSetTile(buildingLayer, layerTile, x, y, 1, 1); buildingTile++; - game->entityMap[y * buildingLayer->width + x] = e; - bzTileMapUpdateCollider(map, x, y); } buildingTile += buildingTileset->width - sizeX; diff --git a/game/components.c b/game/components.c index 0c7831c..1fa86f7 100644 --- a/game/components.c +++ b/game/components.c @@ -7,6 +7,7 @@ ECS_COMPONENT_DECLARE(Owner); ECS_COMPONENT_DECLARE(Position); ECS_COMPONENT_DECLARE(Size); ECS_COMPONENT_DECLARE(TargetPosition); +ECS_COMPONENT_DECLARE(MoveForce); ECS_COMPONENT_DECLARE(Rotation); ECS_COMPONENT_DECLARE(Health); ECS_COMPONENT_DECLARE(TextureRegion); @@ -21,6 +22,7 @@ void initComponentIDs(ecs_world_t *ecs) { ECS_COMPONENT_DEFINE(ecs, Position); ECS_COMPONENT_DEFINE(ecs, Size); ECS_COMPONENT_DEFINE(ecs, TargetPosition); + ECS_COMPONENT_DEFINE(ecs, MoveForce); ECS_COMPONENT_DEFINE(ecs, Rotation); ECS_COMPONENT_DEFINE(ecs, Health); ECS_COMPONENT_DEFINE(ecs, TextureRegion); diff --git a/game/components.h b/game/components.h index 8c73c9b..371c544 100644 --- a/game/components.h +++ b/game/components.h @@ -26,10 +26,11 @@ typedef struct Owner { } Owner; extern ECS_COMPONENT_DECLARE(Owner); -typedef Vector2 Position, Size, TargetPosition; +typedef Vector2 Position, Size, TargetPosition, MoveForce; extern ECS_COMPONENT_DECLARE(Position); extern ECS_COMPONENT_DECLARE(Size); extern ECS_COMPONENT_DECLARE(TargetPosition); +extern ECS_COMPONENT_DECLARE(MoveForce); typedef f32 Rotation; extern ECS_COMPONENT_DECLARE(Rotation); diff --git a/game/entity_map.c b/game/entity_map.c new file mode 100644 index 0000000..b55d541 --- /dev/null +++ b/game/entity_map.c @@ -0,0 +1,150 @@ +#include "entity_map.h" + +#include + +EntityMap entityMapCreate(const EntityMapDesc *desc) { + i32 width = (desc->maxWidth + (desc->cellResolution - 1)) / desc->cellResolution; + i32 height = (desc->maxHeight + (desc->cellResolution - 1)) / desc->cellResolution; + EntityMap map = { + .width=width, + .height=height, + .cellResolution=desc->cellResolution, + .cellDepth=desc->cellDepth, + }; + + size_t numBytes = sizeof(EntityMapCell) * map.width * map.height * map.cellDepth; + map.cells = bzAlloc(numBytes); + bzMemSet(map.cells, 0, numBytes); + map.entities = bzArrayNew(EntityMapEntry, 512); + + return map; +} +void entityMapDestroy(EntityMap *entityMap) { + bzFree(entityMap->cells); + entityMap->cells = NULL; + bzArrayFree(entityMap->entities); + entityMap->entities = NULL; +} + +static EntityMapIndex calculateMapIndex(EntityMap *entityMap, Position pos, Size size) { + i32 minX = (i32) floorf(pos.x); + i32 minY = (i32) floorf(pos.y); + i32 maxX = (i32) floorf(pos.x + size.x); + i32 maxY = (i32) floorf(pos.y + size.y); + return (EntityMapIndex) { + (i16) (minX / entityMap->width), + (i16) (minY / entityMap->height), + (i16) (maxX / entityMap->width), + (i16) (maxY / entityMap->height), + }; +} + +static bool insertMapEntry(EntityMap *entityMap, EntityMapCell idx, i32 x, i32 y) { + EntityMapCell *cell = entityMap->cells + (y * entityMap->width + x) * entityMap->cellDepth; + for (i32 i = 0; i < entityMap->cellResolution; i++) { + if (cell[i] == 0) { + cell[i] = idx; + return true; + } + } + return false; +} +static void removeMapEntry(EntityMap *entityMap, EntityMapCell idx, i32 x, i32 y) { + EntityMapCell *cell = entityMap->cells + (y * entityMap->width + x) * entityMap->cellDepth; + i32 i; + for (i = 0; i < entityMap->cellResolution; i++) { + if (cell[i] == idx) { + break; + } + } + i32 j; + for (j = i; j < entityMap->cellResolution; j++) { + if (cell[j] == 0) { + j--; + break; + } + + } + if (i != j) { + // swap with last + cell[i] = cell[j]; + cell[j] = 0; + } else { + // 'i' is last + cell[i] = 0; + } +} + +EntityMapEntry entityMapInsert(EntityMap *entityMap, ecs_entity_t entity, Position pos, Size size) { + EntityMapEntry entry = {entity}; + EntityMapIndex mapIndex = calculateMapIndex(entityMap, pos, size); + entry.index = mapIndex; + + i32 entryIdx = bzArraySize(entityMap->entities); + entry.entryID = entryIdx; + bzArrayPush(entityMap->entities, entry); + + bool wasInserted = true; + + for (i32 y = mapIndex.minY; y <= mapIndex.maxY; y++) { + for (i32 x = mapIndex.minX; x <= mapIndex.maxX; x++) { + wasInserted &= insertMapEntry(entityMap, entryIdx, x, y); + if (!wasInserted) { + return (EntityMapEntry) { + .entity = 0, + }; + } + } + } + + return entry; +} +void entityMapRemove(EntityMap *entityMap, EntityMapEntry entry) { + entityMapRemoveID(entityMap, entry.entryID); +} +void entityMapRemoveID(EntityMap *entityMap, i32 entryID) { + EntityMapEntry entry = bzArrayGet(entityMap->entities, entryID); + EntityMapIndex index = entry.index; + + for (i32 y = index.minY; y <= index.maxY; y++) { + for (i32 x = index.minX; x <= index.maxX; x++) { + removeMapEntry(entityMap, entryID, x, y); + } + } + + EntityMapEntry last = bzArrayGet(entityMap->entities, bzArraySize(entityMap->entities)); + bzArraySet(entityMap->entities, entryID, last); + bzArrayPop(entityMap->entities); +} + +EntityMapIter entityMapQueryIter(EntityMap *entityMap, Position pos, Size size) { + EntityMapIndex mapIndex = calculateMapIndex(entityMap, pos, size); + EntityMapIter it = { + .entityMap=entityMap, + .index=mapIndex, + .x=mapIndex.minX, + .y=mapIndex.minY, + .cellIdx=0, + }; + return it; +} +bool entityMapQueryNext(EntityMapIter *it) { + i32 cellOffset = (it->y * it->entityMap->width + it->x) * + it->entityMap->cellDepth + it->cellIdx; + if (it->cellIdx >= it->entityMap->cellDepth || + it->entityMap->cells[cellOffset] == 0) { + it->cellIdx = 0; + it->x++; + if (it->x > it->index.maxX) { + it->y++; + if (it->y > it->index.maxY) + return false; + } + } + + EntityMapCell cell = it->entityMap->cells[cellOffset]; + it->entry = bzArrayGet(it->entityMap->entities, cell); + + it->cellIdx++; + return true; +} diff --git a/game/entity_map.h b/game/entity_map.h new file mode 100644 index 0000000..a1d864f --- /dev/null +++ b/game/entity_map.h @@ -0,0 +1,60 @@ +#ifndef PIXELDEFENSE_ENTITY_MAP_H +#define PIXELDEFENSE_ENTITY_MAP_H + +#include +#include + +#include "components.h" + +typedef struct EntityMapIndex { + i32 minX, minY; + i32 maxX, maxY; +} EntityMapIndex; + +typedef struct EntityMapEntry { + ecs_entity_t entity; + i32 queryIdx; + i32 entryID; + EntityMapIndex index; +} EntityMapEntry; + +typedef i32 EntityMapCell; + +typedef struct EntityMap { + EntityMapEntry *entities; + EntityMapCell *cells; + i32 width; + i32 height; + i32 cellResolution; + i32 cellDepth; +} EntityMap; + +typedef struct EntityMapDesc { + i32 maxWidth; + i32 maxHeight; + i32 cellResolution; + i32 cellDepth; +} EntityMapDesc; + +typedef struct EntityMapIter { + EntityMap *entityMap; + EntityMapEntry entry; + EntityMapIndex index; + i32 x; + i32 y; + i32 cellIdx; +} EntityMapIter; + +EntityMap entityMapCreate(const EntityMapDesc *desc); +void entityMapDestroy(EntityMap *entityMap); + +EntityMapEntry entityMapInsert(EntityMap *entityMap, ecs_entity_t entity, Position pos, Size size); +void entityMapRemove(EntityMap *entityMap, EntityMapEntry entry); +void entityMapRemoveID(EntityMap *entityMap, i32 entryID); + +EntityMapIter entityMapQueryIter(EntityMap *entityMap, Position pos, Size size); +bool entityMapQueryNext(EntityMapIter *it); + + + +#endif //PIXELDEFENSE_ENTITY_MAP_H diff --git a/game/game_state.h b/game/game_state.h index af23c66..21d41ca 100644 --- a/game/game_state.h +++ b/game/game_state.h @@ -4,13 +4,15 @@ #include #include +#include "entity_map.h" + typedef struct Game { Camera2D camera; BzTileset terrainTileset; BzTileset buildingsTileset; BzTileset entitiesTileset; BzTileMap map; - ecs_entity_t *entityMap; + EntityMap entityMap; f32 frameDuration; Vector2 targetPos; ecs_entity_t entity; diff --git a/game/main.c b/game/main.c index 9b750b1..5ffc151 100644 --- a/game/main.c +++ b/game/main.c @@ -93,6 +93,12 @@ bool init(void *userData) { .objectGroups[OBJECTS_GAME]=(BzTileObjectsDesc) {"Game"}, .objectGroups[OBJECTS_ENTITIES]=(BzTileObjectsDesc ) {"Entities"} }); + game->entityMap = entityMapCreate(&(EntityMapDesc) { + .maxWidth=game->map.width * game->map.tileWidth, + .maxHeight=game->map.height * game->map.tileHeight, + .cellResolution=game->map.tileWidth, + .cellDepth=10 + }); bzTileMapOverrideLayer(&game->map, LAYER_BUILDING_OWNER, initBuildingsLayer); diff --git a/game/map_init.c b/game/map_init.c index d148034..21b7a43 100644 --- a/game/map_init.c +++ b/game/map_init.c @@ -48,7 +48,6 @@ bool initEntityObjectsLayer(BzTileMap *map, BzTileObjectGroup *objectGroup) { bool initBuildingsLayer(BzTileMap *map, BzTileLayer *layer) { Game *game = ecs_singleton_get_mut(ECS, Game); - game->entityMap = bzCalloc(sizeof(*game->entityMap), layer->width * layer->height); BzTileLayer *ownershipLayer = layer; BzTileLayer *buildingLayer = bzTileMapGetLayer(map, LAYER_BUILDINGS); @@ -76,12 +75,6 @@ bool initBuildingsLayer(BzTileMap *map, BzTileLayer *layer) { ownerTile = getTileBuilding(ownerTile); ecs_set(ECS, e, Owner, {.playerID=ownerTile}); - for (i32 yIdx = y; yIdx < y + size.sizeY; yIdx++) { - for (i32 xIdx = x; xIdx < x + size.sizeX; xIdx++) { - game->entityMap[yIdx * layer->width + xIdx] = e; - } - } - //bzTileMapUpdateCollider(&GAME.map, x, y); } } diff --git a/game/pathfinding.c b/game/pathfinding.c index f111485..993d09f 100644 --- a/game/pathfinding.c +++ b/game/pathfinding.c @@ -27,7 +27,7 @@ bool findPath(const PathfindingDesc *desc) { PathNode *heap = desc->heap; if (!heap) heap = bzHeapNew(PathNode, map->width * map->height); - else bzHeapReset(heap); + else bzHeapClear(heap); i32 toTargetCost = dst(desc->start, desc->target); bzHeapPush(heap, (PathNode) {toTargetCost, 0, toTargetCost, desc->start}); diff --git a/game/systems.h b/game/systems.h index 1596cd1..dc47754 100644 --- a/game/systems.h +++ b/game/systems.h @@ -10,6 +10,23 @@ * Entity Systems **********************************/ +/* + * 0: Game (singleton) + */ +void entityRemoved(ecs_iter_t *it); +/* + * 0: Game (singleton) + */ +void entityAdded(ecs_iter_t *it); + +/* + * 0: Game (singleton) + * 1: Position + * 2: MoveForce + */ +void entityUpdatePhysics(ecs_iter_t *it); + + void renderEntities(ecs_iter_t *it); void updateAnimations(ecs_iter_t *it); void updatePos(ecs_iter_t *it); diff --git a/game/systems_entity.c b/game/systems_entity.c index bb18556..261dcf9 100644 --- a/game/systems_entity.c +++ b/game/systems_entity.c @@ -5,6 +5,15 @@ #include #include +void entityRemoved(ecs_iter_t *it) { + +} +void entityAdded(ecs_iter_t *it) { + +} +void entityUpdatePhysics(ecs_iter_t *it) { + +} void updateAnimations(ecs_iter_t *it) { Game *game = ecs_singleton_get_mut(ECS, Game);