Example #1
0
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="game"></param>
        /// <param name="level">TMX level</param>
        public Engine(Game game, XmlReader level)
            : base(game)
        {
            _level = level;
            // Parse XML data
            while (_level.Read()) {
                var name = _level.Name;

                switch (_level.NodeType)
                {
                    case XmlNodeType.Element:
                        switch (name)
                        {
                            // Map - Root level
                            case "map":
                                // Extract map width, height, tilewidth and tileheight
                                _width = int.Parse(_level.GetAttribute("width"));
                                _height = int.Parse(_level.GetAttribute("height"));
                                _tileWidth = int.Parse(_level.GetAttribute("tilewidth"));
                                _tileHeight = int.Parse(_level.GetAttribute("tileheight"));
                                break;
                            // TileSet
                            case "tileset":
                                // Create a new tileset
                                _tileSet = new TileSet(_level.ReadSubtree(), game);
                                break;
                            // Layer
                            case "layer":
                                // Create a new layer
                                _layers.Add(new Layer(_level.ReadSubtree(), this, _tileSet));
                                break;
                            // Objectgroups (Object layers, Start, Win and Timer)
                            case "objectgroup":
                                switch (_level.GetAttribute("name"))
                                {
                                    // Start object layer
                                    case "Start":
                                        _level.ReadToDescendant("object");
                                        if (_level.Name == "object")
                                        {
                                            // Extract start position (x,y)
                                            _startX = int.Parse(_level.GetAttribute("x"));
                                            _startY = int.Parse(_level.GetAttribute("y"));
                                        }
                                        break;
                                    // Win object layer
                                    case "Win":
                                        _level.ReadToDescendant("object");
                                        if (_level.Name == "object")
                                        {
                                            // Create win rectangle based on object size
                                            _winRect = new Rectangle(
                                                int.Parse(_level.GetAttribute("x")),
                                                int.Parse(_level.GetAttribute("y")),
                                                int.Parse(_level.GetAttribute("width")),
                                                int.Parse(_level.GetAttribute("height"))
                                            );
                                        }
                                        break;
                                    // Timer object layer
                                    case "Timer":
                                        XmlReader properties = _level.ReadSubtree();
                                        while (properties.Read())
                                        {
                                            // Read timer properties and extract time value
                                            if (properties.Name == "property" && properties.GetAttribute("name") == "Timer")
                                            {
                                                _timeInSecondsTotal = double.Parse(properties.GetAttribute("value"));
                                            }
                                        }
                                        break;
                                }
                                break;
                        }
                        break;
                }
            }
        }
Example #2
0
        /// <summary>
        /// Constructor. Parses the LAYER part of the TMX map file. There can be many layers.
        /// </summary>
        /// <param name="xml">Assumes the LAYER part of the tmx map file</param>
        /// <param name="engine"></param>
        /// <param name="tileSet"></param>
        public Layer(XmlReader xml, Engine engine, TileSet tileSet)
        {
            // Move xml ahead
            xml.Read();
            // Read in layer name
            _name = xml.GetAttribute("name");
            // Read in layer width and height
            _width = int.Parse(xml.GetAttribute("width"));
            _height = int.Parse(xml.GetAttribute("height"));

            // Parse the layer block
            while (xml.Read())
            {
                switch (xml.Name)
                {
                    // We currently only support the data block for tile layers, properties are thus ignored
                    case "data":
                        // We create a byte buffer to read in the base64 encoded data, which may or may not be compressed
                        int dataSize = (_width * _height * 4) + 1024;
                        var buffer = new byte[dataSize];
                        if (xml.CanReadBinaryContent)
                        {
                            // Read base64 content info buffer
                            xml.ReadElementContentAsBase64(buffer, 0, dataSize);
                            // We create a memory stream of the buffer
                            Stream stream = new MemoryStream(buffer, false);

                            // At this point it would be natural to check for gzip, zlib or uncompressed xml data since these are all options in Tiled
                            // However, due to time constraints I've only implemented the default setting, zlib compressed base64 encoded data.
                            // The first two bytes are Zlib specific identifiers, we skip those before decompressing
                            stream.ReadByte();
                            stream.ReadByte();
                            stream = new DeflateStream(stream, CompressionMode.Decompress);

                            // At this point we have a decompressed base64 stream which we need to "parse".
                            // For that we use a binary reader to read out the tile ids within the layer.
                            // In pure XML, layer data is just a long list of tile ids which represent the tile within the tileset used.
                            // So we need to loop through the layer width by height, as each tile is listed in this order.
                            using (stream)
                            using (var br = new BinaryReader(stream))
                            {
                                // Loop layer height
                                for (int y = 0; y < _height; y++)
                                {
                                    // Loop layer width
                                    for (int x = 0; x < _width; x++)
                                    {
                                        // tileId represent the tile in the tileset
                                        int tileId = br.ReadInt32();
                                        // Tile id 0 means nothing was "painted" in this tile so we skip that.
                                        if (tileId > 0)
                                        {
                                            // Get the TileSetTile using the id we extracted
                                            TileSetTile t = tileSet.getTileById(tileId);
                                            if (t is TileSetTile)
                                            {
                                                // At this point we check if this tile has a collidable property, if so, we create a new collidable and add to the engine collidable list.
                                                if (t.getProperty("Collidable") is string && t.getProperty("Collidable").Equals("True"))
                                                {
                                                    engine.AddCollidable(
                                                        new Collidable(
                                                            new Rectangle(
                                                                x * tileSet.tileWidth,
                                                                y * tileSet.tileHeight,
                                                                tileSet.tileWidth,
                                                                tileSet.tileHeight
                                                            )
                                                        )
                                                    );
                                                }
                                                // Add the new layertile to the layer list of tiles
                                                _layerTiles.Add(new LayerTile(t, x, y));
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        break;
                }
            }
        }