private Rectangle GetLargestSolidTileRectangle(Tile[][,] SolidTiles, BitArray CheckedTiles, int StartX, int StartY) { // Basically, we know we start at the top-level coordinate. // So we increase X until we reach a gap. // At that point, we increase Y and check each tile for that row until EndX. // If we encounter a gap, we set EndX to be where that gap was. // We know that every row above it was valid until that location so no need to start over. // Also, we treat each checked tile as a gap. Otherwise we'd have duplicates. // There's a pretty significant issue here though. // Imagine a scenario such as /** * . . . . . . . * . . . . . . * . . . . . . * . . . . . . */ // How would this be handled? // The result would end up being something like: /** * 1 1 1 2 2 2 2 * 1 1 1 3 3 3 * 1 1 1 3 3 3 * 1 1 1 3 3 3 */ // Which probably doesn't make much sense.. // You can't even reach 3 ever. // So for now we'll just assume there are no gaps. // This is the way that probably makes most sense for our game... // Though this is in the engine which shouldn't make that assumption, but oh well. // TODO: Handle the above. int EndX, EndY; /*for(EndX = StartX; EndX < Scene.TilesInMap.X; EndX++) { if(!Exists(SolidTiles, CheckedTiles, EndX, StartY)) break; } //EndX--; for(EndY = StartY; EndY < Scene.TilesInMap.Y; EndY++) { if(!Exists(SolidTiles, CheckedTiles, StartX, EndY)) break; } //EndY--; for(int x = StartX; x < EndX; x++) { for(int y = StartY; y < EndY; y++) { int Index = (y * (int)Scene.TilesInMap.X + x); Debug.Assert(!CheckedTiles.Get(Index), "Expected no overlapping tiles when using the rectangle tile approach."); CheckedTiles.Set(Index, true); } }*/ // For now, scrapped above and switched to original one. I think it works better. // Can play with it and determine which works better in practice. // Also should probably be able to declare a layer unreachable. // So, first find the largest possible EndX and EndY. This is taken from above. for(EndX = StartX; EndX < Scene.TilesInMap.X; EndX++) { if(!Exists(SolidTiles, CheckedTiles, EndX, StartY)) break; } for(EndY = StartY; EndY < Scene.TilesInMap.Y; EndY++) { if(!Exists(SolidTiles, CheckedTiles, StartX, EndY)) break; } // Now verify no gaps in each row. if there is a gap, lower the EndX. for(int y = StartY; y < EndY; y++) { for(int x = StartX; x < EndX; x++) { if(!Exists(SolidTiles, CheckedTiles, x, y)) { // Found a gap, reduce EndX to the spot we found a gap at. // Then continue on to the next row. EndX = x; break; } } } // Lastly, indicate we checked this rectangle. for(int x = StartX; x < EndX; x++) { for(int y = StartY; y < EndY; y++) { int Index = GetIndex(x, y); Debug.Assert(!CheckedTiles.Get(Index), "Expected no overlapping tiles when using the rectangle tile approach."); CheckedTiles.Set(Index, true); } } return new Rectangle(StartX, StartY, EndX - StartX, EndY - StartY); }
private static List<Layer> ParseLayers(MapDetails Map, List<TextureDetails> Textures) { var Result = new List<Layer>(); foreach(XmlNode LayerNode in Map.MapElement.SelectNodes("layer")) { var DataNode = LayerNode.SelectNodes("data").Item(0); string CompressionFormat = DataNode.Attributes["compression"].Value; string EncodingFormat = DataNode.Attributes["encoding"].Value; if(!CompressionFormat.Equals("gzip", StringComparison.InvariantCultureIgnoreCase) || !EncodingFormat.Equals("base64", StringComparison.InvariantCultureIgnoreCase)) throw new FormatException("Currently the Tmx loader can only handled base-64 zlib tiles."); string Base64Data = DataNode.InnerXml.Trim(); byte[] CompressedData = Convert.FromBase64String(Base64Data); byte[] UncompressedData = new byte[1024]; // NOTE: This must be a multiple of 4. Tile[,] Tiles = new Tile[Map.MapNumTilesWide, Map.MapNumTilesHigh]; int MapIndex = 0; using(var GZipStream = new GZipStream(new MemoryStream(CompressedData), CompressionMode.Decompress, false)) { while(true) { int BytesRead = GZipStream.Read(UncompressedData, 0, UncompressedData.Length); if(BytesRead == 0) break; using(BinaryReader Reader = new BinaryReader(new MemoryStream(UncompressedData))) { for(int i = 0; i < BytesRead; i += 4) { int GID = Reader.ReadInt32(); int MapX = MapIndex % Map.MapNumTilesWide; int MapY = MapIndex / Map.MapNumTilesWide; MapIndex++; if(GID == 0) continue; var Texture = Textures.Last(c => c.StartGID <= GID); int TextureX = (GID - Texture.StartGID) % Texture.NumTilesWide; int TextureY = (GID - Texture.StartGID) / Texture.NumTilesWide; Rectangle SourceRect = new Rectangle(TextureX * Texture.TileWidth, TextureY * Texture.TileHeight, Texture.TileWidth, Texture.TileHeight); Rectangle Location = new Rectangle(MapX * Map.MapTileWidth, MapY * Map.MapTileHeight, Map.MapTileWidth, Map.MapTileHeight); Tile Tile = new Tile(Texture.Texture, SourceRect, Location, new Vector2(MapX, MapY)); Tiles[MapX, MapY] = Tile; } } } } bool IsSolid = true; foreach(XmlNode PropertiesNode in LayerNode.SelectNodes("properties")) { foreach(XmlNode Property in PropertiesNode.SelectNodes("property")) { string Name = Property.Attributes["name"].Value; string Value = Property.Attributes["value"].Value; if(Name.Equals("Solid", StringComparison.InvariantCultureIgnoreCase)) { IsSolid = bool.Parse(Value); } } } Layer Layer = new Layer(new Vector2(Map.MapTileWidth, Map.MapTileHeight), Tiles); Layer.IsSolid = IsSolid; Result.Add(Layer); } return Result; }
private bool Exists(Tile[][,] Tiles, BitArray CheckedTiles, int X, int Y) { foreach(var TileSet in Tiles) { if(TileSet[X, Y] != null) { if(CheckedTiles.Get(GetIndex(X, Y))) continue; return true; } } return false; }
/// <summary> /// Creates a new layer from the given tiles and size. /// </summary> public Layer(Vector2 TileSize, Tile[,] Tiles) { this._Tiles = Tiles; this._Scale = 1; this._TileSize = TileSize; }