package tfg; import org.jsfml.graphics.Drawable; import org.jsfml.graphics.PrimitiveType; import org.jsfml.graphics.RenderStates; import org.jsfml.graphics.RenderTarget; import org.jsfml.graphics.RenderWindow; import org.jsfml.graphics.Texture; import org.jsfml.graphics.Vertex; import org.jsfml.graphics.VertexArray; import org.jsfml.system.Vector2f; import org.jsfml.system.Vector2i; import java.io.IOException; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Iterator; /** * A map or level for the player to interact in. Can be created * manually or procedurally. * @author Ritchie Cunningham */ public class Map implements Drawable { /** * The size (length, width) of the map. */ private Vector2i dimensions = new Vector2i(0, 0); private Tile[][] tileArray; /** * The tilesheet texture. */ private Texture tilesheetTexture = new Texture(); /** * Vertex array for the tile map. * This is a streamlined way to draw many sprites at once. */ private VertexArray vertexArray = new VertexArray(); private final ArrayList entitiesOnMap = new ArrayList(); /** * Create a new map of specified size and tile type. * @param l Map length. * @param w Map width. * @param t Default tile to auto-pupulate map. */ public Map(int l, int w, Tile t) { dimensions = new Vector2i(l,w); tileArray = new Tile[dimensions.x][dimensions.y]; try { tilesheetTexture.loadFromFile(Paths.get("res/terrain.png")); } catch(IOException ex) { ex.printStackTrace(); } /* Set vertex array to use quads because the tiles are square. */ vertexArray.setPrimitiveType(PrimitiveType.QUADS); initializeMap(t); /* Auto-populate the map with specified tile. */ } /** * Create a new map of speceified size that default to grass. * @param l Map length. * @param w Map width. */ public Map(int l, int w) { this(l,w,Tile.GRASS); } /** * Fill the entire map to the specified tile. * @param initialTile The tile to populate the map with. */ public void initializeMap(Tile initialTile) { /** * Arrays.fill does not work with matrices, * therefore we have to loop through the outer level to fill the inner. */ for(Tile[] row : tileArray) { /* Set each tile in the row to the specified tile. */ Arrays.fill(row,initialTile); } } /** * Draw the map onto the window. */ public void draw(RenderTarget target, RenderStates states) { vertexArray.clear(); /* empty array from previous draw. */ final int tileSize = Tile.getSize(); /* Iterate through every tile in the map. */ for(int i = 0; i < dimensions.x; i++) { for(int j = 0; j < dimensions.y; j++) { Tile tileType = tileArray[i][j]; /* Grab current tile in the loop. */ /* Grab texture coord to render the tile. */ Vector2f textureCoords = Tile.getTextureCoords(tileType); /* * Add each corner of the tile to the vertex array * counter-clockwise. */ /* Top left. */ vertexArray.add(new Vertex( new Vector2f(i*tileSize, j* tileSize), textureCoords)); /* Bottom left. */ vertexArray.add(new Vertex( new Vector2f(i*tileSize,(j*tileSize)+tileSize), Vector2f.add(textureCoords, new Vector2f(tileSize,tileSize)))); /* Bottom right. */ vertexArray.add(new Vertex( new Vector2f((i*tileSize)+tileSize, (j*tileSize)+tileSize), Vector2f.add(textureCoords, new Vector2f(tileSize,tileSize)))); /* Top right. */ vertexArray.add(new Vertex( new Vector2f((i*tileSize)+tileSize, j*tileSize), Vector2f.add(textureCoords, new Vector2f(tileSize,0)))); } } /* Apply texture to the vertex array. */ RenderStates newStates = new RenderStates(tilesheetTexture); vertexArray.draw(target, newStates); /* Draw vertex array. */ } /** * Return the tile at specified location. * @param l Location of the tile to get. * @return Tile at the specified location. */ public Tile getTile(Location l) { Vector2i position = l.getPosition(); /* Get pos from loc. */ Tile t = tileArray[position.x][position.y]; /* Get tile at this pos. */ return t; } /** * Determine whether or not the location fits within the map. * @param l Location to test. * @return If location is valid. */ public boolean isValidLocation(Location l) { Vector2i coordinates = l.getPosition(); /* Pos from last location. */ /* Return true if the location is greater than 0. */ return ((coordinates.x >= 0) && (coordinates.y >=0) && (coordinates.x < dimensions.x) && (coordinates.y < dimensions.y) && Tile.getCanWalkOn(getTile(l)) && (getEntityatLocation(l) == null)); } public Entity getEntityatLocation(Location l) { Iterator it = entitiesOnMap.iterator(); while(it.hasNext()) { Entity e = it.next(); if(e.getLocation().equals(1)) { return e; } } return null; } public void addEntity(Entity e) { if(getEntityatLocation(e.getLocation()) == null) { e.setParentMap(this); entitiesOnMap.add(e); } } public void drawAllEntities(RenderWindow w) { for(Entity e : entitiesOnMap) { w.draw(e); } } public void updateAllEntities() { Collections.sort(entitiesOnMap); for(Entity e : entitiesOnMap) { e.update(); } } }