private void ParseImageLayerXml(XElement xml) { if (xml.Element("image") == null) { Logger.WriteWarning("Image Layer '{0}' is being ignored since it has no image.", base.Name); base.Ignore = IgnoreSettings.True; } else { Width = 1; Height = 1; string imagePath = TmxHelper.GetAttributeAsFullPath(xml.Element("image"), "source"); TmxTile value = base.ParentMap.Tiles.First((KeyValuePair <uint, TmxTile> t) => t.Value.TmxImage.AbsolutePath.ToLower() == imagePath.ToLower()).Value; Data = new TmxData(this); TmxChunk tmxChunk = new TmxChunk(Data); tmxChunk.X = 0; tmxChunk.Y = 0; tmxChunk.Width = 1; tmxChunk.Height = 1; tmxChunk.TileIds.Add(value.GlobalId); Data.Chunks.Add(tmxChunk); PointF offset = base.Offset; offset.Y -= (float)base.ParentMap.TileHeight; offset.Y += (float)value.TmxImage.Size.Height; PointF pointF = TmxMath.TileCornerInScreenCoordinates(base.ParentMap, 0, 0); offset.X -= pointF.X; offset.Y -= pointF.Y; offset.X += TmxHelper.GetAttributeAsFloat(xml, "x", 0f); offset.Y += TmxHelper.GetAttributeAsFloat(xml, "y", 0f); base.Offset = offset; } }
private RectangleF CalculateBoundary() { RectangleF rcMap = new RectangleF(Point.Empty, this.tmxMap.MapSizeInPixels()); // Take boundaries from object groups var objBounds = from g in this.tmxMap.ObjectGroups from o in g.Objects where o.Visible == true where IsLayerEnabled(g.Name) select o.GetWorldBounds(); // Take boundaries from objects embedded in tiles var tileBounds = from layer in tmxMap.Layers where layer.Visible == true where IsLayerEnabled(layer.DefaultName) from y in Enumerable.Range(0, layer.Height) from x in Enumerable.Range(0, layer.Width) let tileId = layer.GetTileIdAt(x, y) where tileId != 0 let tile = this.tmxMap.Tiles[tileId] from o in tile.ObjectGroup.Objects let bound = o.GetWorldBounds() let point = TmxMath.TileCornerInScreenCoordinates(this.tmxMap, x, y) select new RectangleF(bound.X + point.X, bound.Y + point.Y, bound.Width, bound.Height); var allBounds = objBounds.Concat(tileBounds); var union = allBounds.Aggregate(rcMap, RectangleF.Union); // Inflate a tile size to make room for the grid union.Inflate(this.tmxMap.TileWidth, this.tmxMap.TileHeight); union.Inflate(Tiled2UnityViewer.GridSize, Tiled2UnityViewer.GridSize); return(union); }
private void DrawTiles(Graphics g) { // Load all our tiled images var images = from layer in this.tmxMap.Layers where layer.Properties.GetPropertyValueAsBoolean("unity:collisionOnly", false) == false where layer.Visible == true where IsLayerEnabled(layer.DefaultName) from y in Enumerable.Range(0, layer.Height) from x in Enumerable.Range(0, layer.Width) let tileId = layer.GetTileIdAt(x, y) where tileId != 0 let tile = this.tmxMap.Tiles[tileId] select new { Path = tile.TmxImage.Path, Trans = tile.TmxImage.TransparentColor, }; images = images.Distinct(); Dictionary <string, Bitmap> tileSetBitmaps = new Dictionary <string, Bitmap>(); foreach (var img in images) { Bitmap bmp = (Bitmap)Bitmap.FromFile(img.Path); if (!String.IsNullOrEmpty(img.Trans)) { System.Drawing.Color transColor = System.Drawing.ColorTranslator.FromHtml(img.Trans); bmp.MakeTransparent(transColor); } tileSetBitmaps.Add(img.Path, bmp); } foreach (TmxLayer layer in this.tmxMap.Layers) { if (layer.Visible == false) { continue; } if (IsLayerEnabled(layer.DefaultName) == false) { continue; } if (layer.Properties.GetPropertyValueAsBoolean("unity:collisionOnly", false) == true) { continue; } // The range of x and y depends on the render order of the tiles // By default we draw right and down but may reverse the tiles we visit var range_x = Enumerable.Range(0, layer.Width); var range_y = Enumerable.Range(0, layer.Height); if (this.tmxMap.DrawOrderHorizontal == -1) { range_x = range_x.Reverse(); } if (this.tmxMap.DrawOrderVertical == -1) { range_y = range_y.Reverse(); } // Visit the tiles we are going to draw var tiles = from y in range_y from x in range_x let rawTileId = layer.GetRawTileIdAt(x, y) let tileId = layer.GetTileIdAt(x, y) where tileId != 0 let tile = this.tmxMap.Tiles[tileId] // Support for animated tiles. Just show the first frame of the animation. let frame = (tile.Animation == null) ? tile : this.tmxMap.Tiles[tile.Animation.Frames[0].GlobalTileId] select new { Tile = frame, Position = TmxMath.TileCornerInScreenCoordinates(this.tmxMap, x, y), Bitmap = tileSetBitmaps[frame.TmxImage.Path], IsFlippedDiagnoally = TmxMath.IsTileFlippedDiagonally(rawTileId), IsFlippedHorizontally = TmxMath.IsTileFlippedHorizontally(rawTileId), IsFlippedVertically = TmxMath.IsTileFlippedVertically(rawTileId), }; PointF[] destPoints = new PointF[4]; PointF[] destPoints3 = new PointF[3]; foreach (var t in tiles) { PointF location = t.Position; // Individual tiles may be larger than the given tile size of the overall map location.Y = (t.Position.Y - t.Tile.TileSize.Height) + this.tmxMap.TileHeight; // Make up the 'quad' of texture points and transform them PointF center = new PointF(t.Tile.TileSize.Width * 0.5f, t.Tile.TileSize.Height * 0.5f); destPoints[0] = new Point(0, 0); destPoints[1] = new Point(t.Tile.TileSize.Width, 0); destPoints[2] = new Point(t.Tile.TileSize.Width, t.Tile.TileSize.Height); destPoints[3] = new Point(0, t.Tile.TileSize.Height); // Transform the points based on our flipped flags TmxMath.TransformPoints(destPoints, center, t.IsFlippedDiagnoally, t.IsFlippedHorizontally, t.IsFlippedVertically); // Put the destination points back into world space TmxMath.TranslatePoints(destPoints, location); // Stupid DrawImage function only takes 3 destination points otherwise it throws an exception destPoints3[0] = destPoints[0]; destPoints3[1] = destPoints[1]; destPoints3[2] = destPoints[3]; // Draw the tile Rectangle source = new Rectangle(t.Tile.LocationOnSource, t.Tile.TileSize); g.DrawImage(t.Bitmap, destPoints3, source, GraphicsUnit.Pixel); } } tileSetBitmaps.Clear(); }
private void DrawGridHex(Graphics g) { // Our collection of points to render HashSet <Point> points = new HashSet <Point>(); // Note: borrowed heavily from Tiled source (HexagonalRenderer::drawGrid) int tileWidth = this.tmxMap.TileWidth & ~1; int tileHeight = this.tmxMap.TileHeight & ~1; int sideLengthX = tmxMap.StaggerAxis == TmxMap.MapStaggerAxis.X ? tmxMap.HexSideLength : 0; int sideLengthY = tmxMap.StaggerAxis == TmxMap.MapStaggerAxis.Y ? tmxMap.HexSideLength : 0; int sideOffsetX = (tmxMap.TileWidth - sideLengthX) / 2; int sideOffsetY = (tmxMap.TileHeight - sideLengthY) / 2; int columnWidth = sideOffsetX + sideLengthX; int rowHeight = sideOffsetY + sideLengthY; bool staggerX = this.tmxMap.StaggerAxis == TmxMap.MapStaggerAxis.X; // Determine the tile and pixel coordinates to start at Point startTile = new Point(0, 0); Point startPos = TmxMath.TileCornerInScreenCoordinates(this.tmxMap, startTile.X, startTile.Y); Point[] oct = new Point[8] { new Point(0, tileHeight - sideOffsetY), new Point(0, sideOffsetY), new Point(sideOffsetX, 0), new Point(tileWidth - sideOffsetX, 0), new Point(tileWidth, sideOffsetY), new Point(tileWidth, tileHeight - sideOffsetY), new Point(tileWidth - sideOffsetX, tileHeight), new Point(sideOffsetX, tileHeight) }; if (staggerX) { // Odd row shifting is applied in the rendering loop, so un-apply it here if (TmxMath.DoStaggerX(this.tmxMap, startTile.X)) { startPos.Y -= rowHeight; } for (; startTile.X < this.tmxMap.Width; startTile.X++) { Point rowTile = startTile; Point rowPos = startPos; if (TmxMath.DoStaggerX(this.tmxMap, startTile.X)) { rowPos.Y += rowHeight; } for (; rowTile.Y < this.tmxMap.Height; rowTile.Y++) { points.Add(TmxMath.AddPoints(rowPos, oct[1])); points.Add(TmxMath.AddPoints(rowPos, oct[2])); points.Add(TmxMath.AddPoints(rowPos, oct[3])); points.Add(TmxMath.AddPoints(rowPos, oct[4])); bool isStaggered = TmxMath.DoStaggerX(tmxMap, startTile.X); bool lastRow = rowTile.Y == tmxMap.Height - 1; bool lastColumn = rowTile.X == tmxMap.Width - 1; bool bottomLeft = rowTile.X == 0 || (lastRow && isStaggered); bool bottomRight = lastColumn || (lastRow && isStaggered); if (bottomRight) { points.Add(TmxMath.AddPoints(rowPos, oct[5])); points.Add(TmxMath.AddPoints(rowPos, oct[6])); } if (lastRow) { points.Add(TmxMath.AddPoints(rowPos, oct[6])); points.Add(TmxMath.AddPoints(rowPos, oct[7])); } if (bottomLeft) { points.Add(TmxMath.AddPoints(rowPos, oct[7])); points.Add(TmxMath.AddPoints(rowPos, oct[0])); } rowPos.Y += tileHeight + sideLengthY; } startPos.X += columnWidth; } } else { // Odd row shifting is applied in the rendering loop, so un-apply it here if (TmxMath.DoStaggerY(this.tmxMap, startTile.Y)) { startPos.X -= columnWidth; } for (; startTile.Y < tmxMap.Height; startTile.Y++) { Point rowTile = startTile; Point rowPos = startPos; if (TmxMath.DoStaggerY(this.tmxMap, startTile.Y)) { rowPos.X += columnWidth; } for (; rowTile.X < this.tmxMap.Width; rowTile.X++) { points.Add(TmxMath.AddPoints(rowPos, oct[0])); points.Add(TmxMath.AddPoints(rowPos, oct[1])); points.Add(TmxMath.AddPoints(rowPos, oct[2])); points.Add(TmxMath.AddPoints(rowPos, oct[3])); points.Add(TmxMath.AddPoints(rowPos, oct[4])); bool isStaggered = TmxMath.DoStaggerY(this.tmxMap, startTile.Y); bool lastRow = rowTile.Y == this.tmxMap.Height - 1; bool lastColumn = rowTile.Y == this.tmxMap.Width - 1; bool bottomLeft = lastRow || (rowTile.X == 0 && !isStaggered); bool bottomRight = lastRow || (lastColumn && isStaggered); if (lastColumn) { points.Add(TmxMath.AddPoints(rowPos, oct[4])); points.Add(TmxMath.AddPoints(rowPos, oct[5])); } if (bottomRight) { points.Add(TmxMath.AddPoints(rowPos, oct[5])); points.Add(TmxMath.AddPoints(rowPos, oct[6])); } if (bottomLeft) { points.Add(TmxMath.AddPoints(rowPos, oct[7])); points.Add(TmxMath.AddPoints(rowPos, oct[0])); } rowPos.X += tileWidth + sideLengthX; } startPos.Y += rowHeight; } } foreach (var p in points) { RectangleF rc = new RectangleF(p.X, p.Y, Tiled2UnityViewer.GridSize, Tiled2UnityViewer.GridSize); rc.Offset(-Tiled2UnityViewer.GridSize * 0.5f, -Tiled2UnityViewer.GridSize * 0.5f); g.FillRectangle(Brushes.White, rc); g.DrawRectangle(Pens.Black, rc.X, rc.Y, rc.Width, rc.Height); } }
public static TmxLayer FromXml(XElement elem, TmxLayerNode parent, TmxMap tmxMap) { TmxLayer tmxLayer = new TmxLayer(parent, tmxMap); tmxLayer.FromXmlInternal(elem); // We can build a layer from a "tile layer" (default) or an "image layer" if (elem.Name == "layer") { tmxLayer.Width = TmxHelper.GetAttributeAsInt(elem, "width"); tmxLayer.Height = TmxHelper.GetAttributeAsInt(elem, "height"); tmxLayer.ParseData(elem.Element("data")); } else if (elem.Name == "imagelayer") { XElement xmlImage = elem.Element("image"); if (xmlImage == null) { Logger.WriteWarning("Image Layer '{0}' is being ignored since it has no image.", tmxLayer.Name); tmxLayer.Ignore = IgnoreSettings.True; return(tmxLayer); } // An image layer is sort of like an tile layer but with just one tile tmxLayer.Width = 1; tmxLayer.Height = 1; // Find the "tile" that matches our image string imagePath = TmxHelper.GetAttributeAsFullPath(elem.Element("image"), "source"); TmxTile tile = tmxMap.Tiles.First(t => t.Value.TmxImage.AbsolutePath == imagePath).Value; tmxLayer.TileIds = new uint[1] { tile.GlobalId }; // The image layer needs to be tranlated in an interesting way when expressed as a tile layer PointF translated = tmxLayer.Offset; // Make up for height of a regular tile in the map translated.Y -= (float)tmxMap.TileHeight; // Make up for the height of this image translated.Y += (float)tile.TmxImage.Size.Height; // Correct for any orientation effects on the map (like isometric) // (We essentially undo the translation via orientation here) PointF orientation = TmxMath.TileCornerInScreenCoordinates(tmxMap, 0, 0); translated.X -= orientation.X; translated.Y -= orientation.Y; // Translate by the x and y coordiantes translated.X += TmxHelper.GetAttributeAsFloat(elem, "x", 0); translated.Y += TmxHelper.GetAttributeAsFloat(elem, "y", 0); tmxLayer.Offset = translated; } // Sometimes TMX files have "dead" tiles in them (tiles that were removed but are still referenced) // Remove these tiles from the layer by replacing them with zero for (int t = 0; t < tmxLayer.TileIds.Length; ++t) { uint tileId = tmxLayer.TileIds[t]; tileId = TmxMath.GetTileIdWithoutFlags(tileId); if (!tmxMap.Tiles.ContainsKey(tileId)) { tmxLayer.TileIds[t] = 0; } } // Each layer will be broken down into "meshes" which are collections of tiles matching the same texture or animation tmxLayer.Meshes = TmxMesh.ListFromTmxLayer(tmxLayer); // Each layer may contain different collision types which are themselves put into "Collison Layers" to be processed later tmxLayer.BuildCollisionLayers(); return(tmxLayer); }
public Point GetMapPositionAt(int x, int y) { return(TmxMath.TileCornerInScreenCoordinates(this, x, y)); }
public static TmxLayer FromXml(XElement elem, TmxMap tmxMap) { Program.WriteVerbose(elem.ToString()); TmxLayer tmxLayer = new TmxLayer(tmxMap); // Order within Xml file is import for layer types tmxLayer.XmlElementIndex = elem.NodesBeforeSelf().Count(); // Have to decorate layer names in order to force them into being unique // Also, can't have whitespace in the name because Unity will add underscores tmxLayer.Name = TmxHelper.GetAttributeAsString(elem, "name"); tmxLayer.Visible = TmxHelper.GetAttributeAsInt(elem, "visible", 1) == 1; tmxLayer.Opacity = TmxHelper.GetAttributeAsFloat(elem, "opacity", 1); PointF offset = new PointF(0, 0); offset.X = TmxHelper.GetAttributeAsFloat(elem, "offsetx", 0); offset.Y = TmxHelper.GetAttributeAsFloat(elem, "offsety", 0); tmxLayer.Offset = offset; // Set our properties tmxLayer.Properties = TmxProperties.FromXml(elem); // Set the "ignore" setting on this layer tmxLayer.Ignore = tmxLayer.Properties.GetPropertyValueAsEnum <IgnoreSettings>("unity:ignore", IgnoreSettings.False); // We can build a layer from a "tile layer" (default) or an "image layer" if (elem.Name == "layer") { tmxLayer.Width = TmxHelper.GetAttributeAsInt(elem, "width"); tmxLayer.Height = TmxHelper.GetAttributeAsInt(elem, "height"); tmxLayer.ParseData(elem.Element("data")); } else if (elem.Name == "imagelayer") { XElement xmlImage = elem.Element("image"); if (xmlImage == null) { Program.WriteWarning("Image Layer '{0}' is being ignored since it has no image.", tmxLayer.Name); tmxLayer.Ignore = IgnoreSettings.True; return(tmxLayer); } // An image layer is sort of like an tile layer but with just one tile tmxLayer.Width = 1; tmxLayer.Height = 1; // Find the "tile" that matches our image string imagePath = TmxHelper.GetAttributeAsFullPath(elem.Element("image"), "source"); TmxTile tile = tmxMap.Tiles.First(t => t.Value.TmxImage.AbsolutePath == imagePath).Value; tmxLayer.TileIds = new uint[1] { tile.GlobalId }; // The image layer needs to be tranlated in an interesting way when expressed as a tile layer PointF translated = tmxLayer.Offset; // Make up for height of a regular tile in the map translated.Y -= (float)tmxMap.TileHeight; // Make up for the height of this image translated.Y += (float)tile.TmxImage.Size.Height; // Correct for any orientation effects on the map (like isometric) // (We essentially undo the translation via orientation here) PointF orientation = TmxMath.TileCornerInScreenCoordinates(tmxMap, 0, 0); translated.X -= orientation.X; translated.Y -= orientation.Y; // Translate by the x and y coordiantes translated.X += TmxHelper.GetAttributeAsFloat(elem, "x", 0); translated.Y += TmxHelper.GetAttributeAsFloat(elem, "y", 0); tmxLayer.Offset = translated; } // Each layer will be broken down into "meshes" which are collections of tiles matching the same texture or animation tmxLayer.Meshes = TmxMesh.ListFromTmxLayer(tmxLayer); return(tmxLayer); }
private void DrawTiles(Graphics g) { foreach (TmxLayer layer in this.tmxMap.Layers) { if (layer.Visible == false) { continue; } if (layer.Ignore == TmxLayer.IgnoreSettings.Visual) { continue; } // Set the opacity for the layer ColorMatrix colorMatrix = new ColorMatrix(); colorMatrix.Matrix33 = layer.Opacity; ImageAttributes imageAttributes = new ImageAttributes(); imageAttributes.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); // Translate by the offset GraphicsState state = g.Save(); g.TranslateTransform(layer.Offset.X, layer.Offset.Y); // The range of x and y depends on the render order of the tiles // By default we draw right and down but may reverse the tiles we visit var range_x = Enumerable.Range(0, GetMaxTilesWide(layer)); var range_y = Enumerable.Range(0, GetMaxTilesHigh(layer)); if (this.tmxMap.DrawOrderHorizontal == -1) { range_x = range_x.Reverse(); } if (this.tmxMap.DrawOrderVertical == -1) { range_y = range_y.Reverse(); } // Visit the tiles we are going to draw var tiles = from y in range_y from x in range_x let rawTileId = layer.GetRawTileIdAt(x, y) let tileId = layer.GetTileIdAt(x, y) where tileId != 0 let tile = this.tmxMap.Tiles[tileId] // Support for animated tiles. Just show the first frame of the animation. let frame = this.tmxMap.Tiles[tile.Animation.Frames[0].GlobalTileId] select new { Tile = frame, Position = TmxMath.TileCornerInScreenCoordinates(this.tmxMap, x, y), Bitmap = frame.TmxImage.ImageBitmap, IsFlippedDiagnoally = TmxMath.IsTileFlippedDiagonally(rawTileId), IsFlippedHorizontally = TmxMath.IsTileFlippedHorizontally(rawTileId), IsFlippedVertically = TmxMath.IsTileFlippedVertically(rawTileId), }; PointF[] destPoints = new PointF[4]; PointF[] destPoints3 = new PointF[3]; foreach (var t in tiles) { PointF location = t.Position; // Individual tiles may be larger than the given tile size of the overall map location.Y = (t.Position.Y - t.Tile.TileSize.Height) + this.tmxMap.TileHeight; // Take tile offset into account location.X += t.Tile.Offset.X; location.Y += t.Tile.Offset.Y; // Make up the 'quad' of texture points and transform them PointF center = new PointF(t.Tile.TileSize.Width * 0.5f, t.Tile.TileSize.Height * 0.5f); destPoints[0] = new Point(0, 0); destPoints[1] = new Point(t.Tile.TileSize.Width, 0); destPoints[2] = new Point(t.Tile.TileSize.Width, t.Tile.TileSize.Height); destPoints[3] = new Point(0, t.Tile.TileSize.Height); // Transform the points based on our flipped flags TmxMath.TransformPoints(destPoints, center, t.IsFlippedDiagnoally, t.IsFlippedHorizontally, t.IsFlippedVertically); // Put the destination points back into world space TmxMath.TranslatePoints(destPoints, location); // Stupid DrawImage function only takes 3 destination points otherwise it throws an exception destPoints3[0] = destPoints[0]; destPoints3[1] = destPoints[1]; destPoints3[2] = destPoints[3]; // Draw the tile Rectangle source = new Rectangle(t.Tile.LocationOnSource, t.Tile.TileSize); g.DrawImage(t.Bitmap, destPoints3, source, GraphicsUnit.Pixel, imageAttributes); } g.Restore(state); } }