/** * \brief Draws a preview mesh with no collisions from a List<Vector2> of user points. * This function accepts 2d points and converts them to world point vertices, triangulates, and draws a mesh. It does not create collisions, and will be deleted on finalizing an object. See also DestroyPreviewMesh(), CleanUp(), RefreshPreview(). * @param _points List of user points. Assumed to be in world space (use ScreenToWorldPoint(screenPoint) where screenPoint is typically Input.mousePosition ). */ public void DrawPreviewMesh(List <Vector2> _points) { if (_points.Count < 3) { return; } // Create the mesh if (previewGameObject == null) { previewGameObject = new GameObject(); previewGameObject.AddComponent <MeshFilter>(); previewGameObject.GetComponent <MeshFilter>(); previewGameObject.AddComponent <MeshRenderer>(); } Mesh m, c; PolygonType convexity; DrawUtility.MeshWithPoints(_points, drawSettings, out m, out c, out convexity); previewGameObject.GetComponent <MeshFilter>().sharedMesh = m; Material[] mats = (drawSettings.generateSide) ? new Material[2] { drawSettings.frontMaterial, drawSettings.sideMaterial } : new Material[1] { drawSettings.frontMaterial }; previewGameObject.GetComponent <MeshRenderer>().sharedMaterials = mats; }
/** * \brief Draws planes around the edges of a mesh. * @param _points The points to use as a guide. * @param _modifier Multiply plane X and Y dimensions component wise. */ public void DrawEdgePlanes(List <Vector2> _points, PolygonType convexity, Vector2 _modifier, float area) { Vector2[] points = _points.ToArray(); if (convexity == PolygonType.ConcaveClockwise || convexity == PolygonType.ConvexClockwise) { Array.Reverse(points); } for (int i = 0; i < points.Length; i++) { float x1, x2, y1, y2; x1 = points[i].x; y1 = points[i].y; if (i > points.Length - 2) { x2 = points[0].x; y2 = points[0].y; } else { x2 = points[i + 1].x; y2 = points[i + 1].y; } float length = Vector2.Distance(new Vector2(x1, y1), new Vector2(x2, y2)); length *= drawSettings.edgeLengthModifier; if (length < drawSettings.minLengthToDraw) { continue; } float angle = Mathf.Atan2(y2 - y1, x2 - x1) * Mathf.Rad2Deg; if (Mathf.Abs(angle) > 180 - drawSettings.maxAngle && Mathf.Abs(angle) < 180 + drawSettings.maxAngle) { ; } else { continue; } GameObject boxColliderObj = new GameObject(); boxColliderObj.AddComponent <MeshFilter>().sharedMesh = MeshPlane(); boxColliderObj.AddComponent <MeshRenderer>(); boxColliderObj.name = "EdgePlane " + angle; boxColliderObj.transform.position = new Vector3(((x1 + x2) / 2f), ((y1 + y2) / 2f), drawSettings.zPosition + drawSettings.edgeOffset); boxColliderObj.GetComponent <MeshRenderer>().sharedMaterial = drawSettings.edgeMaterial; Vector2[] uvs = boxColliderObj.GetComponent <MeshFilter>().sharedMesh.uv; float imgScale = 1f; if (drawSettings.edgeMaterial != null) { imgScale = ((float)drawSettings.edgeMaterial.mainTexture.width / drawSettings.edgeMaterial.mainTexture.height); } boxColliderObj.GetComponent <MeshFilter>().sharedMesh.uv = DrawUtility.ArrayMultiply(uvs, new Vector2(length / imgScale, 1f)).ToArray(); if (drawSettings.areaRelativeHeight) { boxColliderObj.transform.localScale = new Vector3( length, Mathf.Clamp(Mathf.Abs(area) * drawSettings.edgeHeight, drawSettings.minEdgeHeight, drawSettings.maxEdgeHeight), 2f); } else { boxColliderObj.transform.localScale = new Vector3(length, drawSettings.edgeHeight, 2f); } boxColliderObj.transform.rotation = Quaternion.Euler(new Vector3(0f, 0f, angle)); boxColliderObj.transform.parent = LastDrawnObject.transform; } }
/** * \brief Creates a mesh and applies all collisions and physics components. * This method accepts user points and creates a new gameObject with a mesh composed from point data. As opposed to DrawPreviewMesh(), this function will check against all user specified rules. If conditions are met, CheckMaxMeshes() is called, and the new gameObject is added to the internal cache of all PolyDraw created objects. * @param _points List of user points. Assumed to be in world space (use ScreenToWorldPoint(screenPoint) where screenPoint is typically Input.mousePosition ). */ public void DrawFinalMesh(List <Vector2> _points) { DestroyPreviewMesh(); if (_points.Count < 3) { CleanUp(); #if DEBUG Debug.LogWarning("Polydraw: Mesh generation failed on points < 3"); #endif OnCanceledObjectCreation(); return; } if ((_points[0] - _points[_points.Count - 1]).sqrMagnitude > maxDistance && useDistanceCheck) { #if DEBUG Debug.LogWarning("Mesh generation failed on distance check"); #endif CleanUp(); OnCanceledObjectCreation(); return; } // Calculate this here because the collision code needs it too float obj_area = Mathf.Abs(Triangulator.Area(_points)); if (drawSettings.requireMinimumArea && obj_area < drawSettings.minimumAreaToDraw) { #if DEBUG Debug.Log("Polydraw: Mesh generation failed on requireMinimumArea check."); #endif CleanUp(); return; } // graphics = any mesh that you can see, collision = the side mesh Mesh graphics, collision; Draw.PolygonType convexity; // Since Draw doesn't expose special collision settings, just the side settings. drawSettings.colAnchor = drawSettings.anchor; drawSettings.colDepth = drawSettings.sideLength > .01 ? drawSettings.sideLength : .01f; if (!DrawUtility.MeshWithPoints(_points, drawSettings, out graphics, out collision, out convexity)) { if (graphics != null) { DestroyImmediate(graphics); } if (collision != null) { DestroyImmediate(collision); } CleanUp(); return; } // If we're over max, delete the earliest drawn mesh CheckMaxMeshes(); GameObject finalMeshGameObject = new GameObject(); finalMeshGameObject.name = drawSettings.meshName; if (drawSettings.useTag) { finalMeshGameObject.tag = drawSettings.tagVal; } finalMeshGameObject.AddComponent <MeshFilter>(); finalMeshGameObject.GetComponent <MeshFilter>().sharedMesh = graphics; finalMeshGameObject.AddComponent <MeshRenderer>(); Material[] mats = (drawSettings.generateSide) ? new Material[2] { drawSettings.frontMaterial, drawSettings.sideMaterial } : new Material[1] { drawSettings.frontMaterial }; finalMeshGameObject.GetComponent <MeshRenderer>().sharedMaterials = mats; switch (drawSettings.colliderType) { case ColliderType.MeshCollider: finalMeshGameObject.AddComponent <MeshCollider>(); finalMeshGameObject.GetComponent <MeshCollider>().sharedMesh = collision; if (drawSettings.applyRigidbody) { Rigidbody rigidbody = finalMeshGameObject.AddComponent <Rigidbody>(); if ((convexity == PolygonType.ConcaveCounterClockwise || convexity == PolygonType.ConcaveClockwise) && drawSettings.forceConvex == false) { finalMeshGameObject.GetComponent <MeshCollider>().convex = false; } else { finalMeshGameObject.GetComponent <MeshCollider>().convex = true; } if (drawSettings.areaRelativeMass) { rigidbody.mass = obj_area * drawSettings.massModifier; } else { rigidbody.mass = drawSettings.mass; } rigidbody.constraints = RigidbodyConstraints.FreezeRotationX | RigidbodyConstraints.FreezeRotationY | RigidbodyConstraints.FreezePositionZ; if (drawSettings.useGravity) { rigidbody.useGravity = true; } else { rigidbody.useGravity = false; } if (drawSettings.isKinematic) { rigidbody.isKinematic = true; } else { rigidbody.isKinematic = false; } } break; case ColliderType.BoxCollider: if (drawSettings.applyRigidbody) { BoxCollider parent_collider = finalMeshGameObject.AddComponent <BoxCollider>(); // the parent collider - don't allow it to be seen, just use it for // mass and other settings parent_collider.size = new Vector3(.01f, .01f, .01f); Rigidbody rigidbody = finalMeshGameObject.AddComponent <Rigidbody>(); if (drawSettings.areaRelativeMass) { rigidbody.mass = obj_area * drawSettings.massModifier; } else { rigidbody.mass = drawSettings.mass; } rigidbody.constraints = RigidbodyConstraints.FreezeRotationX | RigidbodyConstraints.FreezeRotationY | RigidbodyConstraints.FreezePositionZ; if (drawSettings.useGravity) { rigidbody.useGravity = true; } else { rigidbody.useGravity = false; } if (drawSettings.isKinematic) { rigidbody.isKinematic = true; } else { rigidbody.isKinematic = false; } } if (!drawSettings.manualColliderDepth) { drawSettings.colDepth = drawSettings.sideLength; } float zPos_collider = drawSettings.zPosition + drawSettings.faceOffset; switch (drawSettings.anchor) { case Anchor.Front: zPos_collider += drawSettings.sideLength / 2f; break; case Anchor.Back: zPos_collider -= drawSettings.sideLength / 2f; break; default: break; } for (int i = 0; i < _points.Count; i++) { float x1, x2, y1, y2; x1 = _points[i].x; y1 = _points[i].y; if (i > _points.Count - 2) { x2 = _points[0].x; y2 = _points[0].y; } else { x2 = _points[i + 1].x; y2 = _points[i + 1].y; } GameObject boxColliderObj = new GameObject(); boxColliderObj.name = "BoxCollider" + i; boxColliderObj.AddComponent <BoxCollider>(); boxColliderObj.transform.position = new Vector3(((x1 + x2) / 2f), ((y1 + y2) / 2f), zPos_collider); Vector2 vectorLength = new Vector2(Mathf.Abs(x1 - x2), Mathf.Abs(y1 - y2)); float length = Mathf.Sqrt((Mathf.Pow((float)vectorLength.x, 2f) + Mathf.Pow(vectorLength.y, 2f))); float angle = Mathf.Atan2(y2 - y1, x2 - x1) * Mathf.Rad2Deg; boxColliderObj.transform.localScale = new Vector3(length, boxColliderSize, drawSettings.colDepth); boxColliderObj.transform.rotation = Quaternion.Euler(new Vector3(0f, 0f, angle)); boxColliderObj.transform.parent = finalMeshGameObject.transform; } break; case ColliderType.PolygonCollider2d: PolygonCollider2D poly = finalMeshGameObject.AddComponent <PolygonCollider2D>(); finalMeshGameObject.AddComponent <Rigidbody2D>(); poly.points = _points.ToArray(); break; default: break; } generatedMeshes.Add(finalMeshGameObject); if (drawSettings.drawEdgePlanes) { DrawEdgePlanes(_points, convexity, new Vector2(.4f, 1.2f), obj_area); } CleanUp(); OnCreatedNewObject(); }
public void Refresh() { if (points.Count < 1) { return; } Mesh m, c; Draw.PolygonType convexity; if (!DrawUtility.MeshWithPoints(points, drawSettings, out m, out c, out convexity)) { if (m) { DestroyImmediate(m); } if (c) { DestroyImmediate(c); } return; } gameObject.SetMesh(m); if (drawSettings.colliderType == Draw.ColliderType.MeshCollider) { if (GetComponent <PolygonCollider2D>()) { DestroyImmediate(GetComponent <PolygonCollider2D>()); } gameObject.SetMeshCollider(c); } MeshRenderer mr = gameObject.GetComponent <MeshRenderer>(); if (mr == null) { mr = gameObject.AddComponent <MeshRenderer>(); } if (drawSettings.generateSide) { mr.sharedMaterials = new Material[] { drawSettings.frontMaterial, drawSettings.sideMaterial, }; } else { mr.sharedMaterials = new Material[] { drawSettings.frontMaterial }; } #if UNITY_EDITOR UnityEditor.EditorApplication.delayCall += this.RefreshCollisions; #else RefreshCollisions(); #endif }
public void Refresh() { if (points.Count < 1) { return; } Mesh m, c; Draw.PolygonType convexity; if (!DrawUtility.MeshWithPoints(points, drawSettings, out m, out c, out convexity)) { if (m) { DestroyImmediate(m); } if (c) { DestroyImmediate(c); } return; } gameObject.SetMesh(m); bool isTrigger = gameObject.GetComponent <Collider>() == null ? false : gameObject.GetComponent <Collider>().isTrigger; bool isConvex = gameObject.GetComponent <MeshCollider>() == null ? false : gameObject.GetComponent <MeshCollider>().convex; RemoveCollisions(); Rigidbody oldRigidbody = gameObject.GetComponent <Rigidbody>(); bool hasRigidbody = (oldRigidbody != null); if (hasRigidbody) { CopyRigidbodySettings(); DestroyImmediate(gameObject.GetComponent <Rigidbody>()); } switch (drawSettings.colliderType) { case Draw.ColliderType.MeshCollider: gameObject.SetMeshCollider(c); break; case Draw.ColliderType.BoxCollider: BuildBoxCollisions(); DestroyImmediate(c); break; default: DestroyImmediate(c); break; } MeshRenderer mr = gameObject.GetComponent <MeshRenderer>(); if (mr == null) { mr = gameObject.AddComponent <MeshRenderer>(); } mr.sharedMaterials = drawSettings.generateSide ? new Material[] { drawSettings.frontMaterial, drawSettings.sideMaterial } : new Material[] { drawSettings.frontMaterial }; if (hasRigidbody) { if (!gameObject.GetComponent <Rigidbody>()) { gameObject.AddComponent <Rigidbody>(); } PasteRigidbodySettings(); } if (gameObject.GetComponent <Collider>()) { gameObject.GetComponent <Collider>().isTrigger = isTrigger; if (gameObject.GetComponent <MeshCollider>()) { gameObject.GetComponent <MeshCollider>().convex = isConvex; } } }