123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522 |
- using UnityEngine;
- using System.Collections.Generic;
- namespace Pathfinding {
- using Pathfinding.Util;
-
- public abstract class NavmeshClipper : VersionedMonoBehaviour {
-
- static System.Action<NavmeshClipper> OnEnableCallback;
-
- static System.Action<NavmeshClipper> OnDisableCallback;
- static readonly List<NavmeshClipper> all = new List<NavmeshClipper>();
- int listIndex = -1;
-
-
-
-
-
-
-
-
-
-
-
- public GraphMask graphMask = GraphMask.everything;
- public static void AddEnableCallback (System.Action<NavmeshClipper> onEnable, System.Action<NavmeshClipper> onDisable) {
- OnEnableCallback += onEnable;
- OnDisableCallback += onDisable;
- }
- public static void RemoveEnableCallback (System.Action<NavmeshClipper> onEnable, System.Action<NavmeshClipper> onDisable) {
- OnEnableCallback -= onEnable;
- OnDisableCallback -= onDisable;
- }
-
-
-
-
-
- public static List<NavmeshClipper> allEnabled { get { return all; } }
- protected virtual void OnEnable () {
- if (OnEnableCallback != null) OnEnableCallback(this);
- listIndex = all.Count;
- all.Add(this);
- }
- protected virtual void OnDisable () {
-
-
-
- all[listIndex] = all[all.Count-1];
- all[listIndex].listIndex = listIndex;
- all.RemoveAt(all.Count-1);
- listIndex = -1;
- if (OnDisableCallback != null) OnDisableCallback(this);
- }
- internal abstract void NotifyUpdated();
- public abstract Rect GetBounds(GraphTransform transform);
- public abstract bool RequiresUpdate();
- public abstract void ForceUpdate();
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- [AddComponentMenu("Pathfinding/Navmesh/Navmesh Cut")]
- [HelpURL("http://arongranberg.com/astar/documentation/stable/class_pathfinding_1_1_navmesh_cut.php")]
- public class NavmeshCut : NavmeshClipper {
- public enum MeshType {
- Rectangle,
- Circle,
- CustomMesh
- }
-
- [Tooltip("Shape of the cut")]
- public MeshType type;
-
-
-
-
-
-
-
-
- [Tooltip("The contour(s) of the mesh will be extracted. This mesh should only be a 2D surface, not a volume (see documentation).")]
- public Mesh mesh;
-
- public Vector2 rectangleSize = new Vector2(1, 1);
-
- public float circleRadius = 1;
-
- public int circleResolution = 6;
-
- public float height = 1;
-
- [Tooltip("Scale of the custom mesh")]
- public float meshScale = 1;
- public Vector3 center;
-
-
-
-
-
- [Tooltip("Distance between positions to require an update of the navmesh\nA smaller distance gives better accuracy, but requires more updates when moving the object over time, so it is often slower.")]
- public float updateDistance = 0.4f;
-
-
-
-
- [Tooltip("Only makes a split in the navmesh, but does not remove the geometry to make a hole")]
- public bool isDual;
-
-
-
-
- public bool cutsAddedGeom = true;
-
-
-
-
-
-
- [Tooltip("How many degrees rotation that is required for an update to the navmesh. Should be between 0 and 180.")]
- public float updateRotationDistance = 10;
-
-
-
-
- [Tooltip("Includes rotation in calculations. This is slower since a lot more matrix multiplications are needed but gives more flexibility.")]
- [UnityEngine.Serialization.FormerlySerializedAsAttribute("useRotation")]
- public bool useRotationAndScale;
- Vector3[][] contours;
-
- protected Transform tr;
- Mesh lastMesh;
- Vector3 lastPosition;
- Quaternion lastRotation;
- protected override void Awake () {
- base.Awake();
- tr = transform;
- }
- protected override void OnEnable () {
- base.OnEnable();
- lastPosition = new Vector3(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity);
- lastRotation = tr.rotation;
- }
-
- static readonly Dictionary<Int2, int> edges = new Dictionary<Int2, int>();
-
- static readonly Dictionary<int, int> pointers = new Dictionary<int, int>();
-
-
-
-
-
-
-
- public override void ForceUpdate () {
- lastPosition = new Vector3(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity);
- }
-
-
-
-
-
- public override bool RequiresUpdate () {
- return (tr.position-lastPosition).sqrMagnitude > updateDistance*updateDistance || (useRotationAndScale && (Quaternion.Angle(lastRotation, tr.rotation) > updateRotationDistance));
- }
-
-
-
-
-
- public virtual void UsedForCut () {
- }
-
- internal override void NotifyUpdated () {
- lastPosition = tr.position;
- if (useRotationAndScale) {
- lastRotation = tr.rotation;
- }
- }
- void CalculateMeshContour () {
- if (mesh == null) return;
- edges.Clear();
- pointers.Clear();
- Vector3[] verts = mesh.vertices;
- int[] tris = mesh.triangles;
- for (int i = 0; i < tris.Length; i += 3) {
-
- if (VectorMath.IsClockwiseXZ(verts[tris[i+0]], verts[tris[i+1]], verts[tris[i+2]])) {
- int tmp = tris[i+0];
- tris[i+0] = tris[i+2];
- tris[i+2] = tmp;
- }
- edges[new Int2(tris[i+0], tris[i+1])] = i;
- edges[new Int2(tris[i+1], tris[i+2])] = i;
- edges[new Int2(tris[i+2], tris[i+0])] = i;
- }
-
- for (int i = 0; i < tris.Length; i += 3) {
- for (int j = 0; j < 3; j++) {
- if (!edges.ContainsKey(new Int2(tris[i+((j+1)%3)], tris[i+((j+0)%3)]))) {
- pointers[tris[i+((j+0)%3)]] = tris[i+((j+1)%3)];
- }
- }
- }
- var contourBuffer = new List<Vector3[]>();
- List<Vector3> buffer = Pathfinding.Util.ListPool<Vector3>.Claim();
-
- for (int i = 0; i < verts.Length; i++) {
- if (pointers.ContainsKey(i)) {
- buffer.Clear();
- int s = i;
- do {
- int tmp = pointers[s];
-
- if (tmp == -1) break;
- pointers[s] = -1;
- buffer.Add(verts[s]);
- s = tmp;
- if (s == -1) {
- Debug.LogError("Invalid Mesh '" + mesh.name + " in " + gameObject.name);
- break;
- }
- } while (s != i);
- if (buffer.Count > 0) contourBuffer.Add(buffer.ToArray());
- }
- }
-
- Pathfinding.Util.ListPool<Vector3>.Release(ref buffer);
- contours = contourBuffer.ToArray();
- }
-
-
-
-
-
- public override Rect GetBounds (GraphTransform inverseTransform) {
- var buffers = Pathfinding.Util.ListPool<List<Vector3> >.Claim();
- GetContour(buffers);
- Rect r = new Rect();
- for (int i = 0; i < buffers.Count; i++) {
- var buffer = buffers[i];
- for (int k = 0; k < buffer.Count; k++) {
- var p = inverseTransform.InverseTransform(buffer[k]);
- if (k == 0) {
- r = new Rect(p.x, p.z, 0, 0);
- } else {
- r.xMax = System.Math.Max(r.xMax, p.x);
- r.yMax = System.Math.Max(r.yMax, p.z);
- r.xMin = System.Math.Min(r.xMin, p.x);
- r.yMin = System.Math.Min(r.yMin, p.z);
- }
- }
- }
- Pathfinding.Util.ListPool<List<Vector3> >.Release(ref buffers);
- return r;
- }
-
-
-
-
-
- public void GetContour (List<List<Vector3> > buffer) {
- if (circleResolution < 3) circleResolution = 3;
- bool reverse;
- switch (type) {
- case MeshType.Rectangle:
- List<Vector3> buffer0 = Pathfinding.Util.ListPool<Vector3>.Claim();
- buffer0.Add(new Vector3(-rectangleSize.x, 0, -rectangleSize.y)*0.5f);
- buffer0.Add(new Vector3(rectangleSize.x, 0, -rectangleSize.y)*0.5f);
- buffer0.Add(new Vector3(rectangleSize.x, 0, rectangleSize.y)*0.5f);
- buffer0.Add(new Vector3(-rectangleSize.x, 0, rectangleSize.y)*0.5f);
- reverse = (rectangleSize.x < 0) ^ (rectangleSize.y < 0);
- TransformBuffer(buffer0, reverse);
- buffer.Add(buffer0);
- break;
- case MeshType.Circle:
- buffer0 = Pathfinding.Util.ListPool<Vector3>.Claim(circleResolution);
- for (int i = 0; i < circleResolution; i++) {
- buffer0.Add(new Vector3(Mathf.Cos((i*2*Mathf.PI)/circleResolution), 0, Mathf.Sin((i*2*Mathf.PI)/circleResolution))*circleRadius);
- }
- reverse = circleRadius < 0;
- TransformBuffer(buffer0, reverse);
- buffer.Add(buffer0);
- break;
- case MeshType.CustomMesh:
- if (mesh != lastMesh || contours == null) {
- CalculateMeshContour();
- lastMesh = mesh;
- }
- if (contours != null) {
- reverse = meshScale < 0;
- for (int i = 0; i < contours.Length; i++) {
- Vector3[] contour = contours[i];
- buffer0 = Pathfinding.Util.ListPool<Vector3>.Claim(contour.Length);
- for (int x = 0; x < contour.Length; x++) {
- buffer0.Add(contour[x]*meshScale);
- }
- TransformBuffer(buffer0, reverse);
- buffer.Add(buffer0);
- }
- }
- break;
- }
- }
- void TransformBuffer (List<Vector3> buffer, bool reverse) {
- var offset = center;
-
- if (useRotationAndScale) {
- var local2world = tr.localToWorldMatrix;
- for (int i = 0; i < buffer.Count; i++) buffer[i] = local2world.MultiplyPoint3x4(buffer[i] + offset);
- reverse ^= VectorMath.ReversesFaceOrientationsXZ(local2world);
- } else {
- offset += tr.position;
- for (int i = 0; i < buffer.Count; i++) buffer[i] += offset;
- }
- if (reverse) buffer.Reverse();
- }
- public static readonly Color GizmoColor = new Color(37.0f/255, 184.0f/255, 239.0f/255);
- public void OnDrawGizmos () {
- if (tr == null) tr = transform;
- var buffer = Pathfinding.Util.ListPool<List<Vector3> >.Claim();
- GetContour(buffer);
- Gizmos.color = GizmoColor;
-
- for (int i = 0; i < buffer.Count; i++) {
- var cont = buffer[i];
- for (int j = 0; j < cont.Count; j++) {
- Vector3 p1 = cont[j];
- Vector3 p2 = cont[(j+1) % cont.Count];
- Gizmos.DrawLine(p1, p2);
- }
- }
- Pathfinding.Util.ListPool<List<Vector3> >.Release(ref buffer);
- }
-
- internal float GetY (Pathfinding.Util.GraphTransform transform) {
- return transform.InverseTransform(useRotationAndScale ? tr.TransformPoint(center) : tr.position + center).y;
- }
- public void OnDrawGizmosSelected () {
- var buffer = Pathfinding.Util.ListPool<List<Vector3> >.Claim();
- GetContour(buffer);
- var col = Color.Lerp(GizmoColor, Color.white, 0.5f);
- col.a *= 0.5f;
- Gizmos.color = col;
- var graph = AstarPath.active != null ? (AstarPath.active.data.recastGraph as NavmeshBase ?? AstarPath.active.data.navmesh) : null;
- var transform = graph != null ? graph.transform : Pathfinding.Util.GraphTransform.identityTransform;
- float ymid = GetY(transform);
- float ymin = ymid - height*0.5f;
- float ymax = ymid + height*0.5f;
-
- for (int i = 0; i < buffer.Count; i++) {
- var cont = buffer[i];
- for (int j = 0; j < cont.Count; j++) {
- Vector3 p1 = transform.InverseTransform(cont[j]);
- Vector3 p2 = transform.InverseTransform(cont[(j+1) % cont.Count]);
- Vector3 p1low = p1, p2low = p2, p1high = p1, p2high = p2;
- p1low.y = p2low.y = ymin;
- p1high.y = p2high.y = ymax;
- Gizmos.DrawLine(transform.Transform(p1low), transform.Transform(p2low));
- Gizmos.DrawLine(transform.Transform(p1high), transform.Transform(p2high));
- Gizmos.DrawLine(transform.Transform(p1low), transform.Transform(p1high));
- }
- }
- Pathfinding.Util.ListPool<List<Vector3> >.Release(ref buffer);
- }
- }
- }
|