using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using Microsoft.Xna.Framework; namespace MonoGame.Extended.Tiled { public sealed class TiledMap { private readonly List _imageLayers = new List(); private readonly List _layers = new List(); private readonly Dictionary _layersByName = new Dictionary(); private readonly List _objectLayers = new List(); private readonly List _tileLayers = new List(); private readonly List _tilesets = new List(); private readonly List> _firstGlobalIdentifiers = new List>(); public string Name { get; } public string Type { get; } public int Width { get; } public int Height { get; } public int TileWidth { get; } public int TileHeight { get; } public TiledMapTileDrawOrder RenderOrder { get; } public TiledMapOrientation Orientation { get; } public TiledMapProperties Properties { get; } public ReadOnlyCollection Tilesets { get; } public ReadOnlyCollection Layers { get; } public ReadOnlyCollection ImageLayers { get; } public ReadOnlyCollection TileLayers { get; } public ReadOnlyCollection ObjectLayers { get; } public Color? BackgroundColor { get; set; } public int WidthInPixels => Width * TileWidth; public int HeightInPixels => Height * TileHeight; private TiledMap() { Layers = new ReadOnlyCollection(_layers); ImageLayers = new ReadOnlyCollection(_imageLayers); TileLayers = new ReadOnlyCollection(_tileLayers); ObjectLayers = new ReadOnlyCollection(_objectLayers); Tilesets = new ReadOnlyCollection(_tilesets); Properties = new TiledMapProperties(); } public TiledMap(string name, string type, int width, int height, int tileWidth, int tileHeight, TiledMapTileDrawOrder renderOrder, TiledMapOrientation orientation, Color? backgroundColor = null) : this() { Name = name; Type = type; Width = width; Height = height; TileWidth = tileWidth; TileHeight = tileHeight; RenderOrder = renderOrder; Orientation = orientation; BackgroundColor = backgroundColor; } public void AddTileset(TiledMapTileset tileset, int firstGlobalIdentifier) { _tilesets.Add(tileset); _firstGlobalIdentifiers.Add(new Tuple(tileset, firstGlobalIdentifier)); } public void AddLayer(TiledMapLayer layer) => AddLayer(layer, true); private void AddLayer(TiledMapLayer layer, bool root) { if (root) _layers.Add(layer); if (_layersByName.ContainsKey(layer.Name)) throw new ArgumentException($"The TiledMap '{Name}' contains two or more layers named '{layer.Name}'. Please ensure all layers have unique names."); _layersByName.Add(layer.Name, layer); switch(layer) { case TiledMapImageLayer imageLayer: _imageLayers.Add(imageLayer); break; case TiledMapTileLayer tileLayer: _tileLayers.Add(tileLayer); break; case TiledMapObjectLayer objectLayer: _objectLayers.Add(objectLayer); break; case TiledMapGroupLayer groupLayer: foreach (var subLayer in groupLayer.Layers) AddLayer(subLayer, false); break; } } public TiledMapLayer GetLayer(string layerName) { TiledMapLayer layer; _layersByName.TryGetValue(layerName, out layer); return layer; } public T GetLayer(string layerName) where T : TiledMapLayer { return GetLayer(layerName) as T; } public TiledMapTileset GetTilesetByTileGlobalIdentifier(int tileIdentifier) { foreach (var tileset in _firstGlobalIdentifiers) { if (tileIdentifier >= tileset.Item2 && tileIdentifier < tileset.Item2 + tileset.Item1.TileCount) return tileset.Item1; } return null; } public int GetTilesetFirstGlobalIdentifier(TiledMapTileset tileset) { return _firstGlobalIdentifiers.FirstOrDefault(t => t.Item1 == tileset).Item2; } private static int CountLayers(TiledMapLayer layer) { var value = 0; if (layer is TiledMapGroupLayer groupLayer) foreach (var subLayer in groupLayer.Layers) value += CountLayers(subLayer); else value = 1; return value; } } }