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);
        }
Beispiel #2
0
        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;
 }
Beispiel #4
0
 /// <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;
 }