using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using MonoGame.Extended;
using MonoGame.Extended.Tiled;
using ColorExtensions = MLEM.Extensions.ColorExtensions;
namespace MLEM.Extended.Tiled {
///
/// A set of extensions for dealing with MonoGame.Extended tiled maps
///
public static class TiledExtensions {
private static readonly Dictionary StubTilesetTiles = new Dictionary();
///
/// Gets the property with the given key, or null if there is none.
///
/// The set of properties
/// The key by which to get a property
/// The property, or null if there is none
public static string Get(this TiledMapProperties properties, string key) {
properties.TryGetValue(key, out var val);
return val;
}
///
/// Gets a boolean property with the given key, or null if there is none.
///
/// The set of properties
/// The key by which to get a property
/// The boolean property, or false if there is none
public static bool GetBool(this TiledMapProperties properties, string key) {
bool.TryParse(properties.Get(key), out var val);
return val;
}
///
/// Gets a Color property with the given key, or null if there is none.
///
/// The set of properties
/// The key by which to get a property
/// The color property
public static Color GetColor(this TiledMapProperties properties, string key) {
return ColorExtensions.FromHex(properties.Get(key));
}
///
/// Gets a float property with the given key, or null if there is none.
///
/// The set of properties
/// The key by which to get a property
/// The float property, or 0 if there is none
public static float GetFloat(this TiledMapProperties properties, string key) {
float.TryParse(properties.Get(key), NumberStyles.Number, NumberFormatInfo.InvariantInfo, out var val);
return val;
}
///
/// Gets an int property with the given key, or null if there is none.
///
/// The set of properties
/// The key by which to get a property
/// The int property, or 0 if there is none
public static int GetInt(this TiledMapProperties properties, string key) {
int.TryParse(properties.Get(key), NumberStyles.Number, NumberFormatInfo.InvariantInfo, out var val);
return val;
}
///
/// Gets the tileset for the given map tile on the given map.
///
/// The tile
/// The map the tile is on
/// The tileset that the tile came from
public static TiledMapTileset GetTileset(this TiledMapTile tile, TiledMap map) {
return map.GetTilesetByTileGlobalIdentifier(tile.GlobalIdentifier);
}
///
/// Gets the local tile identifier for the given tiled map tile.
/// The local tile identifier is the identifier within the tile's tileset.
///
/// The tile whose identifier to get
/// The tileset the tile is from
/// The map the tile is on
/// The local identifier
public static int GetLocalIdentifier(this TiledMapTile tile, TiledMapTileset tileset, TiledMap map) {
return tile.GlobalIdentifier - map.GetTilesetFirstGlobalIdentifier(tileset);
}
///
/// Gets the global tile identifier for the given tiled map tileset tile.
/// The global tile identifier is the identifier within all of the tile sets that the map has.
///
/// The tile whose global identifier to get
/// The tileset the tile is from
/// The map the tile is on
/// The global identifier
public static int GetGlobalIdentifier(this TiledMapTilesetTile tile, TiledMapTileset tileset, TiledMap map) {
return map.GetTilesetFirstGlobalIdentifier(tileset) + tile.LocalTileIdentifier;
}
///
/// Gets the tileset tile on the given tileset for the given tile.
///
/// The tileset
/// The tile
/// The map the tile is on
/// If a tileset tile has no special properties, there is no pre-made object for it. If this boolean is true, a stub object with no extra data will be created instead of returning null.
/// null if the tile is blank or the tileset tile if there is one or createStub is true
public static TiledMapTilesetTile GetTilesetTile(this TiledMapTileset tileset, TiledMapTile tile, TiledMap map, bool createStub = true) {
if (tile.IsBlank)
return null;
var localId = tile.GetLocalIdentifier(tileset, map);
var tilesetTile = tileset.Tiles.FirstOrDefault(t => t.LocalTileIdentifier == localId);
if (tilesetTile == null && createStub) {
var id = tile.GetLocalIdentifier(tileset, map);
if (!StubTilesetTiles.TryGetValue(id, out tilesetTile)) {
tilesetTile = new TiledMapTilesetTile(id);
StubTilesetTiles.Add(id, tilesetTile);
}
}
return tilesetTile;
}
///
/// Gets the tileset tile on the given tileset for the given tile.
/// If the tileset is already known, you should use instead for performance.
///
/// The tile
/// The map the tile is on
/// If a tileset tile has no special properties, there is no pre-made object for it. If this boolean is true, a stub object with no extra data will be created instead of returning null.
/// null if the tile is blank or the tileset tile if there is one or createStub is true
public static TiledMapTilesetTile GetTilesetTile(this TiledMapTile tile, TiledMap map, bool createStub = true) {
if (tile.IsBlank)
return null;
var tileset = tile.GetTileset(map);
return tileset.GetTilesetTile(tile, map, createStub);
}
///
/// Gets the layer index of the layer with the given name in the array.
///
/// The map
/// The name of the layer
/// The resulting index
public static int GetTileLayerIndex(this TiledMap map, string layerName) {
var layer = map.GetLayer(layerName);
return map.TileLayers.IndexOf(layer);
}
///
/// Returns the tiled map tile at the given location on the layer with the given name.
///
/// The map
/// The name of the layer the tile is on
/// The x coordinate of the tile
/// The y coordinate of the tile
/// The tile at the given location, or default if the layer does not exist
public static TiledMapTile GetTile(this TiledMap map, string layerName, int x, int y) {
var layer = map.GetLayer(layerName);
return layer != null ? layer.GetTile(x, y) : default;
}
///
/// Sets the tiled map tile at the given location to the given global tile identifier.
///
/// The map
/// The name of the layer
/// The x coordinate
/// The y coordinate
/// The tile's global identifier to set
public static void SetTile(this TiledMap map, string layerName, int x, int y, int globalTile) {
var layer = map.GetLayer(layerName);
if (layer != null)
layer.SetTile((ushort) x, (ushort) y, (uint) globalTile);
}
///
/// For an x and y coordinate, returns an enumerable of all of the tiles on each of the map's .
///
/// The map
/// The x coordinate
/// The y coordinate
/// All of the tiles on the map at the given location
public static IEnumerable GetTiles(this TiledMap map, int x, int y) {
foreach (var layer in map.TileLayers) {
var tile = layer.GetTile(x, y);
if (!tile.IsBlank)
yield return tile;
}
}
///
/// Returns the tiled map at the given location on the given layer
///
/// The layer to get the tile from
/// The tile's x coordinate
/// The tile's y coordinate
/// The tiled map tile at the location, or default if the location is out of bounds
public static TiledMapTile GetTile(this TiledMapTileLayer layer, int x, int y) {
return !layer.IsInBounds(x, y) ? default : layer.GetTile((ushort) x, (ushort) y);
}
///
/// Returns the area that a tiled map object covers.
/// The area returned is in percent, meaning that an area that covers a full tile has a size of 1,1.
///
/// The object whose area to get
/// The map
/// The position to add to the object's position
/// The area that the tile covers
public static RectangleF GetArea(this TiledMapObject obj, TiledMap map, Vector2? position = null) {
var tileSize = map.GetTileSize();
var pos = position ?? Vector2.Zero;
return new RectangleF(obj.Position / tileSize + pos, obj.Size / tileSize);
}
///
/// Returns the width and height of a tile on the given map, as a vector.
///
/// The map
/// The width and height of a tile
public static Vector2 GetTileSize(this TiledMap map) {
return new Vector2(map.TileWidth, map.TileHeight);
}
///
/// Returns whether the given position is in the bounds of the layer (that is, if each coordinate is >= 0 and if they are both smaller than the layer's width and height).
///
/// The layer
/// The x coordinate
/// The y coordinate
/// Whether the position is in bounds of the layer
public static bool IsInBounds(this TiledMapTileLayer layer, int x, int y) {
return x >= 0 && y >= 0 && x < layer.Width && y < layer.Height;
}
///
/// Returns all of the objects by the given name, or by the given type, in an object layer.
///
/// The layer whose objects to search
/// The name or type name of the objects to find
/// Whether to search object names
/// Whether to search object types
/// An enumerable of tiled map objects that match the search
public static IEnumerable GetObjects(this TiledMapObjectLayer layer, string id, bool searchName = true, bool searchType = false) {
foreach (var obj in layer.Objects) {
if (searchName && obj.Name == id || searchType && obj.Type == id)
yield return obj;
}
}
///
/// Returns all of the objects by the given name, or by the given type, on the given map.
///
/// The layer whose objects to search
/// The name or type name of the objects to find
/// Whether to search object names
/// Whether to search object types
/// An enumerable of tiled map objects that match the search
public static IEnumerable GetObjects(this TiledMap map, string id, bool searchName = true, bool searchType = false) {
foreach (var layer in map.ObjectLayers) {
foreach (var obj in layer.GetObjects(id, searchName, searchType))
yield return obj;
}
}
///
/// Returns the texture region, as a rectangle, that the given tile uses for rendering.
///
/// The tileset the tile is on
/// The tile
/// The tile's texture region, in pixels.
public static Rectangle GetTextureRegion(this TiledMapTileset tileset, TiledMapTilesetTile tile) {
var id = tile.LocalTileIdentifier;
if (tile is TiledMapTilesetAnimatedTile animated)
id = animated.CurrentAnimationFrame.LocalTileIdentifier;
return tileset.GetTileRegion(id);
}
///
/// Converts a tile's flip settings into .
///
/// The tile whose flip settings to convert
/// The tile's flip settings as sprite effects
public static SpriteEffects GetSpriteEffects(this TiledMapTile tile) {
var flipping = SpriteEffects.None;
if (tile.IsFlippedHorizontally)
flipping |= SpriteEffects.FlipHorizontally;
if (tile.IsFlippedVertically)
flipping |= SpriteEffects.FlipVertically;
return flipping;
}
}
}