using System; using System.Collections.Generic; using System.Linq; using UnityEngine; namespace SuperTiled2Unity { [Serializable] public class CollisionObject { public int m_ObjectId; public string m_ObjectName; public string m_ObjectType; public Vector2 m_Position; public Vector2 m_Size; public float m_Rotation; public List m_CustomProperties; public string m_PhysicsLayer; public bool m_IsTrigger; [SerializeField] private Vector2[] m_Points; public Vector2[] Points { get { return m_Points; } } [SerializeField] private bool m_IsClosed; public bool IsClosed { get { return m_IsClosed; } } [SerializeField] private CollisionShapeType m_CollisionShapeType; public CollisionShapeType CollisionShapeType { get { return m_CollisionShapeType; } } public void MakePointsFromRectangle() { m_CollisionShapeType = CollisionShapeType.Rectangle; m_IsClosed = true; // Make the points the give us a rectangle shape // Note: points are counter-clockwise m_Points = new Vector2[4]; m_Points[0] = Vector2.zero; m_Points[1] = new Vector2(0, m_Size.y); m_Points[2] = new Vector2(m_Size.x, m_Size.y); m_Points[3] = new Vector2(m_Size.x, 0); } public void MakePoint() { m_CollisionShapeType = CollisionShapeType.Point; m_IsClosed = false; m_Points = new Vector2[1]; m_Points[0] = m_Position; } public void MakePointsFromEllipse(int numEdges) { m_CollisionShapeType = CollisionShapeType.Ellipse; m_IsClosed = true; // Estimate the ellipse with a polygon float theta = ((float)Math.PI * 2.0f) / numEdges; float half_x = m_Size.x * 0.5f; float half_y = m_Size.y * 0.5f; m_Points = new Vector2[numEdges]; for (int i = 0; i < numEdges; i++) { m_Points[i].x = half_x + half_x * Mathf.Cos(theta * i); m_Points[i].y = half_y + half_y * Mathf.Sin(theta * i); } } public void MakePointsFromPolygon(Vector2[] points) { m_CollisionShapeType = CollisionShapeType.Polygon; m_IsClosed = true; m_Points = points; } public void MakePointsFromPolyline(Vector2[] points) { m_CollisionShapeType = CollisionShapeType.Polyline; m_IsClosed = false; m_Points = points; } // This must be called in order for rotation and position offset to by applied public void RenderPoints(SuperTile tile, GridOrientation orientation, Vector2 gridSize) { if (orientation == GridOrientation.Isometric) { m_Position = IsometricTransform(m_Position, tile, gridSize); m_Position.x += gridSize.x * 0.5f; for (int i = 0; i < m_Points.Length; i++) { m_Points[i] = IsometricTransform(m_Points[i], tile, gridSize); } // Also, we are forced to use polygon colliders for isometric projection if (m_CollisionShapeType == CollisionShapeType.Ellipse || m_CollisionShapeType == CollisionShapeType.Rectangle) { m_CollisionShapeType = CollisionShapeType.Polygon; } } // Burn rotation into our points ApplyRotationToPoints(); // Burn translation into our points m_Points = m_Points.Select(p => p + m_Position).ToArray(); // Transform all points so that they wrt the bottom-left of the tile // This should make calculations later easier since Tiled treats the bottom-left corner of a tile as the local origin m_Points = m_Points.Select(p => LocalTransform(p, tile)).ToArray(); m_Position = LocalTransform(m_Position, tile); } private Vector2 IsometricTransform(Vector2 pt, SuperTile tile,Vector2 gridSize) { float cx = pt.x / gridSize.y; float cy = pt.y / gridSize.y; float x = (cx - cy) * gridSize.x * 0.5f; float y = (cx + cy) * gridSize.y * 0.5f; y += (tile.m_Height - gridSize.y) * 0.5f; return new Vector2(x, y); } private Vector2 LocalTransform(Vector2 pt, SuperTile tile) { return new Vector2(pt.x, tile.m_Height - pt.y); } private void ApplyRotationToPoints() { if (m_Rotation != 0) { var rads = m_Rotation * Mathf.Deg2Rad; var cos = Mathf.Cos(rads); var sin = Mathf.Sin(rads); var rotate = MatrixUtils.Rotate2d(cos, -sin, sin, cos); m_Points = m_Points.Select(p => rotate.MultiplyPoint(p)).Select(v3 => (Vector2)v3).ToArray(); } } } }