GameMap.java
package io.github.neonteam10.map;
import com.badlogic.gdx.maps.tiled.TiledMap;
import com.badlogic.gdx.maps.tiled.TiledMapTileLayer;
import io.github.neonteam10.graphs.MapGraph;
import java.util.ArrayList;
import java.util.List;
/**
* A class which represents the playable game map. Holds the underlying tiled map and keeps track
* of placed buildings.
*/
public class GameMap {
private final TiledMap tiledMap;
private final TiledMapTileLayer buildingLayer;
private final int width;
private final int height;
private final int widthPx;
private final int heightPx;
private final int tileWidthPx;
private final int tileHeightPx;
private final boolean[][] usableTiles;
private final List<BuildingPrefab> availablePrefabs;
private final List<Building> placedBuildings;
public final MapGraph buildingGraph;
public GameMap(TiledMap tiledMap) {
this.tiledMap = tiledMap;
buildingLayer = (TiledMapTileLayer) tiledMap.getLayers().get("Buildings");
width = buildingLayer.getWidth();
height = buildingLayer.getHeight();
tileWidthPx = buildingLayer.getTileWidth();
tileHeightPx = buildingLayer.getTileHeight();
widthPx = width * tileWidthPx;
heightPx = height * tileHeightPx;
// Compute which tiles are allowed to be placed on.
usableTiles = new boolean[width][height];
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
usableTiles[x][y] = true;
for (var layer : tiledMap.getLayers()) {
if (layer.getName().equals("Terrain")) {
continue;
}
if (((TiledMapTileLayer) layer).getCell(x, y) != null) {
usableTiles[x][y] = false;
}
}
}
}
// Create building types for each prefab layer in the map.
availablePrefabs = new ArrayList<>();
for (var layer : tiledMap.getLayers()) {
if (layer.getName().startsWith("Prefab: ")) {
// Extract prefab name, e.g. Accommodation.
var prefabName = layer.getName().substring("Prefab: ".length());
availablePrefabs.add(new BuildingPrefab(prefabName, (TiledMapTileLayer) layer));
}
}
// Generate textures for each building prefab.
var offscreenBuildingRenderer = new OffscreenBuildingRenderer(this);
for (var prefab : availablePrefabs) {
prefab.generateTextures(offscreenBuildingRenderer);
}
placedBuildings = new ArrayList<>();
buildingGraph = new MapGraph();
}
/**
* Checks whether a building prefab can be placed at the given coordinates.
*
* @param prefab the building prefab
* @param x the x coordinate in world space
* @param y the y coordinate in world space
* @return true if the building can be placed, false otherwise
*/
public boolean canPlaceBuilding(BuildingPrefab prefab, int x, int y) {
for (int prefabX = 0; prefabX < prefab.getWidth(); prefabX++) {
for (int prefabY = 0; prefabY < prefab.getHeight(); prefabY++) {
int mapX = x + prefabX;
int mapY = y + prefabY;
// Check out of bounds.
if (mapX < 0 || mapY < 0 || mapX >= width || mapY >= height) {
return false;
}
// Check if on top of a disallowed tile.
if (!usableTiles[mapX][mapY]) {
return false;
}
}
}
return true;
}
/**
* Creates an instance of the given building prefab and places it at the given coordinates. Doesn't check for
* validity of placement.
*
* @param prefab the building prefab
* @param x the x coordinate in world space
* @param y the y coordinate in world space
* @see #canPlaceBuilding
*/
public void placeBuilding(BuildingPrefab prefab, int x, int y) {
for (int prefabX = 0; prefabX < prefab.getWidth(); prefabX++) {
for (int prefabY = 0; prefabY < prefab.getHeight(); prefabY++) {
int mapX = x + prefabX;
int mapY = y + prefabY;
buildingLayer.setCell(mapX, mapY, prefab.getTiledLayer().getCell(prefabX, prefabY));
usableTiles[mapX][mapY] = false;
}
}
Building newBuilding;
if (prefab.getName().equals("Road")) {
newBuilding = new Building(prefab, x, y, true);
}
else {
newBuilding = new Building(prefab, x, y);
}
buildingGraph.addBuilding(newBuilding);
placedBuildings.add(newBuilding);
}
/**
* Counts the number of existing buildings of the given prefab.
*
* @param prefab the building prefab
* @return the building count
*/
public int getBuildingCount(BuildingPrefab prefab) {
int count = 0;
for (var building : placedBuildings) {
if (building.getPrefab() == prefab) {
count++;
}
}
return count;
}
/**
* @return the total building count of all prefabs
*/
public int getTotalBuildingCount() {
int count = 0;
for (Building building : placedBuildings) {
if (!(building.getRoad())) {
count++;
}
}
return count;
}
/**
* @return the underlying tiled map of this map
*/
public TiledMap getTiledMap() {
return tiledMap;
}
/**
* @return the width of the map in tiles
*/
public int getWidth() {
return width;
}
/**
* @return the height of the map in tiles
*/
public int getHeight() {
return height;
}
/**
* @return the width of the map in pixels
*/
public int getWidthPx() {
return widthPx;
}
/**
* @return the height of the map in pixels
*/
public int getHeightPx() {
return heightPx;
}
/**
* @return the width of a single map tile in pixels
*/
public int getTileWidthPx() {
return tileWidthPx;
}
/**
* @return the height of a single map tile in pixels
*/
public int getTileHeightPx() {
return tileHeightPx;
}
/**
* @return a list of all available prefabs in this map
*/
public List<BuildingPrefab> getAvailablePrefabs() {
return availablePrefabs;
}
}