public static TmxObject FromXml(XElement xml, TmxObjectGroup tmxObjectGroup, TmxMap tmxMap) { Logger.WriteVerbose("Parsing object ..."); uint attributeAsUInt = TmxHelper.GetAttributeAsUInt(xml, "tid", 0u); if (attributeAsUInt != 0 && tmxMap.Templates.TryGetValue(attributeAsUInt, out TgxTemplate value)) { xml = value.Templatize(xml); tmxMap = value.TemplateGroupMap; } TmxObject tmxObject = null; if (xml.Element("ellipse") != null) { tmxObject = new TmxObjectEllipse(); } else if (xml.Element("polygon") != null) { tmxObject = new TmxObjectPolygon(); } else if (xml.Element("polyline") != null) { tmxObject = new TmxObjectPolyline(); } else if (xml.Attribute("gid") != null) { uint attributeAsUInt2 = TmxHelper.GetAttributeAsUInt(xml, "gid"); attributeAsUInt2 = TmxMath.GetTileIdWithoutFlags(attributeAsUInt2); if (tmxMap.Tiles.ContainsKey(attributeAsUInt2)) { tmxObject = new TmxObjectTile(); } else { Logger.WriteWarning("Tile Id {0} not found in tilesets. Using a rectangle instead.\n{1}", attributeAsUInt2, xml.ToString()); tmxObject = new TmxObjectRectangle(); } } else { tmxObject = new TmxObjectRectangle(); } tmxObject.Id = TmxHelper.GetAttributeAsInt(xml, "id", 0); tmxObject.Name = TmxHelper.GetAttributeAsString(xml, "name", ""); tmxObject.Type = TmxHelper.GetAttributeAsString(xml, "type", ""); tmxObject.Visible = (TmxHelper.GetAttributeAsInt(xml, "visible", 1) == 1); tmxObject.ParentObjectGroup = tmxObjectGroup; float attributeAsFloat = TmxHelper.GetAttributeAsFloat(xml, "x"); float attributeAsFloat2 = TmxHelper.GetAttributeAsFloat(xml, "y"); float attributeAsFloat3 = TmxHelper.GetAttributeAsFloat(xml, "width", 0f); float attributeAsFloat4 = TmxHelper.GetAttributeAsFloat(xml, "height", 0f); float attributeAsFloat5 = TmxHelper.GetAttributeAsFloat(xml, "rotation", 0f); tmxObject.Position = new PointF(attributeAsFloat, attributeAsFloat2); tmxObject.Size = new SizeF(attributeAsFloat3, attributeAsFloat4); tmxObject.Rotation = attributeAsFloat5; tmxObject.Properties = TmxProperties.FromXml(xml); tmxObject.InternalFromXml(xml, tmxMap); return(tmxObject); }
public void VisitObject(TmxObject obj) { // Objects only increase draw order if they are tiles if (obj is TmxObjectTile) { TmxObjectTile tile = obj as TmxObjectTile; tile.DrawOrderIndex = this.drawOrderIndex++; } }
private void DrawObjectCollider(Graphics g, TmxObject tmxObject, Color color) { Color brushColor = Color.FromArgb(128, color); using (Brush brush = new HatchBrush(HatchStyle.BackwardDiagonal, color, brushColor)) using (Pen pen = new Pen(color)) { pen.Alignment = PenAlignment.Inset; GraphicsState state = g.Save(); g.TranslateTransform(tmxObject.Position.X, tmxObject.Position.Y); g.RotateTransform(tmxObject.Rotation); if (tmxObject.GetType() == typeof(TmxObjectPolygon)) { DrawPolygon(g, pen, brush, tmxObject as TmxObjectPolygon); } else if (tmxObject.GetType() == typeof(TmxObjectRectangle)) { // Rectangles are polygons DrawPolygon(g, pen, brush, tmxObject as TmxObjectPolygon); } else if (tmxObject.GetType() == typeof(TmxObjectEllipse)) { DrawEllipse(g, pen, brush, tmxObject as TmxObjectEllipse); } else if (tmxObject.GetType() == typeof(TmxObjectPolyline)) { DrawPolyline(g, pen, tmxObject as TmxObjectPolyline); } else if (tmxObject.GetType() == typeof(TmxObjectTile)) { TmxObjectTile tmxObjectTile = tmxObject as TmxObjectTile; RectangleF rcTile = new RectangleF(); rcTile.X = 0; rcTile.Y = -tmxObjectTile.Tile.TileSize.Height; rcTile.Size = tmxObjectTile.Tile.TileSize; g.FillRectangle(brush, rcTile); g.DrawRectangle(pen, rcTile.X, rcTile.Y, rcTile.Width - 1, rcTile.Height - 1); } else { g.Restore(state); RectangleF bounds = tmxObject.GetWorldBounds(); g.FillRectangle(Brushes.Red, bounds.X, bounds.Y, bounds.Width, bounds.Height); g.DrawRectangle(Pens.White, bounds.X, bounds.Y, bounds.Width, bounds.Height); string message = String.Format("Unhandled object: {0}", tmxObject.GetNonEmptyName()); DrawString(g, message, bounds.X, bounds.Y); } // Restore our state g.Restore(state); } }
public static TmxObject FromXml(XElement xml, TmxObjectGroup tmxObjectGroup, TmxMap tmxMap) { Program.WriteLine("Parsing object ..."); Program.WriteVerbose(xml.ToString()); // What kind of TmxObject are we creating? TmxObject tmxObject = null; if (xml.Element("ellipse") != null) { tmxObject = new TmxObjectEllipse(); } else if (xml.Element("polygon") != null) { tmxObject = new TmxObjectPolygon(); } else if (xml.Element("polyline") != null) { tmxObject = new TmxObjectPolyline(); } else if (xml.Attribute("gid") != null) { tmxObject = new TmxObjectTile(); } else { // Just a rectangle tmxObject = new TmxObjectRectangle(); } // Data found on every object type tmxObject.Name = TmxHelper.GetAttributeAsString(xml, "name", ""); tmxObject.Type = TmxHelper.GetAttributeAsString(xml, "type", ""); tmxObject.Visible = TmxHelper.GetAttributeAsInt(xml, "visible", 1) == 1; tmxObject.ParentObjectGroup = tmxObjectGroup; float x = TmxHelper.GetAttributeAsFloat(xml, "x"); float y = TmxHelper.GetAttributeAsFloat(xml, "y"); float w = TmxHelper.GetAttributeAsFloat(xml, "width", 0); float h = TmxHelper.GetAttributeAsFloat(xml, "height", 0); float r = TmxHelper.GetAttributeAsFloat(xml, "rotation", 0); tmxObject.Position = new System.Drawing.PointF(x, y); tmxObject.Size = new System.Drawing.SizeF(w, h); tmxObject.Rotation = r; tmxObject.Properties = TmxProperties.FromXml(xml); tmxObject.InternalFromXml(xml, tmxMap); return(tmxObject); }
public static TmxObject FromXml(XElement xml, TmxObjectGroup tmxObjectGroup, TmxMap tmxMap) { Program.WriteLine("Parsing object ..."); Program.WriteVerbose(xml.ToString()); // What kind of TmxObject are we creating? TmxObject tmxObject = null; if (xml.Element("ellipse") != null) { tmxObject = new TmxObjectEllipse(); } else if (xml.Element("polygon") != null) { tmxObject = new TmxObjectPolygon(); } else if (xml.Element("polyline") != null) { tmxObject = new TmxObjectPolyline(); } else if (xml.Attribute("gid") != null) { tmxObject = new TmxObjectTile(); } else { // Just a rectangle tmxObject = new TmxObjectRectangle(); } // Data found on every object type tmxObject.Name = TmxHelper.GetAttributeAsString(xml, "name", ""); tmxObject.Type = TmxHelper.GetAttributeAsString(xml, "type", ""); tmxObject.Visible = TmxHelper.GetAttributeAsInt(xml, "visible", 1) == 1; tmxObject.ParentObjectGroup = tmxObjectGroup; float x = TmxHelper.GetAttributeAsFloat(xml, "x"); float y = TmxHelper.GetAttributeAsFloat(xml, "y"); float w = TmxHelper.GetAttributeAsFloat(xml, "width", 0); float h = TmxHelper.GetAttributeAsFloat(xml, "height", 0); float r = TmxHelper.GetAttributeAsFloat(xml, "rotation", 0); tmxObject.Position = new System.Drawing.PointF(x, y); tmxObject.Size = new System.Drawing.SizeF(w, h); tmxObject.Rotation = r; tmxObject.Properties = TmxProperties.FromXml(xml); tmxObject.InternalFromXml(xml, tmxMap); return tmxObject; }
private void AddTileObjectElements(TmxObjectTile tmxTile, XElement xmlTileObject) { // We combine the properties of the tile that is referenced and add it to our own properties AssignTiledProperties(tmxTile.Tile, xmlTileObject); // Add any colliders that might be on the tile foreach (TmxObject tmxObject in tmxTile.Tile.ObjectGroup.Objects) { // All the objects/colliders in our object group need to be separate game objects because they can have unique tags/layers XElement xmlObject = new XElement("GameObject", new XAttribute("name", tmxObject.GetNonEmptyName())); // Transform object locaction into map space (needed for isometric and hex modes) PointF xfPosition = TmxMath.ObjectPointFToMapSpace(this.tmxMap, tmxObject.Position); Vector3D pos = PointFToUnityVector(xfPosition); xmlObject.SetAttributeValue("x", pos.X); xmlObject.SetAttributeValue("y", pos.Y); xmlObject.SetAttributeValue("rotation", tmxObject.Rotation); XElement objElement = null; if (tmxObject.GetType() == typeof(TmxObjectRectangle)) { // Note: Tile objects have orthographic rectangles even in isometric orientations so no need to transform rectangle points objElement = CreateBoxColliderElement(tmxObject as TmxObjectRectangle); } else if (tmxObject.GetType() == typeof(TmxObjectEllipse)) { objElement = CreateCircleColliderElement(tmxObject as TmxObjectEllipse, tmxTile.Tile.ObjectGroup.Name); } else if (tmxObject.GetType() == typeof(TmxObjectPolygon)) { objElement = CreatePolygonColliderElement(tmxObject as TmxObjectPolygon); } else if (tmxObject.GetType() == typeof(TmxObjectPolyline)) { objElement = CreateEdgeColliderElement(tmxObject as TmxObjectPolyline); } if (objElement != null) { xmlTileObject.Add(objElement); } } }
private void AddTileObjectElements(TmxObjectTile tmxTile, XElement xmlTileObject) { // We combine the properties of the tile that is referenced and add it to our own properties AssignTiledProperties(tmxTile.Tile, xmlTileObject); // Add any colliders that might be on the tile foreach (TmxObject tmxObject in tmxTile.Tile.ObjectGroup.Objects) { // All the objects/colliders in our object group need to be separate game objects because they can have unique tags/layers XElement xmlObject = new XElement("GameObject", new XAttribute("name", tmxObject.GetNonEmptyName())); Vector3D pos = PointFToUnityVector(tmxObject.Position); xmlObject.SetAttributeValue("x", pos.X); xmlObject.SetAttributeValue("y", pos.Y); xmlObject.SetAttributeValue("rotation", tmxObject.Rotation); XElement objElement = null; if (tmxObject.GetType() == typeof(TmxObjectRectangle)) { objElement = CreateBoxColliderElement(tmxObject as TmxObjectRectangle); } else if (tmxObject.GetType() == typeof(TmxObjectEllipse)) { objElement = CreateCircleColliderElement(tmxObject as TmxObjectEllipse, tmxTile.Tile.ObjectGroup.Name); } else if (tmxObject.GetType() == typeof(TmxObjectPolygon)) { objElement = CreatePolygonColliderElement(tmxObject as TmxObjectPolygon); } else if (tmxObject.GetType() == typeof(TmxObjectPolyline)) { objElement = CreateEdgeColliderElement(tmxObject as TmxObjectPolyline); } if (objElement != null) { xmlTileObject.Add(objElement); } } }
private void AddTileObjectElements(TmxObjectTile tmxObjectTile, XElement xmlTileObjectRoot) { // TileObjects can be scaled (this is separate from vertex scaling) SizeF scale = tmxObjectTile.GetTileObjectScale(); // Flipping is done through negative-scaling on the child object float flip_w = tmxObjectTile.FlippedHorizontal ? -1.0f : 1.0f; float flip_h = tmxObjectTile.FlippedVertical ? -1.0f : 1.0f; // Helper values for moving tile about local origin float full_w = tmxObjectTile.Tile.TileSize.Width; float full_h = tmxObjectTile.Tile.TileSize.Height; float half_w = full_w * 0.5f; float half_h = full_h * 0.5f; // Scale goes onto root node xmlTileObjectRoot.SetAttributeValue("scaleX", scale.Width); xmlTileObjectRoot.SetAttributeValue("scaleY", scale.Height); // We combine the properties of the tile that is referenced and add it to our own properties AssignTiledProperties(tmxObjectTile.Tile, xmlTileObjectRoot); // Add a TileObject component for scripting purposes { XElement xmlTileObjectComponent = new XElement("TileObjectComponent"); xmlTileObjectComponent.SetAttributeValue("width", tmxObjectTile.Tile.TileSize.Width * scale.Width * Tiled2Unity.Settings.Scale); xmlTileObjectComponent.SetAttributeValue("height", tmxObjectTile.Tile.TileSize.Height * scale.Height * Tiled2Unity.Settings.Scale); xmlTileObjectRoot.Add(xmlTileObjectComponent); } // Child node positions game object to match center of tile so can flip along x and y axes XElement xmlTileObject = new XElement("GameObject"); xmlTileObject.SetAttributeValue("name", "TileObject"); if (tmxMap.Orientation == TmxMap.MapOrientation.Isometric) { // In isometric mode the local origin of the tile is at the bottom middle xmlTileObject.SetAttributeValue("x", 0); xmlTileObject.SetAttributeValue("y", half_h); } else { // For non-isometric maps the local origin of the tile is the bottom left xmlTileObject.SetAttributeValue("x", half_w); xmlTileObject.SetAttributeValue("y", half_h); } xmlTileObject.SetAttributeValue("scaleX", flip_w); xmlTileObject.SetAttributeValue("scaleY", flip_h); // Add any colliders that might be on the tile // Note: Colliders on a tile object are always treated as if they are in Orthogonal space TmxMap.MapOrientation restoreOrientation = tmxMap.Orientation; this.tmxMap.Orientation = TmxMap.MapOrientation.Orthogonal; { foreach (TmxObject tmxObject in tmxObjectTile.Tile.ObjectGroup.Objects) { XElement objElement = null; if (tmxObject.GetType() == typeof(TmxObjectRectangle)) { // Note: Tile objects have orthographic rectangles even in isometric orientations so no need to transform rectangle points objElement = CreateBoxColliderElement(tmxObject as TmxObjectRectangle); } else if (tmxObject.GetType() == typeof(TmxObjectEllipse)) { objElement = CreateCircleColliderElement(tmxObject as TmxObjectEllipse, tmxObjectTile.Tile.ObjectGroup.Name); } else if (tmxObject.GetType() == typeof(TmxObjectPolygon)) { objElement = CreatePolygonColliderElement(tmxObject as TmxObjectPolygon); } else if (tmxObject.GetType() == typeof(TmxObjectPolyline)) { objElement = CreateEdgeColliderElement(tmxObject as TmxObjectPolyline); } if (objElement != null) { // This object is currently in the center of the Tile Object we are constructing // The collision geometry is wrt the top-left corner // The "Offset" of the collider translation to get to lop-left corner and the collider's position into account float offset_x = (-half_w + tmxObject.Position.X) * Tiled2Unity.Settings.Scale; float offset_y = (half_h - tmxObject.Position.Y) * Tiled2Unity.Settings.Scale; objElement.SetAttributeValue("offsetX", offset_x); objElement.SetAttributeValue("offsetY", offset_y); xmlTileObject.Add(objElement); } } } this.tmxMap.Orientation = restoreOrientation; // Add a child for each mesh // (The child node is needed due to animation) foreach (var mesh in tmxObjectTile.Tile.Meshes) { XElement xmlMeshObject = new XElement("GameObject"); xmlMeshObject.SetAttributeValue("name", mesh.ObjectName); xmlMeshObject.SetAttributeValue("copy", mesh.UniqueMeshName); xmlMeshObject.SetAttributeValue("sortingLayerName", tmxObjectTile.SortingLayerName ?? tmxObjectTile.ParentObjectGroup.SortingLayerName); xmlMeshObject.SetAttributeValue("sortingOrder", tmxObjectTile.SortingOrder ?? tmxObjectTile.ParentObjectGroup.SortingOrder); // Game object that contains mesh moves position to that local origin of Tile Object (from Tiled's point of view) matches the root position of the Tile game object // Put another way: This translation moves away from center to local origin xmlMeshObject.SetAttributeValue("x", -half_w); xmlMeshObject.SetAttributeValue("y", half_h); if (mesh.FullAnimationDurationMs > 0) { XElement xmlAnimation = new XElement("TileAnimator", new XAttribute("startTimeMs", mesh.StartTimeMs), new XAttribute("durationMs", mesh.DurationMs), new XAttribute("fullTimeMs", mesh.FullAnimationDurationMs)); xmlMeshObject.Add(xmlAnimation); } xmlTileObject.Add(xmlMeshObject); } xmlTileObjectRoot.Add(xmlTileObject); }
private List <XElement> CreateObjectElementList(TmxObjectGroup objectGroup) { List <XElement> elements = new List <XElement>(); foreach (TmxObject tmxObject in objectGroup.Objects) { // All the objects/colliders in our object group need to be separate game objects because they can have unique tags/layers XElement xmlObject = new XElement("GameObject", new XAttribute("name", tmxObject.GetNonEmptyName())); // Transform object locaction into map space (needed for isometric and hex modes) PointF xfPosition = TmxMath.ObjectPointFToMapSpace(this.tmxMap, tmxObject.Position); PointF pos = PointFToUnityVector(xfPosition); xmlObject.SetAttributeValue("x", pos.X); xmlObject.SetAttributeValue("y", pos.Y); xmlObject.SetAttributeValue("rotation", tmxObject.Rotation); AssignUnityProperties(tmxObject, xmlObject, PrefabContext.Object); AssignTiledProperties(tmxObject, xmlObject); // If we're not using a unity:layer override and there is an Object Type to go with this object then use it if (String.IsNullOrEmpty(objectGroup.UnityLayerOverrideName)) { xmlObject.SetAttributeValue("layer", tmxObject.Type); } XElement objElement = null; if (tmxObject.GetType() == typeof(TmxObjectRectangle)) { if (this.tmxMap.Orientation == TmxMap.MapOrientation.Isometric) { TmxObjectPolygon tmxIsometricRectangle = TmxObjectPolygon.FromRectangle(this.tmxMap, tmxObject as TmxObjectRectangle); objElement = CreatePolygonColliderElement(tmxIsometricRectangle); } else { objElement = CreateBoxColliderElement(tmxObject as TmxObjectRectangle); } } else if (tmxObject.GetType() == typeof(TmxObjectEllipse)) { objElement = CreateCircleColliderElement(tmxObject as TmxObjectEllipse, objectGroup.Name); } else if (tmxObject.GetType() == typeof(TmxObjectPolygon)) { objElement = CreatePolygonColliderElement(tmxObject as TmxObjectPolygon); } else if (tmxObject.GetType() == typeof(TmxObjectPolyline)) { objElement = CreateEdgeColliderElement(tmxObject as TmxObjectPolyline); } else if (tmxObject.GetType() == typeof(TmxObjectTile)) { TmxObjectTile tmxObjectTile = tmxObject as TmxObjectTile; // Apply z-cooridnate for use with the depth buffer // (Again, this is complicated by the fact that object tiles position is WRT the bottom edge of a tile) if (Tiled2Unity.Settings.DepthBufferEnabled) { float mapLogicalHeight = this.tmxMap.MapSizeInPixels().Height; float tileLogicalHeight = this.tmxMap.TileHeight; float logicalPos_y = (-pos.Y / Tiled2Unity.Settings.Scale) - tileLogicalHeight; float depth_z = CalculateFaceDepth(logicalPos_y, mapLogicalHeight); xmlObject.SetAttributeValue("z", depth_z); } AddTileObjectElements(tmxObject as TmxObjectTile, xmlObject); } else { Logger.WriteLine("Object '{0}' has been added for use with custom importers", tmxObject); } if (objElement != null) { xmlObject.Add(objElement); } elements.Add(xmlObject); } return(elements); }
private List <XElement> CreateObjectElementList(TmxObjectGroup objectGroup) { List <XElement> elements = new List <XElement>(); foreach (TmxObject tmxObject in objectGroup.Objects) { // All the objects/colliders in our object group need to be separate game objects because they can have unique tags/layers XElement xmlObject = new XElement("GameObject", new XAttribute("name", tmxObject.GetNonEmptyName())); // Transform object locaction into map space (needed for isometric and hex modes) PointF xfPosition = TmxMath.ObjectPointFToMapSpace(this.tmxMap, tmxObject.Position); PointF pos = PointFToUnityVector(xfPosition); xmlObject.SetAttributeValue("x", pos.X); xmlObject.SetAttributeValue("y", pos.Y); xmlObject.SetAttributeValue("rotation", tmxObject.Rotation); AssignUnityProperties(tmxObject, xmlObject, PrefabContext.Object); AssignTiledProperties(tmxObject, xmlObject); // If we're not using a unity:layer override and there is an Object Type to go with this object then use it if (String.IsNullOrEmpty(objectGroup.UnityLayerOverrideName)) { // why would we /ever/ do this, christ //xmlObject.SetAttributeValue("layer", tmxObject.Type); } XElement objElement = null; XElement objComponent = new XElement("TmxObjectComponent", new XAttribute("tmx-object-id", tmxObject.Id), new XAttribute("tmx-object-name", tmxObject.Name), new XAttribute("tmx-object-type", tmxObject.Type), new XAttribute("tmx-object-x", tmxObject.Position.X), new XAttribute("tmx-object-y", tmxObject.Position.Y), new XAttribute("tmx-object-width", tmxObject.Size.Width), new XAttribute("tmx-object-height", tmxObject.Size.Height), new XAttribute("tmx-object-rotation", tmxObject.Rotation)); // Do not create colliders if the are being ignored. (Still want to creat the game object though) bool ignoringCollisions = (objectGroup.Ignore == TmxLayerNode.IgnoreSettings.Collision); if (!ignoringCollisions && tmxObject.GetType() == typeof(TmxObjectRectangle)) { if (this.tmxMap.Orientation == TmxMap.MapOrientation.Isometric) { TmxObjectPolygon tmxIsometricRectangle = TmxObjectPolygon.FromRectangle(this.tmxMap, tmxObject as TmxObjectRectangle); objElement = CreatePolygonColliderElement(tmxIsometricRectangle); } else { objElement = CreateBoxColliderElement(tmxObject as TmxObjectRectangle); } // Set object component type objComponent.Name = "RectangleObjectComponent"; } else if (!ignoringCollisions && tmxObject.GetType() == typeof(TmxObjectEllipse)) { objElement = CreateCircleColliderElement(tmxObject as TmxObjectEllipse, objectGroup.Name); // Set the component type objComponent.Name = "CircleObjectComponent"; } else if (!ignoringCollisions && tmxObject.GetType() == typeof(TmxObjectPolygon)) { objElement = CreatePolygonColliderElement(tmxObject as TmxObjectPolygon); // Set the component type objComponent.Name = "PolygonObjectComponent"; } else if (!ignoringCollisions && tmxObject.GetType() == typeof(TmxObjectPolyline)) { objElement = CreateEdgeColliderElement(tmxObject as TmxObjectPolyline); // Set the component type objComponent.Name = "PolylineObjectComponent"; } else if (tmxObject.GetType() == typeof(TmxObjectTile)) { TmxObjectTile tmxObjectTile = tmxObject as TmxObjectTile; // Apply z-cooridnate for use with the depth buffer if (Tiled2Unity.Settings.DepthBufferEnabled) { float depth_z = CalculateFaceDepth(tmxObjectTile.Position.Y, tmxMap.MapSizeInPixels.Height); xmlObject.SetAttributeValue("z", depth_z); } AddTileObjectElements(tmxObjectTile, xmlObject, objComponent); } else { Logger.WriteLine("Object '{0}' has been added for use with custom importers", tmxObject); } if (objElement != null) { xmlObject.Add(objComponent); xmlObject.Add(objElement); } elements.Add(xmlObject); } return(elements); }
private void AddTileObjectElements(TmxObjectTile tmxObjectTile, XElement xmlTileObjectRoot) { // We combine the properties of the tile that is referenced and add it to our own properties AssignTiledProperties(tmxObjectTile.Tile, xmlTileObjectRoot); // TileObjects can be scaled (this is separate from vertex scaling) SizeF scale = tmxObjectTile.GetTileObjectScale(); xmlTileObjectRoot.SetAttributeValue("scaleX", scale.Width); xmlTileObjectRoot.SetAttributeValue("scaleY", scale.Height); // Need another transform to help us with flipping of the tile (and their collisions) XElement xmlTileObject = new XElement("GameObject"); xmlTileObject.SetAttributeValue("name", "TileObject"); if (tmxObjectTile.FlippedHorizontal) { xmlTileObject.SetAttributeValue("x", tmxObjectTile.Tile.TileSize.Width * Tiled2Unity.Settings.Scale); xmlTileObject.SetAttributeValue("flipX", true); } if (tmxObjectTile.FlippedVertical) { xmlTileObject.SetAttributeValue("y", tmxObjectTile.Tile.TileSize.Height * Tiled2Unity.Settings.Scale); xmlTileObject.SetAttributeValue("flipY", true); } // Add any colliders that might be on the tile // Note: Colliders on a tile object are always treated as if they are in Orthogonal space TmxMap.MapOrientation restoreOrientation = tmxMap.Orientation; this.tmxMap.Orientation = TmxMap.MapOrientation.Orthogonal; { foreach (TmxObject tmxObject in tmxObjectTile.Tile.ObjectGroup.Objects) { XElement objElement = null; if (tmxObject.GetType() == typeof(TmxObjectRectangle)) { // Note: Tile objects have orthographic rectangles even in isometric orientations so no need to transform rectangle points objElement = CreateBoxColliderElement(tmxObject as TmxObjectRectangle); } else if (tmxObject.GetType() == typeof(TmxObjectEllipse)) { objElement = CreateCircleColliderElement(tmxObject as TmxObjectEllipse, tmxObjectTile.Tile.ObjectGroup.Name); } else if (tmxObject.GetType() == typeof(TmxObjectPolygon)) { objElement = CreatePolygonColliderElement(tmxObject as TmxObjectPolygon); } else if (tmxObject.GetType() == typeof(TmxObjectPolyline)) { objElement = CreateEdgeColliderElement(tmxObject as TmxObjectPolyline); } if (objElement != null) { // Objects can be offset (and we need to make up for the bottom-left corner being the origin in a TileObject) objElement.SetAttributeValue("offsetX", tmxObject.Position.X * Tiled2Unity.Settings.Scale); objElement.SetAttributeValue("offsetY", (tmxObjectTile.Size.Height - tmxObject.Position.Y) * Tiled2Unity.Settings.Scale); xmlTileObject.Add(objElement); } } } this.tmxMap.Orientation = restoreOrientation; // Add a child for each mesh (with animation if needed) foreach (var mesh in tmxObjectTile.Tile.Meshes) { XElement xmlMeshObject = new XElement("GameObject"); xmlMeshObject.SetAttributeValue("name", mesh.ObjectName); xmlMeshObject.SetAttributeValue("copy", mesh.UniqueMeshName); xmlMeshObject.SetAttributeValue("sortingLayerName", tmxObjectTile.SortingLayerName ?? tmxObjectTile.ParentObjectGroup.SortingLayerName); xmlMeshObject.SetAttributeValue("sortingOrder", tmxObjectTile.SortingOrder ?? tmxObjectTile.ParentObjectGroup.SortingOrder); // This object, that actually displays the tile, has to be bumped up to account for the bottom-left corner problem with Tile Objects in Tiled xmlMeshObject.SetAttributeValue("x", 0); xmlMeshObject.SetAttributeValue("y", tmxObjectTile.Tile.TileSize.Height * Tiled2Unity.Settings.Scale); if (mesh.FullAnimationDurationMs > 0) { XElement xmlAnimation = new XElement("TileAnimator", new XAttribute("startTimeMs", mesh.StartTimeMs), new XAttribute("durationMs", mesh.DurationMs), new XAttribute("fullTimeMs", mesh.FullAnimationDurationMs)); xmlMeshObject.Add(xmlAnimation); } xmlTileObject.Add(xmlMeshObject); } xmlTileObjectRoot.Add(xmlTileObject); }
public static TmxObject FromXml(XElement xml, TmxObjectGroup tmxObjectGroup, TmxMap tmxMap) { Logger.WriteLine("Parsing object ..."); // What kind of TmxObject are we creating? TmxObject tmxObject = null; if (xml.Element("ellipse") != null) { tmxObject = new TmxObjectEllipse(); } else if (xml.Element("polygon") != null) { tmxObject = new TmxObjectPolygon(); } else if (xml.Element("polyline") != null) { tmxObject = new TmxObjectPolyline(); } else if (xml.Attribute("gid") != null) { uint gid = TmxHelper.GetAttributeAsUInt(xml, "gid"); gid = TmxMath.GetTileIdWithoutFlags(gid); if (tmxMap.Tiles.ContainsKey(gid)) { tmxObject = new TmxObjectTile(); } else { // For some reason, the tile is not in any of our tilesets // Warn the user and use a rectangle Logger.WriteWarning("Tile Id {0} not found in tilesets. Using a rectangle instead.\n{1}", gid, xml.ToString()); tmxObject = new TmxObjectRectangle(); } } else { // Just a rectangle tmxObject = new TmxObjectRectangle(); } // Data found on every object type tmxObject.Name = TmxHelper.GetAttributeAsString(xml, "name", ""); tmxObject.Type = TmxHelper.GetAttributeAsString(xml, "type", ""); tmxObject.Visible = TmxHelper.GetAttributeAsInt(xml, "visible", 1) == 1; tmxObject.ParentObjectGroup = tmxObjectGroup; float x = TmxHelper.GetAttributeAsFloat(xml, "x"); float y = TmxHelper.GetAttributeAsFloat(xml, "y"); float w = TmxHelper.GetAttributeAsFloat(xml, "width", 0); float h = TmxHelper.GetAttributeAsFloat(xml, "height", 0); float r = TmxHelper.GetAttributeAsFloat(xml, "rotation", 0); tmxObject.Position = new System.Drawing.PointF(x, y); tmxObject.Size = new System.Drawing.SizeF(w, h); tmxObject.Rotation = r; tmxObject.Properties = TmxProperties.FromXml(xml); tmxObject.InternalFromXml(xml, tmxMap); return(tmxObject); }
public static TmxObject FromXml(XElement xml, TmxObjectGroup tmxObjectGroup, TmxMap tmxMap) { Program.WriteLine("Parsing object ..."); Program.WriteVerbose(xml.ToString()); // What kind of TmxObject are we creating? TmxObject tmxObject = null; if (xml.Element("ellipse") != null) { tmxObject = new TmxObjectEllipse(); } else if (xml.Element("polygon") != null) { tmxObject = new TmxObjectPolygon(); } else if (xml.Element("polyline") != null) { tmxObject = new TmxObjectPolyline(); } else if (xml.Attribute("gid") != null) { uint gid = TmxHelper.GetAttributeAsUInt(xml, "gid"); gid = TmxMath.GetTileIdWithoutFlags(gid); if (tmxMap.Tiles.ContainsKey(gid)) { tmxObject = new TmxObjectTile(); } else { // For some reason, the tile is not in any of our tilesets // Warn the user and use a rectangle Program.WriteWarning("Tile Id {0} not found in tilesets. Using a rectangle instead.\n{1}", gid, xml.ToString()); tmxObject = new TmxObjectRectangle(); } } else { // Just a rectangle tmxObject = new TmxObjectRectangle(); } // Data found on every object type tmxObject.Name = TmxHelper.GetAttributeAsString(xml, "name", ""); tmxObject.Type = TmxHelper.GetAttributeAsString(xml, "type", ""); tmxObject.Visible = TmxHelper.GetAttributeAsInt(xml, "visible", 1) == 1; tmxObject.ParentObjectGroup = tmxObjectGroup; float x = TmxHelper.GetAttributeAsFloat(xml, "x"); float y = TmxHelper.GetAttributeAsFloat(xml, "y"); float w = TmxHelper.GetAttributeAsFloat(xml, "width", 0); float h = TmxHelper.GetAttributeAsFloat(xml, "height", 0); float r = TmxHelper.GetAttributeAsFloat(xml, "rotation", 0); tmxObject.Position = new System.Drawing.PointF(x, y); tmxObject.Size = new System.Drawing.SizeF(w, h); tmxObject.Rotation = r; tmxObject.Properties = TmxProperties.FromXml(xml); tmxObject.InternalFromXml(xml, tmxMap); return tmxObject; }
private void DrawObjectCollider(Graphics g, TmxObject tmxObject, Color color) { Color brushColor = Color.FromArgb(128, color); using (Brush brush = new HatchBrush(HatchStyle.BackwardDiagonal, color, brushColor)) using (Pen pen = new Pen(color)) { pen.Alignment = PenAlignment.Inset; GraphicsState state = g.Save(); PointF xfPosition = TmxMath.ObjectPointFToMapSpace(this.tmxMap, tmxObject.Position); g.TranslateTransform(xfPosition.X, xfPosition.Y); g.RotateTransform(tmxObject.Rotation); if (tmxObject.GetType() == typeof(TmxObjectPolygon)) { DrawPolygon(g, pen, brush, tmxObject as TmxObjectPolygon); } else if (tmxObject.GetType() == typeof(TmxObjectRectangle)) { if (this.tmxMap.Orientation == TmxMap.MapOrientation.Isometric) { TmxObjectPolygon tmxIsometricRectangle = TmxObjectPolygon.FromRectangle(this.tmxMap, tmxObject as TmxObjectRectangle); DrawPolygon(g, pen, brush, tmxIsometricRectangle); } else { // Rectangles are polygons DrawPolygon(g, pen, brush, tmxObject as TmxObjectPolygon); } } else if (tmxObject.GetType() == typeof(TmxObjectEllipse)) { DrawEllipse(g, pen, brush, tmxObject as TmxObjectEllipse); } else if (tmxObject.GetType() == typeof(TmxObjectPolyline)) { DrawPolyline(g, pen, tmxObject as TmxObjectPolyline); } else if (tmxObject.GetType() == typeof(TmxObjectTile)) { GraphicsState tileState = g.Save(); TmxObjectTile tmxObjectTile = tmxObject as TmxObjectTile; // Apply scale SizeF scale = tmxObjectTile.GetTileObjectScale(); g.ScaleTransform(scale.Width, scale.Height); // Apply horizontal flip if (tmxObjectTile.FlippedHorizontal) { g.TranslateTransform(tmxObjectTile.Tile.TileSize.Width, 0); g.ScaleTransform(-1, 1); } // Apply vertical flip if (tmxObjectTile.FlippedVertical) { g.TranslateTransform(0, -tmxObjectTile.Tile.TileSize.Height); g.ScaleTransform(1, -1); } // (Note: Now we can draw the tile and collisions as normal as the transforms have been set up.) // Draw the tile Rectangle destination = new Rectangle(0, -tmxObjectTile.Tile.TileSize.Height, tmxObjectTile.Tile.TileSize.Width, tmxObjectTile.Tile.TileSize.Height); Rectangle source = new Rectangle(tmxObjectTile.Tile.LocationOnSource, tmxObjectTile.Tile.TileSize); g.DrawImage(tmxObjectTile.Tile.TmxImage.ImageBitmap, destination, source, GraphicsUnit.Pixel); // Put a black border around the tile so it sticks out a bit as an object g.DrawRectangle(Pens.Black, destination); // Draw the collisions // Make up for the fact that the bottom-left corner is the origin g.TranslateTransform(0, -tmxObjectTile.Tile.TileSize.Height); foreach (var obj in tmxObjectTile.Tile.ObjectGroup.Objects) { DrawObjectCollider(g, obj, Color.Gray); } g.Restore(tileState); } else { g.Restore(state); RectangleF bounds = tmxObject.GetWorldBounds(); g.FillRectangle(Brushes.Red, bounds.X, bounds.Y, bounds.Width, bounds.Height); g.DrawRectangle(Pens.White, bounds.X, bounds.Y, bounds.Width, bounds.Height); string message = String.Format("Unhandled object: {0}", tmxObject.GetNonEmptyName()); DrawString(g, message, bounds.X, bounds.Y); } // Restore our state g.Restore(state); } }