using System; using System.Collections.Generic; using System.Linq; using Core.Extensions; using UnityEngine; using Random = UnityEngine.Random; namespace TowerDefense.MeshCreator { /// /// Creates a Mesh that represents an area /// [Serializable] public class AreaMeshCreator : MonoBehaviour { [HideInInspector] public MeshObject meshObject; public Transform outSidePointsParent; /// /// The parent transform of points in the mesh /// public Transform pointsCenter { get { if (outSidePointsParent == null) { var points = new GameObject("Points"); outSidePointsParent = points.transform; outSidePointsParent.SetParent(transform, false); outSidePointsParent.eulerAngles = new Vector3(90, 0, 0); } #if UNITY_EDITOR outSidePointsParent.hideFlags = HideFlags.HideInHierarchy; #endif return outSidePointsParent; } } #if UNITY_EDITOR /// /// Gets an array of the Transforms of points in this mesh - only used by editor script /// public Transform[] pointsTransforms { get { Transform[] childern = new Transform[pointsCenter.childCount]; int length = pointsCenter.childCount; for (int i = 0; i < length; i++) { childern[i] = pointsCenter.GetChild(i); } return childern; } } #endif /// /// Get a list of Vector3s that correspond to the positions of the points in this mesh /// /// List of Points public List GetPoints() { return GetChildrenPositions(pointsCenter); } /// /// Gets a random Vector3 that lies inside the mesh object /// /// Random point public Vector3 GetRandomPointInside() { return transform.TransformPoint(meshObject.RandomPointInMesh()); } /// /// Forces all points to have a local "y" position of 0 /// Makes them coplanar /// public void ForcePointsFlat() { int length = pointsCenter.childCount; for (int i = 0; i < length; i++) { Transform t = pointsCenter.GetChild(i); Vector3 position = t.localPosition; position.z = 0; t.localPosition = position; } } List GetChildrenPositions(Transform parent) { int length = parent.childCount; List points = new List(); for (int i = 0; i < length; i++) { points.Add(parent.GetChild(i).position); } return points; } #if UNITY_EDITOR void OnDrawGizmos() { int count = pointsCenter.childCount; for (int i = 0; i < count - 1; i++) { Vector3 from = pointsCenter.GetChild(i).position; Vector3 to = pointsCenter.GetChild(i + 1).position; Gizmos.DrawLine(from, to); } // last to first Vector3 last = pointsCenter.GetChild(count - 1).position; Vector3 first = pointsCenter.GetChild(0).position; Gizmos.DrawLine(last, first); } #endif } [Serializable] public class Triangle { public Vector3 v0; public Vector3 v1; public Vector3 v2; public float area; /// /// Represents a Triangle in a mesh /// /// First Point /// Second Point /// Third Point public Triangle(Vector3 v0, Vector3 v1, Vector3 v2) { this.v0 = v0; this.v1 = v1; this.v2 = v2; // Precalculate area float a = Vector3.Distance(v0, v1), b = Vector3.Distance(v1, v2), c = Vector3.Distance(v2, v0); float s = (a + b + c) / 2; area = Mathf.Sqrt(s * (s - a) * (s - b) * (s - c)); } } /// /// Contains the triangles of the mesh /// Calculates the mesh area /// Can get a random point within the mesh area /// [Serializable] public class MeshObject { public List triangles; public float completeArea; protected Vector3 cacheVec; protected bool first = true; public MeshObject(List triangles) { this.triangles = triangles; completeArea = this.triangles.Sum(x => x.area); } /// /// Gets a random point in the mesh /// /// Random point public Vector3 RandomPointInMesh() { Triangle randomTriangle = triangles.WeightedSelection(completeArea, t => t.area); float x = Random.value, y = Random.value; if (x + y >= 1) { x = 1 - x; y = 1 - y; } float z = 1 - x - y; var randomBaryCentricPoint = new Vector3(x, y, z); // River: 直接返回数据.ATTENTION TO OPP:其实最后可以直接设置一个顶点当做是Node则可。 if (first) { this.cacheVec.x = x; this.cacheVec.y = y; this.cacheVec.z = z; first = false; } return cacheVec; /** 如果要返回随机点,则打开下面的代码。 Vector3 cartesianPoint = (randomBaryCentricPoint.x * randomTriangle.v0) + (randomBaryCentricPoint.y * randomTriangle.v1) + (randomBaryCentricPoint.z * randomTriangle.v2); return cartesianPoint;*/ } } }