private void FromPolygonCollider2D(Shape shape) { PolygonCollider2D pc2d = shape.GetComponent <PolygonCollider2D>(); if (shape.settings.shapeType == ShapeType.Polygon) { if (pc2d.points.Length >= 64) { EditorUtility.DisplayDialog("Too many points", "The PolygonCollider2D has too many points (max 64).", "Okay"); return; } Vector3[] points = new Vector3[pc2d.points.Length]; for (int i = 0; i < pc2d.points.Length; i++) { points[i] = shape.transform.TransformPoint(pc2d.points[i]); } Undo.RecordObject(shape, "Edit Shapes2D Polygon Vertices"); shape.SetPolygonWorldVertices(points); EditorUtility.SetDirty(target); } else if (shape.settings.shapeType == ShapeType.Path) { if (pc2d.points.Length >= 32) { EditorUtility.DisplayDialog("Too many points", "The PolygonCollider2D has too many points (max 32).", "Okay"); return; } PathSegment[] segments = new PathSegment[pc2d.points.Length]; for (int i = 0; i < pc2d.points.Length; i++) { Vector3 p0 = shape.transform.TransformPoint(pc2d.points[i]); Vector3 p2 = i == pc2d.points.Length - 1 ? shape.transform.TransformPoint(pc2d.points[0]) : shape.transform.TransformPoint(pc2d.points[i + 1]); segments[i] = new PathSegment(p0, p2); } Undo.RecordObject(shape, "Edit Shapes2D Path Segments"); shape.SetPathWorldSegments(segments); EditorUtility.SetDirty(target); } }
void OnSceneGUI() { Shape shape = (Shape)target; if (!isEditingPolygon || shape.settings.shapeType != ShapeType.Polygon) { return; } // all the rest is for polygon editing if (Tools.current != Tool.None) { StopEditingPolygon(false); return; } HandleUtility.AddDefaultControl(GUIUtility.GetControlID(FocusType.Passive)); // draw the borders so the user knows where vertices should live DrawShapeBorders(shape); // get the existing verts Vector3[] oldVerts = shape.GetPolygonWorldVertices(); List <Vector3> verts = new List <Vector3>(oldVerts); bool hasMaxVerts = verts.Count == Shape.MaxPolygonVertices; // add the first vert at the end as well so Unity will draw it right etc verts.Add(verts[0]); // are we in delete mode? what color should handles be? Color pink = new Color(1, 0, 0.75f); bool deleteMode = false; if ((Event.current.control || Event.current.command) && verts.Count > 4) { Handles.color = Color.red; deleteMode = true; } else { Handles.color = pink; } // draw the shape Handles.DrawAAPolyLine(3f, verts.ToArray()); // drag handle result for getting info from our handles CustomHandles.DragHandleResult dhResult; // draw handles for each existing vert and check if they've been moved or clicked bool changed = false; for (int i = verts.Count - 2; i >= 0; i--) { Vector3 v = verts[i]; Vector3 newPos = CustomHandles.DragHandle(v, 0.05f * HandleUtility.GetHandleSize(v), Handles.DotCap, pink, out dhResult); if (deleteMode && dhResult == CustomHandles.DragHandleResult.LMBPress) { // the user clicked on the handle while in delete mode, so delete the vert verts.RemoveAt(i); changed = true; } else if (!deleteMode && newPos != v) { // the handle has been dragged, so move the vert to the new position verts[i] = new Vector2(newPos.x, newPos.y); changed = true; } } // check if the mouse is hovering over a space where we could add a new vert, // and draw it if so bool snapped = false; Vector3 closestPos = HandleUtility.ClosestPointToPolyLine(verts.ToArray()); float distance = HandleUtility.DistanceToPolyLine(verts.ToArray()); bool isCloseToLine = distance < 25; if (!changed && isCloseToLine && !hasMaxVerts && !deleteMode) { // todo - ClosestPointToPolyLine doesn't work very well in 3D... foreach (Vector3 v in verts) { // if close to an existing vert, we don't want to add a new one if (Vector2.Distance(HandleUtility.WorldToGUIPoint(closestPos), HandleUtility.WorldToGUIPoint(v)) < 15) { snapped = true; break; } } if (!snapped) { // not too close to an existing vert, so draw a new one. don't // use an actual handle cause we want to intercept nearby clicks // and not just clicks directly on the handle. Rect rect = new Rect(); float dim = 0.05f * HandleUtility.GetHandleSize(closestPos); rect.center = closestPos - new Vector3(dim, dim, 0); rect.size = new Vector2(dim * 2, dim * 2); Handles.color = Color.white; // remove the weird tint it does Handles.DrawSolidRectangleWithOutline(rect, Color.green, Color.clear); if (Event.current.type == EventType.MouseDown) { // the user has clicked the new vert, so add it for real // figure out which line segment it's on int lineStart = GetClosestLineToPoint(closestPos, verts); verts.Insert(lineStart + 1, closestPos); changed = true; } } } // something has been changed, so apply the new verts back to the shape if (changed) { // make sure to remove the duplicated last vert we added Undo.RecordObject(shape, "Edit Shapes2D Polygon Vertices"); shape.SetPolygonWorldVertices( verts.GetRange(0, verts.Count - 1).ToArray()); EditorUtility.SetDirty(target); } else { HandleUtility.Repaint(); // to draw the new vert placeholder handle if (Event.current.type == EventType.MouseDown && !isCloseToLine) { StopEditingPolygon(true); } } }