Now featuring the messy tilemap code! (Tomorrow is refactor day)
							parent
							
								
									c280a688dc
								
							
						
					
					
						commit
						9ec55c4c7e
					
				@ -0,0 +1,21 @@
 | 
			
		||||
namespace SeeNoEvil.Level {
 | 
			
		||||
	public struct Camera {
 | 
			
		||||
		public int width;
 | 
			
		||||
		public int height;
 | 
			
		||||
		public int x;
 | 
			
		||||
		public int y;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    // public class Camera {
 | 
			
		||||
	// 	private Viewport m_dimension; 
 | 
			
		||||
 | 
			
		||||
    //     public Camera(int x, int y) {
 | 
			
		||||
	// 		m_dimension.x = x;
 | 
			
		||||
	// 		m_dimension.y = x;
 | 
			
		||||
    //     }
 | 
			
		||||
 | 
			
		||||
	// 	public Viewport GetDimension() {
 | 
			
		||||
	// 		return m_dimension;
 | 
			
		||||
	// 	}
 | 
			
		||||
    // }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,34 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using SeeNoEvil.Tiled;
 | 
			
		||||
using Microsoft.Xna.Framework;
 | 
			
		||||
using Microsoft.Xna.Framework.Graphics;
 | 
			
		||||
 | 
			
		||||
namespace SeeNoEvil.Level {
 | 
			
		||||
    public class TilemapLevel {
 | 
			
		||||
        private readonly string MapName;
 | 
			
		||||
        private TiledMap Map;
 | 
			
		||||
 | 
			
		||||
        public TilemapLevel(string tilemapName) {
 | 
			
		||||
            MapName = tilemapName;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void LoadMap() {
 | 
			
		||||
			Map = TiledParser.ReadMapJson(MapName);
 | 
			
		||||
		} 
 | 
			
		||||
 | 
			
		||||
		public IEnumerable<string> GetTilesetNames() {
 | 
			
		||||
			return Map.GetTilesetNames();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void Draw(Camera viewport, SpriteBatch spritebatch, IDictionary<string, Texture2D> this_sucks) {
 | 
			
		||||
			IEnumerable<TileLocation> locations = Map.DrawView(viewport);
 | 
			
		||||
			locations.ToList().ForEach(tile => {
 | 
			
		||||
				Texture2D this_one;
 | 
			
		||||
				if(tile.tile.gid > 0 && this_sucks.TryGetValue(tile.tile.setName, out this_one)) {
 | 
			
		||||
					spritebatch.Draw(this_one, tile.location, tile.tile.srcRectangle, Color.White);
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,234 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using Microsoft.Xna.Framework;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using SeeNoEvil.Level;
 | 
			
		||||
using System.Text.Json.Serialization;
 | 
			
		||||
 | 
			
		||||
namespace SeeNoEvil.Tiled {
 | 
			
		||||
    public class TiledMap {
 | 
			
		||||
        public TiledMap() => TileCache = new Dictionary<uint, Tile>();
 | 
			
		||||
 | 
			
		||||
        public bool Infinite {get; set;}
 | 
			
		||||
        public IEnumerable<MapLayer> Layers {get; set;}
 | 
			
		||||
		public IEnumerable<TileSet> TileSets {get; set;}
 | 
			
		||||
		public int TileHeight {get; set;}
 | 
			
		||||
		public int TileWidth {get; set;}
 | 
			
		||||
		private Dictionary<uint, Tile> TileCache {get; set;}
 | 
			
		||||
 | 
			
		||||
		public IEnumerable<TileLocation> DrawView(Camera viewport) {
 | 
			
		||||
			Dictionary<string, IEnumerable<DataCoordinate>> layerData = new Dictionary<string, IEnumerable<DataCoordinate>>();
 | 
			
		||||
			Layers.Where(layer => layer.Type == "tilelayer").ToList()
 | 
			
		||||
				.ForEach(layer => {
 | 
			
		||||
					layerData.Add(layer.Name, layer.GetVisibleTiles(viewport, TileHeight, TileWidth));
 | 
			
		||||
				});
 | 
			
		||||
			HashSet<uint> gids = layerData.Aggregate(new HashSet<uint>(), 
 | 
			
		||||
				(tiles, layer) => {
 | 
			
		||||
					layer.Value.ToList().ForEach(tile => tiles.Add(tile.gid));
 | 
			
		||||
					return tiles;
 | 
			
		||||
				});
 | 
			
		||||
			IDictionary<uint, Tile> tiles = GetTilesetTiles(gids);
 | 
			
		||||
			// return layerData.Aggregate(new List<TileLocation>(),
 | 
			
		||||
			// 	(locations, layer) => {
 | 
			
		||||
			// 		layer.Value.ToList().ForEach(coord => {
 | 
			
		||||
			// 			Tile currTile;
 | 
			
		||||
			// 			if(!tiles.TryGetValue(coord.gid, out currTile)) {
 | 
			
		||||
			// 				currTile = new Tile();
 | 
			
		||||
			// 			}
 | 
			
		||||
			// 			Vector2 pxLocation = new Vector2(coord.x*TileWidth, coord.y*TileHeight);
 | 
			
		||||
			// 			locations.Add(new TileLocation(currTile, pxLocation));
 | 
			
		||||
			// 		});
 | 
			
		||||
			// 		return locations;
 | 
			
		||||
			// 	});
 | 
			
		||||
			int column = 0, row = 0, columnPx = 0, rowPx = 0;
 | 
			
		||||
			int viewportRows = viewport.height / TileHeight;
 | 
			
		||||
			int viewportColumns = viewport.width / TileWidth;
 | 
			
		||||
			return layerData.Aggregate(new List<TileLocation>(),
 | 
			
		||||
				(locations, layer) => {
 | 
			
		||||
					layer.Value.ToList().ForEach(coord => {
 | 
			
		||||
						Tile currTile;
 | 
			
		||||
						if(!tiles.TryGetValue(coord.gid, out currTile)) {
 | 
			
		||||
							currTile = new Tile();
 | 
			
		||||
						}
 | 
			
		||||
						Vector2 pxLocation = new Vector2(columnPx, rowPx);
 | 
			
		||||
						locations.Add(new TileLocation(currTile, pxLocation));
 | 
			
		||||
						if(column == viewportColumns) {
 | 
			
		||||
							row++;
 | 
			
		||||
							rowPx += TileHeight;
 | 
			
		||||
							column = columnPx = 0;
 | 
			
		||||
						} else {
 | 
			
		||||
							column++;
 | 
			
		||||
							columnPx += TileWidth;
 | 
			
		||||
						}
 | 
			
		||||
					});
 | 
			
		||||
					return locations;
 | 
			
		||||
				});
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public IEnumerable<string> GetTilesetNames() =>
 | 
			
		||||
			TileSets.Aggregate(new List<string>(), 
 | 
			
		||||
				(names, tileset) => {
 | 
			
		||||
					names.Add(tileset.GetContentName());
 | 
			
		||||
					return names;
 | 
			
		||||
				});
 | 
			
		||||
 | 
			
		||||
		private IDictionary<uint, Tile> GetTilesetTiles(HashSet<uint> tiles) {
 | 
			
		||||
			Dictionary<uint, Tile> loadedTiles = new Dictionary<uint, Tile>();
 | 
			
		||||
            tiles.ToList().ForEach(gid => {
 | 
			
		||||
				TileSet tileset = TileSets.FirstOrDefault(set => set.ContainsTile(gid));
 | 
			
		||||
				Tile tile = tileset == null ? new Tile() : tileset.GetTile(gid);
 | 
			
		||||
				loadedTiles.Add(gid, tile);
 | 
			
		||||
			});
 | 
			
		||||
			return loadedTiles;
 | 
			
		||||
		}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	public struct TileLocation {
 | 
			
		||||
        public TileLocation(Tile tile, Vector2 location) {
 | 
			
		||||
            this.tile = tile;
 | 
			
		||||
            this.location = location;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
		public Tile tile;
 | 
			
		||||
		public Vector2 location;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	public struct Tile {
 | 
			
		||||
		public Tile(long _gid, Rectangle _srcRectangle, string _setName) {
 | 
			
		||||
			gid = (uint)_gid;
 | 
			
		||||
			srcRectangle = _srcRectangle;
 | 
			
		||||
			setName = _setName;
 | 
			
		||||
		}
 | 
			
		||||
		public uint gid;
 | 
			
		||||
		public Rectangle srcRectangle;
 | 
			
		||||
		public string setName;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public class TileSet {
 | 
			
		||||
		public TileSet() {
 | 
			
		||||
			TilesLoaded = false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
        public string Image {get; set;}
 | 
			
		||||
		public string Name {get; set;}
 | 
			
		||||
		public int ImageHeight {get; set;}
 | 
			
		||||
		public int ImageWidth {get; set;}
 | 
			
		||||
		public int TileHeight {get; set;}
 | 
			
		||||
		public int TileWidth {get; set;}
 | 
			
		||||
		public int Spacing {get; set;}
 | 
			
		||||
		public int Columns {get; set;}
 | 
			
		||||
		public int FirstGid {get; set;}
 | 
			
		||||
		public int TileCount {get; set;}
 | 
			
		||||
		private IDictionary<uint, Tile> Tiles {get; set;}
 | 
			
		||||
		private bool TilesLoaded {get; set;}
 | 
			
		||||
 | 
			
		||||
		public Tile GetTile(uint gid) {
 | 
			
		||||
			if(!TilesLoaded) {
 | 
			
		||||
				LoadTiles();
 | 
			
		||||
			}
 | 
			
		||||
			Tile result;
 | 
			
		||||
			Tiles.TryGetValue(gid, out result);
 | 
			
		||||
			return result;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool ContainsTile(uint gid) {
 | 
			
		||||
			return !(gid < FirstGid || 
 | 
			
		||||
					gid > (FirstGid + TileCount - 1));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public string GetContentName() {
 | 
			
		||||
			return Name;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private void LoadTiles() {
 | 
			
		||||
			Tiles = new Dictionary<uint, Tile>();
 | 
			
		||||
			int row = 0;
 | 
			
		||||
			int rowPx = 0;
 | 
			
		||||
			int column = 0;
 | 
			
		||||
			int columnPx = 0;
 | 
			
		||||
			for(int i = 0; i < TileCount; i++) {
 | 
			
		||||
				Rectangle rectangle = new Rectangle(
 | 
			
		||||
					columnPx,
 | 
			
		||||
					rowPx,
 | 
			
		||||
                    TileWidth,
 | 
			
		||||
                    TileHeight
 | 
			
		||||
				);
 | 
			
		||||
				uint gid = (uint)(i + FirstGid);
 | 
			
		||||
				Tiles.Add(gid, new Tile(gid, rectangle, Name));
 | 
			
		||||
				if(column == Columns-1) {
 | 
			
		||||
					row++;
 | 
			
		||||
					rowPx += Spacing + TileHeight;
 | 
			
		||||
					column = 0;
 | 
			
		||||
					columnPx = 0;
 | 
			
		||||
				} else {
 | 
			
		||||
					column++;
 | 
			
		||||
					columnPx += Spacing + TileWidth;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			TilesLoaded = true;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public struct DataCoordinate {
 | 
			
		||||
		public DataCoordinate(int _x, int _y, uint _gid) {
 | 
			
		||||
			x = _x;
 | 
			
		||||
			y = _y;
 | 
			
		||||
			gid = _gid;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public int x;
 | 
			
		||||
		public int y;
 | 
			
		||||
		public uint gid;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public class MapLayer {
 | 
			
		||||
        public MapLayer() { }
 | 
			
		||||
 | 
			
		||||
		public string Name {get; set;}
 | 
			
		||||
		public int Width {get; set;}
 | 
			
		||||
		public int Height {get; set;}
 | 
			
		||||
		public IEnumerable<uint> Data {get; set;}
 | 
			
		||||
		public string Type {get; set;}
 | 
			
		||||
		public IEnumerable<DataCoordinate> DataCoordinates {get; set;}
 | 
			
		||||
		public bool BuiltCoordinates {get; private set;}
 | 
			
		||||
 | 
			
		||||
		public IEnumerable<DataCoordinate> GetVisibleTiles(Camera viewport, int tileHeight, int tileWidth) {
 | 
			
		||||
			if(!BuiltCoordinates) {
 | 
			
		||||
				BuildCoordinates();
 | 
			
		||||
			}
 | 
			
		||||
			int startColumn = viewport.x / tileWidth;
 | 
			
		||||
			int endColumn = startColumn + (viewport.width / tileWidth);
 | 
			
		||||
			int startRow = viewport.y / tileHeight;
 | 
			
		||||
			int endRow = startRow + (viewport.height / tileHeight);
 | 
			
		||||
 | 
			
		||||
			var coords = DataCoordinates.Where(coord =>
 | 
			
		||||
				startRow <= coord.y &&
 | 
			
		||||
				endRow >= coord.y &&
 | 
			
		||||
				startColumn <= coord.x &&
 | 
			
		||||
				endColumn >= coord.x
 | 
			
		||||
			).ToList();
 | 
			
		||||
 | 
			
		||||
			return DataCoordinates.Where(coord =>
 | 
			
		||||
				startRow <= coord.y &&
 | 
			
		||||
				endRow >= coord.y &&
 | 
			
		||||
				startColumn <= coord.x &&
 | 
			
		||||
				endColumn >= coord.x
 | 
			
		||||
			);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private void BuildCoordinates() {
 | 
			
		||||
			int row = 0;
 | 
			
		||||
			int column = 0;
 | 
			
		||||
			List<DataCoordinate> coordinates = new List<DataCoordinate>();
 | 
			
		||||
			Data.ToList().ForEach(gid => {
 | 
			
		||||
				coordinates.Add(new DataCoordinate(column, row, gid));
 | 
			
		||||
				if(column == Width-1) {
 | 
			
		||||
					row++;
 | 
			
		||||
					column = 0;
 | 
			
		||||
				} else column++;
 | 
			
		||||
			});
 | 
			
		||||
			DataCoordinates = coordinates;
 | 
			
		||||
			BuiltCoordinates = true;
 | 
			
		||||
		}
 | 
			
		||||
    }    
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,15 @@
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Text.Json;
 | 
			
		||||
 | 
			
		||||
namespace SeeNoEvil.Tiled {
 | 
			
		||||
    public static class TiledParser {
 | 
			
		||||
        public static TiledMap ReadMapJson(string fileName) {
 | 
			
		||||
			StreamReader streamReader = File.OpenText(fileName);
 | 
			
		||||
			string text = streamReader.ReadToEnd();
 | 
			
		||||
			var options = new JsonSerializerOptions {
 | 
			
		||||
				PropertyNameCaseInsensitive = true,
 | 
			
		||||
			};
 | 
			
		||||
			return JsonSerializer.Deserialize<TiledMap>(text, options);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
					Loading…
					
					
				
		Reference in New Issue