Add 8 layers to collisions

This commit is contained in:
2024-01-13 08:09:34 +01:00
parent 0118e574de
commit 8692d89479
10 changed files with 76 additions and 61 deletions

View File

@@ -24,6 +24,7 @@ add_executable(PixelDefense
game/buildings.h
game/components.c
game/components.h
game/constants.h
game/entity_factory.c
game/entity_factory.h
game/entrypoint.c

View File

@@ -112,47 +112,6 @@ static void handleTileObjectLayer(BzTileObjectGroup *layer, cute_tiled_layer_t *
}
static void updateCollisionMap(BzTileMap *map, i32 startX, i32 startY, i32 endX, i32 endY) {
BZ_ASSERT(map->collisionMap);
BZ_ASSERT(startX >= 0 && endX <= map->width &&
startY >= 0 && endY <= map->height);
for (i32 y = startY; y < endY; y++) {
for (i32 x = startX; x < endX; x++) {
map->collisionMap[y * map->width + x] = false;
}
}
// Top-most layer takes priority
for (i32 i = map->layerCount - 1; i >= 0; i--) {
BzTileLayer *layer = map->layers + i;
if (!layer->desc.applyColliders) continue;
if (!layer->data) continue;
if (layer->tilesetIdx == -1) continue;
BzTileset *tileset = map->tilesets + layer->tilesetIdx;
for (i32 y = startY; y < endY; y++) {
for (i32 x = startX; x < endX; x++) {
i32 idx = y * map->width + x;
if (map->collisionMap[idx]) continue;
BzTile tile = bzTileLayerGetTile(layer, x, y);
BzTileID tileID = bzTilesetGetTileID(tileset, tile);
BzTileShape tilesetShape = bzTilesetGetTileCollider(tileset, tileID);
if (tilesetShape.type == BZ_TILE_SHAPE_NONE ||
tilesetShape.type == BZ_TILE_SHAPE_POINT)
continue;
map->collisionMap[idx] = true;
}
}
}
}
static void createColliders(BzTileMap *map) {
map->collisionMap = bzAlloc(map->width * map->height * sizeof(*map->collisionMap));
updateCollisionMap(map, 0, 0, map->width, map->height);
}
BzTileMap bzTileMapCreate(const BzTileMapDesc *desc) {
BzTileMap map = {.backgroundColor=BLACK};
// Auto detect tileset count.
@@ -257,8 +216,11 @@ BzTileMap bzTileMapCreate(const BzTileMapDesc *desc) {
}
cute_tiled_free_map(cuteMap);
if (desc->generateCollisionMap)
createColliders(&map);
if (desc->collisionMap) {
i32 numBytes = map.width * map.height;
map.collisionMap = bzAlloc(numBytes);
bzMemSet(map.collisionMap, 0, numBytes);
}
map.isValid = true;
return map;
@@ -407,7 +369,7 @@ f32 bzTileMapRayCast(BzTileMap *map, Vector2 from, Vector2 to, f32 maxDst, Vecto
i32 cellX = (i32) from.x;
i32 cellY = (i32) from.y;
if (bzTileMapHasCollision(map, cellX, cellY)) {
if (bzTileMapHasAnyCollision(map, cellX, cellY)) {
return 0.0f;
}
Vector2 rayLength = Vector2Zero();
@@ -503,25 +465,61 @@ void bzTileMapDrawCollisions(BzTileMap *map) {
}
}
bool bzTileMapHasCollision(BzTileMap *map, i32 x, i32 y) {
bool bzTileMapHasAnyCollision(BzTileMap *map, i32 x, i32 y) {
if (!map->collisionMap) return false;
i32 idx = y * map->width + x;
return map->collisionMap[idx];
return map->collisionMap[idx] != 0;
}
void bzTileMapSetCollisions(BzTileMap *map, bool collision, i32 startX, i32 startY, i32 sizeX, i32 sizeY) {
bool bzTileMapHasCollision(BzTileMap *map, i32 layer, i32 x, i32 y) {
BZ_ASSERT(layer >= 0 && layer < 8);
if (!map->collisionMap) return false;
i32 idx = y * map->width + x;
return (map->collisionMap[idx] & (1 << layer)) != 0;
}
void bzTileMapSetCollisions(BzTileMap *map, bool collision, i32 layer, i32 startX, i32 startY, i32 sizeX, i32 sizeY) {
i32 endX = startX + sizeX;
i32 endY = startY + sizeY;
BZ_ASSERT(layer >= 0 && layer < 8);
BZ_ASSERT(map->collisionMap);
BZ_ASSERT(startX >= 0 && endX <= map->width &&
startY >= 0 && endY <= map->height);
for (i32 y = startY; y < endY; y++) {
for (i32 x = startX; x < endX; x++) {
map->collisionMap[y * map->width + x] = collision;
i32 idxOffset = y * map->width + x;
u8 *cell = map->collisionMap + idxOffset;
if (collision)
*cell |= (1 << layer);
else
*cell &= ~(1 << layer);
}
}
}
void bzTileMapAddLayerCollisions(BzTileMap *map, i32 mapLayer, i32 collLayer) {
BZ_ASSERT(map);
BZ_ASSERT(mapLayer >= 0 && mapLayer < map->layerCount);
BZ_ASSERT(collLayer >= 0 && collLayer < 8);
const i32 layerBit = (1 << collLayer);
BzTileLayer *layer = map->layers + mapLayer;
BzTileset *tileset = map->tilesets + layer->tilesetIdx;
for (i32 y = 0; y < map->height; y++) {
for (i32 x = 0; x < map->width; x++) {
i32 idx = y * map->width + x;
if (map->collisionMap[idx]) continue;
BzTile tile = bzTileLayerGetTile(layer, x, y);
BzTileID tileID = bzTilesetGetTileID(tileset, tile);
BzTileShape tilesetShape = bzTilesetGetTileCollider(tileset, tileID);
u8 *cell = map->collisionMap + idx;
if (tilesetShape.type == BZ_TILE_SHAPE_NONE ||
tilesetShape.type == BZ_TILE_SHAPE_POINT) {
// Reset
*cell &= ~layerBit;
} else {
*cell |= layerBit;
}
}
}
void bzTileMapUpdateCollisions(BzTileMap *map, i32 x, i32 y, i32 sizeX, i32 sizeY) {
if (!map->collisionMap) return;
updateCollisionMap(map, x, y, x + sizeX, y + sizeY);
}

View File

@@ -32,7 +32,7 @@ typedef struct BzTileObjectsDesc {
typedef struct BzTileMapDesc {
const char *path;
bool generateCollisionMap;
bool collisionMap;
BzTileset tilesets[BZ_MAP_MAX_TILESETS];
BzTileLayerDesc layers[BZ_MAP_MAX_LAYERS];
@@ -86,7 +86,8 @@ typedef struct BzTileMap {
i32 tileWidth;
i32 tileHeight;
bool *collisionMap;
u8 *collisionMap;
i32 resolution;
BzTileLayer layers[BZ_MAP_MAX_LAYERS];
i32 layerCount;
@@ -129,10 +130,12 @@ f32 bzTileMapRayCast(BzTileMap *map, Vector2 from, Vector2 to, f32 maxDst, Vecto
bool bzTileMapCanRayCastLine(BzTileMap *map, Vector2 from, Vector2 to);
void bzTileMapDraw(BzTileMap *map);
void bzTileMapDrawCollisions(BzTileMap *map);
bool bzTileMapHasCollision(BzTileMap *map, i32 x, i32 y);
void bzTileMapSetCollisions(BzTileMap *map, bool collision, i32 startX, i32 startY, i32 sizeX, i32 sizeY);
void bzTileMapUpdateCollisions(BzTileMap *map, i32 x, i32 y, i32 sizeX, i32 sizeY);
bool bzTileMapHasAnyCollision(BzTileMap *map, i32 x, i32 y);
bool bzTileMapHasCollision(BzTileMap *map, i32 layer, i32 x, i32 y);
void bzTileMapSetCollisions(BzTileMap *map, bool collision, i32 layer, i32 startX, i32 startY, i32 sizeX, i32 sizeY);
void bzTileMapAddLayerCollisions(BzTileMap *map, i32 mapLayer, i32 layer);

View File

@@ -78,7 +78,7 @@ ecs_entity_t placeBuilding(Game *game, BuildingType type,
region.rec.height *= sizeY;
ecs_set_ptr(ECS, building, TextureRegion, &region);
bzTileMapSetCollisions(&game->map, true, posX, posY, sizeX, sizeY);
bzTileMapSetCollisions(&game->map, true, COLL_LAYER_BUILDINGS, posX, posY, sizeX, sizeY);
switch (type) {
case BUILDING_KEEP:

9
game/constants.h Normal file
View File

@@ -0,0 +1,9 @@
#ifndef PIXELDEFENSE_CONSTANTS_H
#define PIXELDEFENSE_CONSTANTS_H
enum {
COLL_LAYER_TERRAIN = 0,
COLL_LAYER_BUILDINGS = 1,
};
#endif //PIXELDEFENSE_CONSTANTS_H

View File

@@ -4,6 +4,8 @@
#include <breeze.h>
#include <flecs.h>
#include "constants.h"
typedef enum GameScreen {
SCREEN_GAME,
SCREEN_PAUSE_MENU,

View File

@@ -95,7 +95,7 @@ void unloadMap(Game *game) {
void loadMap(Game *game, const char *path) {
game->map = bzTileMapCreate(&(BzTileMapDesc) {
.path=path,
.generateCollisionMap=true,
.collisionMap=true,
.tilesets[0]=game->tileset,
.layers[LAYER_TERRAIN]=(BzTileLayerDesc) {"terrain", .renderer=terrainRender, .applyColliders=true},
@@ -123,6 +123,8 @@ void loadMap(Game *game, const char *path) {
game->camera.rotation = 0.0f;
game->camera.zoom = 3.0f;
bzTileMapAddLayerCollisions(&game->map, LAYER_TERRAIN, COLL_LAYER_TERRAIN);
bzTileMapOverrideLayer(&game->map, LAYER_TREES, initTreesLayer);
bzTileMapOverrideLayer(&game->map, LAYER_TREES2, initTreesLayer);

View File

@@ -192,7 +192,7 @@ bool pathfindAStar(const PathfindingDesc *desc) {
x < 0 || x >= map->width)
continue;
// not walkable
if (bzTileMapHasCollision(map, x, y))
if (bzTileMapHasAnyCollision(map, x, y))
continue;
PathNodeRecord *curRecord = &closedSet[y * map->width + x];
if (curRecord->visited)

View File

@@ -412,7 +412,7 @@ void addEntityToInspected(ecs_entity_t entity, Game *game) {
}
static bool isUnitObstructed(f32 x, f32 y, BzTileMap *map) {
return bzTileMapHasCollision(map, x / map->tileWidth, y / map->tileHeight);
return bzTileMapHasAnyCollision(map, x / map->tileWidth, y / map->tileHeight);
}
static bool canPlaceUnit(Vector2 pos, f32 space, BzTileMap *map) {

View File

@@ -81,7 +81,7 @@ ECS_DTOR(Building, building, {
Vec2i pos = building->pos;
Vec2i size = building->size;
Game *game = ecs_singleton_get_mut(ECS, Game);
bzTileMapSetCollisions(&game->map, false, pos.x, pos.y, size.x, size.y);
bzTileMapSetCollisions(&game->map, false, COLL_LAYER_BUILDINGS, pos.x, pos.y, size.x, size.y);
})
ECS_MOVE(Building, dst, src, {
*dst = *src;