Files
PixelDefense/game/buildings.c

111 lines
3.5 KiB
C

#include "buildings.h"
#include "components.h"
#include "entity_factory.h"
#include "game_state.h"
#include "map_layers.h"
#include "systems/systems.h"
#include <raymath.h>
bool canPlaceBuilding(Game *game, BuildingType type, BzTile tileX, BzTile tileY) {
i32 sizeX, sizeY;
getBuildingSize(type, &sizeX, &sizeY);
if (sizeX == 0 || sizeY == 0) return false;
BzTileMap *map = &game->map;
// Ensure that it is within the map
if (tileX < 0 || tileX + sizeX > map->width ||
tileY < 0 || tileY + sizeY > map->height)
return false;
Rectangle buildArea = {tileX * map->tileWidth, tileY * map->tileHeight,
sizeX * map->tileWidth, sizeY * map->tileHeight};
BzSpatialGridIter it = bzSpatialGridIter(game->entityGrid, buildArea.x, buildArea.y, buildArea.width, buildArea.height);
while (bzSpatialGridQueryNext(&it)) { ecs_entity_t entity = *(ecs_entity_t *) it.data;
Rectangle bounds;
if (!getEntityBounds(entity, NULL, NULL, &bounds)) continue;
if (CheckCollisionRecs(buildArea, bounds))
return false;
}
return true;
}
ecs_entity_t placeBuilding(Game *game, BuildingType type,
BzTile posX, BzTile posY, Owner owner) {
if (type <= BUILDING_NONE || type >= BUILDING_COUNT)
return 0;
i32 sizeX, sizeY;
getBuildingSize(type, &sizeX, &sizeY);
const i32 tileWidth = game->map.tileWidth;
const i32 tileHeight = game->map.tileHeight;
// Create entity
ecs_entity_t building = entityCreateEmpty();
ecs_add_id(ECS, building, Selectable);
ecs_set(ECS, building, Building, {
.type = type,
.pos = (Vec2i) { posX, posY },
.size = (Vec2i) { sizeX, sizeY }
});
Position pos = {
.x = posX * tileWidth + sizeX * tileWidth * 0.5f,
.y = posY * tileHeight + sizeY * tileHeight * 0.5f
};
Size size = {
.x = sizeX * tileWidth,
.y = sizeY * tileHeight
};
ecs_set_ptr(ECS, building, Position, &pos);
ecs_set_ptr(ECS, building, Size, &size);
ecs_set(ECS, building, Rotation, {0});
SpatialGridID gridID = bzSpatialGridInsert(game->entityGrid, &building,
pos.x, pos.y,
size.x, size.y);
ecs_set_ptr(ECS, building, SpatialGridID, &gridID);
ecs_set_ptr(ECS, building, Owner, &owner);
BzTileset *tileset = &game->tileset;
TextureRegion region = {
tileset->tiles,
bzTilesetGetTileRegion(tileset, getBuildingTile(type))
};
region.rec.width *= sizeX;
region.rec.height *= sizeY;
ecs_set_ptr(ECS, building, TextureRegion, &region);
bzTileMapSetCollisions(&game->map, true, posX, posY, sizeX, sizeY);
switch (type) {
case BUILDING_KEEP:
ecs_add_id(ECS, building, Storage);
break;
default:
break;
}
return building;
}
Vector2 getPositionNearBuilding(ecs_entity_t building, Vector2 fromPos) {
BZ_ASSERT(ecs_is_alive(ECS, building));
BZ_ASSERT(ecs_has(ECS, building, Position));
BZ_ASSERT(ecs_has(ECS, building, Size));
Vector2 pos = *ecs_get(ECS, building, Position);
Vector2 size = *ecs_get(ECS, building, Size);
size = Vector2SubtractValue(size, 10.0f);
Vector2 dir = Vector2Normalize(Vector2Subtract(fromPos, pos));
dir = Vector2Multiply(dir, size);
pos = Vector2Add(pos, dir);
return pos;
}