using System.Collections.Generic; using UnityEngine.Tilemaps; using UnityEngine; using System; using System.Collections; using System.Linq; using Newtonsoft.Json; using System.Threading.Tasks; namespace GatherAndDefend.LevelEditor { [Serializable] public class TilemapData : IEnumerable { public const int INVISIBLE_LAYER = 6; [SerializeField] private string _key; [SerializeField] private List _tiles; [SerializeField] private bool _isInvisible; [SerializeField] private bool _isCollidable; [SerializeField] private bool _isTrigger; [SerializeField] private int _renderOrder; [SerializeField] private string _renderLayer; [SerializeField] private Vector2 _position; [SerializeField] private Vector2 _scale; public string Key => _key; public async Task LoadToTilemap(Tilemap reference, PlacementAnimationHandler placementAnimation = null, Reference allTilesSpawned = default, Func tileSpawnAcceleration = default) { if (tileSpawnAcceleration == default) tileSpawnAcceleration = () => 1; const int tilesPerSecond = 15; reference.transform.localPosition = _position; reference.transform.localScale = _scale; var rend = reference.GetComponent(); rend.sortingOrder = _renderOrder; rend.sortingLayerName = _renderLayer; if (_isInvisible) rend.gameObject.layer = INVISIBLE_LAYER; if (_isCollidable) { var collision = rend.gameObject.AddComponent(); collision.isTrigger = _isTrigger; } var tasks = new List(); foreach (TileData data in _tiles) { tasks.Add(placementAnimation(data.Position, data.Tile, () => reference.SetTile(data.Position, data.Tile))); await Task.Delay((int)(1000f / (tilesPerSecond * tileSpawnAcceleration()))); } if (allTilesSpawned != null) allTilesSpawned.Value = true; await Task.WhenAll(tasks); } /// /// saves a tilemap into the level object /// /// /// the bounds of the tilemap public void SaveFromTilemap(Tilemap reference) { _key = reference.name; if (_isCollidable = reference.GetComponent()) { _isTrigger = reference.GetComponent().isTrigger; } _isInvisible = reference.gameObject.layer == INVISIBLE_LAYER; _renderLayer = reference.GetComponent().sortingLayerName; _renderOrder = reference.GetComponent().sortingOrder; _position = reference.transform.localPosition; _scale = reference.transform.localScale; _tiles = new List(); BoundsInt bounds = reference.cellBounds; for (int i = bounds.xMin; i <= bounds.xMax; i++) { for (int j = bounds.yMin; j <= bounds.yMax; j++) { Vector3Int position = new Vector3Int(i, j); TileBase tile = reference.GetTile(position); if (!tile) continue; var tileData = new TileData(position, tile); _tiles.Add(tileData); } } } /// /// returns a dictionary representation of the tilemap /// /// public Dictionary ToDictionary() { return new Dictionary() { {nameof(_key), _key }, {nameof(_isInvisible), _isInvisible }, {nameof(_isCollidable), _isCollidable }, {nameof(_isTrigger), _isTrigger }, {nameof(_renderOrder), _renderOrder }, {nameof(_renderLayer), _renderLayer }, {nameof(_position), new float[]{_position.x, _position.y, 0 } }, {nameof(_scale), new float[]{ _scale.x, _scale.y, 0 } }, {nameof(_tiles), _tiles.FindAll(x => !(x.Tile is LevelTile)) .Select(x => new Dictionary() { {nameof(x.Position), new float[] { x.Position.x, x.Position.y, x.Position.z } }, {nameof(x.Tile), x.Tile.name } }).ToArray() } }; } /// /// builds a tilemap from a dictionary representation (from the save file) /// /// /// public static Tilemap FromDictionary(Dictionary dict) { //get all tilemap data var key = dict[nameof(_key)].ToString(); var invisible = dict[nameof(_isInvisible)].ToBool(); var collidable = dict[nameof(_isCollidable)].ToBool(); var trigger = dict[nameof(_isTrigger)].ToBool(); var renderOrder = dict[nameof(_renderOrder)].ToInt(); var renderLayer = dict[nameof(_renderLayer)].ToString(); var position = dict[nameof(_position)].ToVector3(); var scale = dict[nameof(_scale)].ToVector3(); var tiles = dict[nameof(_tiles)]; //get grid var grid = GameObject.FindObjectOfType(); if (!grid) { var levelMgrScript = GameObject.FindObjectOfType(); grid = new GameObject("Grid").AddComponent(); grid.transform.SetParent(levelMgrScript.transform.parent); } //get tilemap by name var tilemap = grid.GetComponentInChildren(key); TilemapRenderer renderer; if (!tilemap) { tilemap = new GameObject(key).AddComponent(); tilemap.tileAnchor = Vector3.zero; tilemap.gameObject.AddComponent(); tilemap.transform.SetParent(grid.transform); } tilemap.transform.localPosition = position; tilemap.transform.localScale = scale; renderer = tilemap.GetComponent(); //populate tilemap according to specs renderer.sortingOrder = renderOrder; renderer.sortingLayerName = renderLayer; if (invisible) tilemap.gameObject.layer = INVISIBLE_LAYER; if (collidable) { tilemap.gameObject.AddComponent().isTrigger = trigger; } //populate tilemaps with non-LevelTile tiles foreach (var tileObj in tiles as IEnumerable) { var tileDict = JsonConvert.DeserializeObject>(tileObj.ToString()); var tileName = tileDict["Tile"].ToString(); var tile = Database.Instance.ScriptableObjects[tileName]; var tilePos = tileDict["Position"].ToVector3(); tilemap.SetTile(Vector3Int.RoundToInt(tilePos), tile as TileBase); } return tilemap; } public IEnumerator GetEnumerator() { return _tiles.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return _tiles.GetEnumerator(); } public TilemapData() { _tiles = new List(); } } }