org.mini2Dx.tiled.TiledMap Maven / Gradle / Ivy
/*******************************************************************************
* Copyright 2019 See AUTHORS file
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package org.mini2Dx.tiled;
import org.mini2Dx.core.Graphics;
import org.mini2Dx.core.Mdx;
import org.mini2Dx.core.assets.AssetManager;
import org.mini2Dx.core.files.FileHandle;
import org.mini2Dx.core.graphics.Color;
import org.mini2Dx.core.graphics.TextureAtlas;
import org.mini2Dx.gdx.utils.Array;
import org.mini2Dx.tiled.exception.TiledException;
import org.mini2Dx.tiled.exception.UnsupportedOrientationException;
import org.mini2Dx.tiled.renderer.*;
/**
* A Tiled map instance
*/
public class TiledMap {
/**
* Set to true to tell the renderer to not render layers marked as hidden in Tiled
*/
public static boolean STRICT_LAYER_VISIBILITY = false;
/**
* Set to true to optimise CPU time (at cost of memory usage) for rendering tile layers that are mostly empty
*/
public static boolean FAST_RENDER_EMPTY_LAYERS = false;
/**
* Set to true if mini2Dx should check the viewport bounds while rendering a tile and avoid rendering it if it is outside of the bounds
*/
public static boolean CLIP_TILES_OUTSIDE_GRAPHICS_VIEWPORT = false;
private final TiledMapData tiledMapData;
private TileLayerRenderer tileLayerRenderer;
private TiledObjectGroupRenderer tiledObjectGroupRenderer;
/**
* Constructs a map from a TMX file
*
* @param fileHandle
* A {@link FileHandle} to a .tmx file
* @throws TiledException
* Thrown if there were issues with the loaded map
*/
public TiledMap(FileHandle fileHandle) {
this(fileHandle, true);
}
/**
* Constructs a map from a TMX file
*
* @param fileHandle
* A {@link FileHandle} to a .tmx file
* @param loadTilesetTextures
* True if the tileset images should be loaded
* @throws TiledException
* Thrown if there were issues with the loaded map
*/
public TiledMap(FileHandle fileHandle, boolean loadTilesetTextures) {
this(new TiledParser(), fileHandle, loadTilesetTextures);
}
/**
* Constructs a map from a TMX file
*
* @param parser
* An existing {@link TiledParser} instance
* @param fileHandle
* A {@link FileHandle} to a .tmx file
* @param loadTilesetTextures
* True if the tileset images should be loaded
* @throws TiledException
* Thrown if there were issues with the loaded map
*/
public TiledMap(TiledParser parser, FileHandle fileHandle, boolean loadTilesetTextures) {
this(new TiledMapData(parser, fileHandle), loadTilesetTextures);
}
public TiledMap(TiledMapData tiledMapData, boolean loadTilesetTextures) {
super();
this.tiledMapData = tiledMapData;
if (loadTilesetTextures) {
loadTilesetTextures();
}
switch (tiledMapData.getOrientation()) {
case ORTHOGONAL:
tileLayerRenderer = new OrthogonalTileLayerRenderer(this);
break;
case ISOMETRIC:
tileLayerRenderer = new IsometricTileLayerRenderer(this);
break;
case ISOMETRIC_STAGGERED:
// TODO: Add renderer for isometric maps
break;
case HEXAGONAL:
tileLayerRenderer = new HexagonalTileLayerRenderer(this);
break;
case UNKNOWN:
default:
throw new UnsupportedOrientationException(tiledMapData.getOrientation().name());
}
}
/**
* Returns if the {@link Tileset} images have been loaded
*
* @return True if all tilesets + textures have been loaded, otherwise false
*/
public boolean isTilesetTexturesLoaded() {
return tiledMapData.isTilesetTexturesLoaded();
}
/**
* Returns if the {@link Tileset} images have been loaded
* @param ignoreObjectTemplateTilesets True if tilesets referenced by object templates should be ignored
* @return True if all tilesets + textures have been loaded, otherwise false
*/
public boolean isTilesetTexturesLoaded(boolean ignoreObjectTemplateTilesets) {
return tiledMapData.isTilesetTexturesLoaded(ignoreObjectTemplateTilesets);
}
/**
* Loads all {@link Tileset} textures for this map if they are not already loaded
* Note: Depending on the texture sizes, this may need to be called over several frames
* @return True if all tilesets + textures have been loaded, otherwise false
*/
public boolean loadTilesetTextures() {
return tiledMapData.loadTilesetTextures();
}
/**
* Loads all {@link Tileset} textures for this map if they are not already loaded
*
Note: Depending on the texture sizes, this may need to be called over several frames
* @param assetManager The {@link AssetManager} to use
* @return True if all tilesets + textures have been loaded, otherwise false
*/
public boolean loadTilesetTextures(AssetManager assetManager) {
return tiledMapData.loadTilesetTextures(assetManager);
}
/**
* Loads all {@link Tileset} textures for this map if they are not already loaded
*
Note: Depending on the texture sizes, this may need to be called over several frames
* @param textureAtlas The {@link TextureAtlas} to load textures from
* @return True if all tilesets + textures have been loaded, otherwise false
*/
public boolean loadTilesetTextures(TextureAtlas textureAtlas) {
return tiledMapData.loadTilesetTextures(textureAtlas);
}
/**
* Loads all {@link Tileset} textures for this map if they are not already loaded
*
Note: Depending on the texture sizes, this may need to be called over several frames
* @param loadObjectTemplateTilesets True if tilesets used by object templates should be loaded
* @return True if all tilesets + textures have been loaded, otherwise false
*/
public boolean loadTilesetTextures(boolean loadObjectTemplateTilesets) {
return tiledMapData.loadTilesetTextures(loadObjectTemplateTilesets);
}
/**
* Loads all {@link Tileset} textures for this map if they are not already loaded
*
Note: Depending on the texture sizes, this may need to be called over several frames
* @param loadObjectTemplateTilesets True if tilesets used by object templates should be loaded
* @param assetManager The {@link AssetManager} to use
* @return True if all tilesets + textures have been loaded, otherwise false
*/
public boolean loadTilesetTextures(AssetManager assetManager, boolean loadObjectTemplateTilesets) {
return tiledMapData.loadTilesetTextures(assetManager, loadObjectTemplateTilesets);
}
/**
* Loads all {@link Tileset} textures for this map if they are not already loaded
*
Note: Depending on the texture sizes, this may need to be called over several frames
* @param loadObjectTemplateTilesets True if tilesets used by object templates should be loaded
* @param textureAtlas The {@link TextureAtlas} to load textures from
* @return True if all tilesets + textures have been loaded, otherwise false
*/
public boolean loadTilesetTextures(TextureAtlas textureAtlas, boolean loadObjectTemplateTilesets) {
return tiledMapData.loadTilesetTextures(textureAtlas, loadObjectTemplateTilesets);
}
/**
* Updates map elements such as animated tiles
*
* @param delta
* The time since the last frame (in seconds)
*/
public void update(float delta) {
if (tiledMapData.getAnimatedTiles() == null) {
return;
}
for (int i = 0; i < tiledMapData.getAnimatedTiles().size; i++) {
tiledMapData.getAnimatedTiles().get(i).update(delta);
}
}
/**
* Draws the entire map at the specified coordinates
*
* @param g
* The {@link Graphics} context available for rendering
* @param x
* The x coordinate to render at
* @param y
* The y coordinate to render at
*/
public void draw(Graphics g, int x, int y) {
draw(g, x, y, 0, 0, tiledMapData.getWidth(), tiledMapData.getHeight());
}
/**
* Draws a layer of the map at the specified coordinates
*
* @param g
* The {@link Graphics} context available for rendering
* @param x
* The x coordinate to render at
* @param y
* The y coordinate to render at
* @param layer
* The layer index to render (Note: The indicies only represent the root layers)
*/
public void draw(Graphics g, int x, int y, int layer) {
draw(g, x, y, 0, 0, tiledMapData.getWidth(), tiledMapData.getHeight(), layer);
}
/**
* Draws a section of the map at the specified coordinates
*
* @param g
* The {@link Graphics} context available for rendering
* @param x
* The x coordinate to render at
* @param y
* The y coordinate to render at
* @param startTileX
* The x tile coordinate in the map to start from
* @param startTileY
* The y tile coordinate in the map to start from
* @param widthInTiles
* The amount of tiles across the x axis to render
* @param heightInTiles
* The amount of tiles across the y axis to render
*/
public void draw(Graphics g, int x, int y, int startTileX, int startTileY, int widthInTiles, int heightInTiles) {
for (int i = 0; i < tiledMapData.getTotalLayers(); i++) {
draw(g, x, y, startTileX, startTileY, widthInTiles, heightInTiles, i);
}
}
/**
* Draws a section of a specified layer of the map at the specified coordinates
*
* @param g
* The {@link Graphics} context available for rendering
* @param x
* The x coordinate to render at
* @param y
* The y coordinate to render at
* @param startTileX
* The x tile coordinate in the map to start from
* @param startTileY
* The y tile coordinate in the map to start from
* @param widthInTiles
* The amount of tiles across the x axis to render
* @param heightInTiles
* The amount of tiles across the y axis to render
* @param layer
* The layer index to render (Note: The indicies only represent the root layers)
*/
public void draw(Graphics g, int x, int y, int startTileX, int startTileY, int widthInTiles, int heightInTiles,
int layer) {
Layer tiledLayer = tiledMapData.getLayers().get(layer);
drawLayer(g, tiledLayer, x, y, startTileX, startTileY, widthInTiles, heightInTiles);
}
private void drawLayer(Graphics g, Layer tiledLayer, int x, int y, int startTileX, int startTileY, int widthInTiles, int heightInTiles) {
switch (tiledLayer.getLayerType()) {
case IMAGE:
break;
case OBJECT:
drawTiledObjectGroup(g, (TiledObjectGroup) tiledLayer, x, y, startTileX, startTileY, widthInTiles,
heightInTiles);
break;
case TILE:
drawTileLayer(g, (TileLayer) tiledLayer, x, y, startTileX, startTileY, widthInTiles, heightInTiles);
break;
case GROUP:
drawGroupLayer(g, (GroupLayer) tiledLayer, x, y, startTileX, startTileY, widthInTiles, heightInTiles);
break;
default:
break;
}
}
/**
* Developers can override this method which is called before a layer is
* rendered
*
* To prevent the layer from rendering, return false from this method.
*
* @param g
* The {@link Graphics} context used for rendering
* @param layer
* The {@link TileLayer} which was just rendered
* @param startTileX
* The x coordinate in tiles where rendering started
* @param startTileY
* The y coordinate in tiles where rendering started
* @param widthInTiles
* The amount of tiles that were rendered along the X axis
* @param heightInTiles
* The amount of tiles that were rendered along the Y axis
* @return True if the layer should be rendered
*/
protected boolean preTileLayerRendered(Graphics g, TileLayer layer, int startTileX, int startTileY, int widthInTiles,
int heightInTiles) {
return true;
}
/**
* Developers can override this method to implement sprite rendering
*
* @param g
* The {@link Graphics} context used for rendering
* @param layer
* The {@link TileLayer} which was just rendered
* @param startTileX
* The x coordinate in tiles where rendering started
* @param startTileY
* The y coordinate in tiles where rendering started
* @param widthInTiles
* The amount of tiles that were rendered along the X axis
* @param heightInTiles
* The amount of tiles that were rendered along the Y axis
*/
protected void onTileLayerRendered(Graphics g, TileLayer layer, int startTileX, int startTileY, int widthInTiles,
int heightInTiles) {
}
/**
* Developers can override this method which is called before a layer is
* rendered
*
* To prevent the layer from rendering, return false from this method.
*
* @param g
* The {@link Graphics} context used for rendering
* @param layer
* The {@link GroupLayer} which was just rendered
* @param startTileX
* The x coordinate in tiles where rendering started
* @param startTileY
* The y coordinate in tiles where rendering started
* @param widthInTiles
* The amount of tiles that were rendered along the X axis
* @param heightInTiles
* The amount of tiles that were rendered along the Y axis
* @return True if the layer should be rendered
*/
protected boolean preGroupLayerRendered(Graphics g, GroupLayer layer, int startTileX, int startTileY, int widthInTiles,
int heightInTiles) {
return true;
}
/**
* Developers can override this method to implement sprite rendering
*
* @param g
* The {@link Graphics} context used for rendering
* @param layer
* The {@link GroupLayer} which was just rendered
* @param startTileX
* The x coordinate in tiles where rendering started
* @param startTileY
* The y coordinate in tiles where rendering started
* @param widthInTiles
* The amount of tiles that were rendered along the X axis
* @param heightInTiles
* The amount of tiles that were rendered along the Y axis
*/
protected void onGroupLayerRendered(Graphics g, GroupLayer layer, int startTileX, int startTileY, int widthInTiles,
int heightInTiles) {
}
public void drawTileLayer(Graphics g, TileLayer layer, int renderX, int renderY, int startTileX, int startTileY,
int widthInTiles, int heightInTiles) {
if (!isTilesetTexturesLoaded(true)) {
Mdx.log.error(TiledMap.class.getSimpleName(), "Attempting to render TiledMap without its tilesets loaded");
return;
}
if(STRICT_LAYER_VISIBILITY) {
if(!layer.isVisible()) {
return;
}
}
if (!preTileLayerRendered(g, layer, startTileX, startTileY, widthInTiles, heightInTiles))
return;
tileLayerRenderer.drawLayer(g, layer, renderX, renderY, startTileX, startTileY, widthInTiles, heightInTiles);
onTileLayerRendered(g, layer, startTileX, startTileY, widthInTiles, heightInTiles);
}
private void drawTiledObjectGroup(Graphics g, TiledObjectGroup objectGroup, int renderX, int renderY,
int startTileX, int startTileY, int widthInTiles, int heightInTiles) {
if (tiledObjectGroupRenderer == null) {
return;
}
tiledObjectGroupRenderer.drawObjectGroup(g, objectGroup, renderX, renderY, startTileX, startTileY, widthInTiles,
heightInTiles);
}
public void drawGroupLayer(Graphics g, GroupLayer layer, int renderX, int renderY, int startTileX, int startTileY,
int widthInTiles, int heightInTiles) {
if (!isTilesetTexturesLoaded(true)) {
Mdx.log.error(TiledMap.class.getSimpleName(), "Attempting to render TiledMap without its tilesets loaded");
return;
}
if(STRICT_LAYER_VISIBILITY) {
if(!layer.isVisible()) {
return;
}
}
if (!preGroupLayerRendered(g, layer, startTileX, startTileY, widthInTiles, heightInTiles))
return;
for(Layer childLayer : layer.layers) {
drawLayer(g, childLayer, renderX, renderY, startTileX, startTileY, widthInTiles, heightInTiles);
}
onGroupLayerRendered(g, layer, startTileX, startTileY, widthInTiles, heightInTiles);
}
/**
* Returns if the map contains the specified property
*
* @param propertyName
* The property name to search for
* @return True if the map contains the property
*/
public boolean containsProperty(String propertyName) {
return tiledMapData.containsProperty(propertyName);
}
/**
* Returns the value of a specified property
*
* @param propertyName
* The property name to search for
* @return Null if there is no such property
*/
public String getProperty(String propertyName) {
return tiledMapData.getProperty(propertyName);
}
/**
* Sets the value of a specified property
*
* @param propertyName
* The property name to set the value for
* @param value
* The value of the property to set
*/
public void setProperty(String propertyName, String value) {
tiledMapData.setProperty(propertyName, value);
}
/**
* Returns the {@link TileLayer} with the given name
*
* @param name
* The name to search for
* @return Null if there is no such {@link TileLayer}
*/
public TileLayer getTileLayer(String name) {
return tiledMapData.getTileLayer(name);
}
/**
* Returns the {@link TileLayer} with the given name
*
* @param name The name to search for
* @param recursive False if only the root's immediate child layers should be searched (ignoring descendants)
* @return Null if there is no such {@link TileLayer}
*/
public TileLayer getTileLayer(String name, boolean recursive) {
return tiledMapData.getTileLayer(name, recursive);
}
/**
* Returns the {@link TileLayer} at the given index
*
* @param index
* The index of the layer
* @return Null if the index is out of bounds
*/
public TileLayer getTileLayer(int index) {
return tiledMapData.getTileLayer(index);
}
/**
* Returns the {@link GroupLayer} with the given name
* @param name The name of the layer
* @return Null if the layer does not exist
*/
public GroupLayer getGroupLayer(String name) {
return tiledMapData.getGroupLayer(name);
}
/**
* Returns the {@link GroupLayer} with the given name
* @param name The name of the layer
* @param recursive False if only the root's immediate child layers should be searched (ignoring descendants)
* @return Null if the layer does not exist
*/
public GroupLayer getGroupLayer(String name, boolean recursive) {
return tiledMapData.getGroupLayer(name, recursive);
}
/**
* Returns the {@link GroupLayer} at the given index
* @param index The index of the layer
* @return Null if the index is out of bounds
*/
public GroupLayer getGroupLayer(int index) {
return tiledMapData.getGroupLayer(index);
}
/**
* Returns the {@link TiledObjectGroup} with the given name
*
* @param name
* The name to search for
* @return Null if there is no such {@link TiledObjectGroup}
*/
public TiledObjectGroup getObjectGroup(String name) {
return tiledMapData.getObjectGroup(name);
}
/**
* Returns the {@link TiledObjectGroup} with the given name
*
* @param name The name to search for
* @param recursive False if only the root's immediate layers should be searched (ignoring descendants)
* @return Null if there is no such {@link TiledObjectGroup}
*/
public TiledObjectGroup getObjectGroup(String name, boolean recursive) {
return tiledMapData.getObjectGroup(name, recursive);
}
/**
* Returns all the {@link TiledObjectGroup}s in this map
*
* @return Null if there are no {@link TiledObjectGroup}s
*/
public Iterable getObjectGroups() {
return tiledMapData.getObjectGroups();
}
/**
* Returns the index of the {@link TileLayer} or {@link TiledObjectGroup}
* with the given name
*
* @param name
* The name to search for
* @return -1 if there is no such {@link TileLayer} or
* {@link TiledObjectGroup}
*/
public int getLayerIndex(String name) {
return tiledMapData.getLayerIndex(name);
}
/**
* Returns the index of the {@link TileLayer} or {@link TiledObjectGroup}
* with the given name ignoring upper/lowercase differences
*
* @param name
* The name to search for
* @return -1 if there is no such {@link TileLayer} or
* {@link TiledObjectGroup}
*/
public int getLayerIndexIgnoreCase(String name) {
return tiledMapData.getLayerIndexIgnoreCase(name);
}
/**
* Returns the {@link Tile} for the given tile ID
*
* @param tileId
* The tile ID to search for
* @return Null if there is no {@link Tile} with the given ID
*/
public Tile getTile(int tileId) {
return tiledMapData.getTile(tileId);
}
/**
* Returns the {@link Tile} at the given coordinate on a specific layer
*
* @param x
* The x coordinate (in tiles)
* @param y
* The y coordinate (in tiles)
* @param layer
* The layer index
* @return Null if there is no {@link Tile}
*/
public Tile getTile(int x, int y, int layer) {
return tiledMapData.getTile(x, y, layer);
}
/**
* Releases any resources used by this TiledMap including tilesets
*/
public void dispose() {
dispose(true);
}
/**
* Releases any resources used by this TiledMap
*
* @param disposeTilesets
* True if tilesets should also be disposed
*/
public void dispose(boolean disposeTilesets) {
if (tileLayerRenderer != null) {
tileLayerRenderer.dispose();
}
tiledMapData.dispose(disposeTilesets);
}
/**
* Returns the {@link Orientation} of this map
*
* @return
*/
public Orientation getOrientation() {
return tiledMapData.getOrientation();
}
/**
* Returns the {@link StaggerAxis} of this map
*
* @return Null if there is no value
*/
public StaggerAxis getStaggerAxis() {
return tiledMapData.getStaggerAxis();
}
/**
* Returns the {@link StaggerIndex} of this map
*
* @return Null if there is no value
*/
public StaggerIndex getStaggerIndex() {
return tiledMapData.getStaggerIndex();
}
/**
* Returns the stagger side length of this map
*
* @return -1 if there is no value
*/
public int getSideLength() {
return tiledMapData.getSideLength();
}
/**
* Returns the width of the map in tiles
*
* @return
*/
public int getWidth() {
return tiledMapData.getWidth();
}
/**
* Returns the height of the map in tiles
*
* @return
*/
public int getHeight() {
return tiledMapData.getHeight();
}
/**
* Returns the width of tiles in pixels
*
* @return
*/
public int getTileWidth() {
return tiledMapData.getTileWidth();
}
/**
* Returns the height of tiles in pixels
*
* @return
*/
public int getTileHeight() {
return tiledMapData.getTileHeight();
}
/**
* Returns the width of the map in pixels
*
* @return
*/
public int getPixelWidth() {
return tiledMapData.getPixelWidth();
}
/**
* Return the height of the map in pixels
*
* @return
*/
public int getPixelHeight() {
return tiledMapData.getPixelHeight();
}
/**
* Returns the {@link Tileset}s of this map
*
* @return An empty list if none have been loaded
*/
public Array getTilesets() {
return tiledMapData.getTilesets();
}
/**
* Returns the {@link Layer}s of this map
*
* @return
*/
public Array getLayers() {
return tiledMapData.getLayers();
}
/**
* Returns the total amount of {@link TiledObjectGroup} instances
*
* @return
*/
public int getTotalObjectGroups() {
return tiledMapData.getTotalObjectGroups();
}
/**
* Returns the background {@link Color} of the map
*
* @return null by default
*/
public Color getBackgroundColor() {
return tiledMapData.getBackgroundColor();
}
/**
* Sets the {@link TileLayerRenderer} implementation to use for rendering
*
* @param tileLayerRenderer
* The {@link TileLayerRenderer} to use
*/
public void setTileLayerRenderer(TileLayerRenderer tileLayerRenderer) {
this.tileLayerRenderer = tileLayerRenderer;
}
/**
* Sets the {@link TiledObjectGroupRenderer} implementation to use for
* rendering
*
* @param tiledObjectGroupRenderer
* The {@link TiledObjectGroupRenderer} to use
*/
public void setTiledObjectGroupRenderer(TiledObjectGroupRenderer tiledObjectGroupRenderer) {
this.tiledObjectGroupRenderer = tiledObjectGroupRenderer;
}
/**
* Returns if this map contains animated tiles
*
* @return True if there are animated tiles
*/
public boolean containsAnimatedTiles() {
return tiledMapData.containsAnimatedTiles();
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy