Base.cs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713
  1. using UnityEngine;
  2. using System.Collections.Generic;
  3. using Pathfinding.Util;
  4. using Pathfinding.Serialization;
  5. namespace Pathfinding {
  6. /// <summary>
  7. /// Exposes internal methods for graphs.
  8. /// This is used to hide methods that should not be used by any user code
  9. /// but still have to be 'public' or 'internal' (which is pretty much the same as 'public'
  10. /// as this library is distributed with source code).
  11. ///
  12. /// Hiding the internal methods cleans up the documentation and IntelliSense suggestions.
  13. /// </summary>
  14. public interface IGraphInternals {
  15. string SerializedEditorSettings { get; set; }
  16. void OnDestroy();
  17. void DestroyAllNodes();
  18. IEnumerable<Progress> ScanInternal();
  19. void SerializeExtraInfo(GraphSerializationContext ctx);
  20. void DeserializeExtraInfo(GraphSerializationContext ctx);
  21. void PostDeserialization(GraphSerializationContext ctx);
  22. void DeserializeSettingsCompatibility(GraphSerializationContext ctx);
  23. }
  24. /// <summary>Base class for all graphs</summary>
  25. public abstract class NavGraph : IGraphInternals {
  26. /// <summary>Reference to the AstarPath object in the scene</summary>
  27. public AstarPath active;
  28. /// <summary>
  29. /// Used as an ID of the graph, considered to be unique.
  30. /// Note: This is Pathfinding.Util.Guid not System.Guid. A replacement for System.Guid was coded for better compatibility with iOS
  31. /// </summary>
  32. [JsonMember]
  33. public Guid guid;
  34. /// <summary>Default penalty to apply to all nodes</summary>
  35. [JsonMember]
  36. public uint initialPenalty;
  37. /// <summary>Is the graph open in the editor</summary>
  38. [JsonMember]
  39. public bool open;
  40. /// <summary>Index of the graph, used for identification purposes</summary>
  41. public uint graphIndex;
  42. /// <summary>
  43. /// Name of the graph.
  44. /// Can be set in the unity editor
  45. /// </summary>
  46. [JsonMember]
  47. public string name;
  48. /// <summary>
  49. /// Enable to draw gizmos in the Unity scene view.
  50. /// In the inspector this value corresponds to the state of
  51. /// the 'eye' icon in the top left corner of every graph inspector.
  52. /// </summary>
  53. [JsonMember]
  54. public bool drawGizmos = true;
  55. /// <summary>
  56. /// Used in the editor to check if the info screen is open.
  57. /// Should be inside UNITY_EDITOR only \<see cref="ifs"/> but just in case anyone tries to serialize a NavGraph instance using Unity, I have left it like this as it would otherwise cause a crash when building.
  58. /// Version 3.0.8.1 was released because of this bug only
  59. /// </summary>
  60. [JsonMember]
  61. public bool infoScreenOpen;
  62. /// <summary>Used in the Unity editor to store serialized settings for graph inspectors</summary>
  63. [JsonMember]
  64. string serializedEditorSettings;
  65. /// <summary>True if the graph exists, false if it has been destroyed</summary>
  66. internal bool exists { get { return active != null; } }
  67. /// <summary>
  68. /// Number of nodes in the graph.
  69. /// Note that this is, unless the graph type has overriden it, an O(n) operation.
  70. ///
  71. /// This is an O(1) operation for grid graphs and point graphs.
  72. /// For layered grid graphs it is an O(n) operation.
  73. /// </summary>
  74. public virtual int CountNodes () {
  75. int count = 0;
  76. GetNodes(node => count++);
  77. return count;
  78. }
  79. /// <summary>Calls a delegate with all nodes in the graph until the delegate returns false</summary>
  80. public void GetNodes (System.Func<GraphNode, bool> action) {
  81. bool cont = true;
  82. GetNodes(node => {
  83. if (cont) cont &= action(node);
  84. });
  85. }
  86. /// <summary>
  87. /// Calls a delegate with all nodes in the graph.
  88. /// This is the primary way of iterating through all nodes in a graph.
  89. ///
  90. /// Do not change the graph structure inside the delegate.
  91. ///
  92. /// <code>
  93. /// var gg = AstarPath.active.data.gridGraph;
  94. ///
  95. /// gg.GetNodes(node => {
  96. /// // Here is a node
  97. /// Debug.Log("I found a node at position " + (Vector3)node.position);
  98. /// });
  99. /// </code>
  100. ///
  101. /// If you want to store all nodes in a list you can do this
  102. ///
  103. /// <code>
  104. /// var gg = AstarPath.active.data.gridGraph;
  105. ///
  106. /// List<GraphNode> nodes = new List<GraphNode>();
  107. ///
  108. /// gg.GetNodes((System.Action<GraphNode>)nodes.Add);
  109. /// </code>
  110. ///
  111. /// See: <see cref="Pathfinding.AstarData.GetNodes"/>
  112. /// </summary>
  113. public abstract void GetNodes(System.Action<GraphNode> action);
  114. /// <summary>
  115. /// A matrix for translating/rotating/scaling the graph.
  116. /// Deprecated: Use the transform field (only available on some graph types) instead
  117. /// </summary>
  118. [System.Obsolete("Use the transform field (only available on some graph types) instead", true)]
  119. public Matrix4x4 matrix = Matrix4x4.identity;
  120. /// <summary>
  121. /// Inverse of matrix.
  122. /// Deprecated: Use the transform field (only available on some graph types) instead
  123. /// </summary>
  124. [System.Obsolete("Use the transform field (only available on some graph types) instead", true)]
  125. public Matrix4x4 inverseMatrix = Matrix4x4.identity;
  126. /// <summary>
  127. /// Use to set both matrix and inverseMatrix at the same time.
  128. /// Deprecated: Use the transform field (only available on some graph types) instead
  129. /// </summary>
  130. [System.Obsolete("Use the transform field (only available on some graph types) instead", true)]
  131. public void SetMatrix (Matrix4x4 m) {
  132. matrix = m;
  133. inverseMatrix = m.inverse;
  134. }
  135. /// <summary>
  136. /// Moves nodes in this graph.
  137. /// Deprecated: Use RelocateNodes(Matrix4x4) instead.
  138. /// To keep the same behavior you can call RelocateNodes(newMatrix * oldMatrix.inverse).
  139. /// </summary>
  140. [System.Obsolete("Use RelocateNodes(Matrix4x4) instead. To keep the same behavior you can call RelocateNodes(newMatrix * oldMatrix.inverse).")]
  141. public void RelocateNodes (Matrix4x4 oldMatrix, Matrix4x4 newMatrix) {
  142. RelocateNodes(newMatrix * oldMatrix.inverse);
  143. }
  144. /// <summary>
  145. /// Throws an exception if it is not safe to update internal graph data right now.
  146. ///
  147. /// It is safe to update graphs when graphs are being scanned, or inside a work item.
  148. /// In other cases pathfinding could be running at the same time, which would not appreciate graph data changing under its feet.
  149. ///
  150. /// See: <see cref="AstarPath.AddWorkItem"/>
  151. /// </summary>
  152. protected void AssertSafeToUpdateGraph () {
  153. if (!active.IsAnyWorkItemInProgress && !active.isScanning) {
  154. throw new System.Exception("Trying to update graphs when it is not safe to do so. Graph updates must be done inside a work item or when a graph is being scanned. See AstarPath.AddWorkItem");
  155. }
  156. }
  157. /// <summary>
  158. /// Moves the nodes in this graph.
  159. /// Multiplies all node positions by deltaMatrix.
  160. ///
  161. /// For example if you want to move all your nodes in e.g a point graph 10 units along the X axis from the initial position
  162. /// <code>
  163. /// var graph = AstarPath.data.pointGraph;
  164. /// var m = Matrix4x4.TRS (new Vector3(10,0,0), Quaternion.identity, Vector3.one);
  165. /// graph.RelocateNodes (m);
  166. /// </code>
  167. ///
  168. /// Note: For grid graphs, navmesh graphs and recast graphs it is recommended to
  169. /// use their custom overloads of the RelocateNodes method which take parameters
  170. /// for e.g center and nodeSize (and additional parameters) instead since
  171. /// they are both easier to use and are less likely to mess up pathfinding.
  172. ///
  173. /// Warning: This method is lossy for PointGraphs, so calling it many times may
  174. /// cause node positions to lose precision. For example if you set the scale
  175. /// to 0 in one call then all nodes will be scaled/moved to the same point and
  176. /// you will not be able to recover their original positions. The same thing
  177. /// happens for other - less extreme - values as well, but to a lesser degree.
  178. /// </summary>
  179. public virtual void RelocateNodes (Matrix4x4 deltaMatrix) {
  180. GetNodes(node => node.position = ((Int3)deltaMatrix.MultiplyPoint((Vector3)node.position)));
  181. }
  182. /// <summary>
  183. /// Returns the nearest node to a position.
  184. /// See: Pathfinding.NNConstraint.None
  185. /// </summary>
  186. /// <param name="position">The position to try to find a close node to</param>
  187. public NNInfoInternal GetNearest (Vector3 position) {
  188. return GetNearest(position, NNConstraint.None);
  189. }
  190. /// <summary>Returns the nearest node to a position using the specified NNConstraint.</summary>
  191. /// <param name="position">The position to try to find a close node to</param>
  192. /// <param name="constraint">Can for example tell the function to try to return a walkable node. If you do not get a good node back, consider calling GetNearestForce.</param>
  193. public NNInfoInternal GetNearest (Vector3 position, NNConstraint constraint) {
  194. return GetNearest(position, constraint, null);
  195. }
  196. /// <summary>Returns the nearest node to a position using the specified NNConstraint.</summary>
  197. /// <param name="position">The position to try to find a close node to</param>
  198. /// <param name="hint">Can be passed to enable some graph generators to find the nearest node faster.</param>
  199. /// <param name="constraint">Can for example tell the function to try to return a walkable node. If you do not get a good node back, consider calling GetNearestForce.</param>
  200. public virtual NNInfoInternal GetNearest (Vector3 position, NNConstraint constraint, GraphNode hint) {
  201. // This is a default implementation and it is pretty slow
  202. // Graphs usually override this to provide faster and more specialised implementations
  203. float maxDistSqr = constraint == null || constraint.constrainDistance ? AstarPath.active.maxNearestNodeDistanceSqr : float.PositiveInfinity;
  204. float minDist = float.PositiveInfinity;
  205. GraphNode minNode = null;
  206. float minConstDist = float.PositiveInfinity;
  207. GraphNode minConstNode = null;
  208. // Loop through all nodes and find the closest suitable node
  209. GetNodes(node => {
  210. float dist = (position-(Vector3)node.position).sqrMagnitude;
  211. if (dist < minDist) {
  212. minDist = dist;
  213. minNode = node;
  214. }
  215. if (dist < minConstDist && dist < maxDistSqr && (constraint == null || constraint.Suitable(node))) {
  216. minConstDist = dist;
  217. minConstNode = node;
  218. }
  219. });
  220. var nnInfo = new NNInfoInternal(minNode);
  221. nnInfo.constrainedNode = minConstNode;
  222. if (minConstNode != null) {
  223. nnInfo.constClampedPosition = (Vector3)minConstNode.position;
  224. } else if (minNode != null) {
  225. nnInfo.constrainedNode = minNode;
  226. nnInfo.constClampedPosition = (Vector3)minNode.position;
  227. }
  228. return nnInfo;
  229. }
  230. /// <summary>
  231. /// Returns the nearest node to a position using the specified <see cref="Pathfinding.NNConstraint"/>.
  232. /// Returns: an NNInfo. This method will only return an empty NNInfo if there are no nodes which comply with the specified constraint.
  233. /// </summary>
  234. public virtual NNInfoInternal GetNearestForce (Vector3 position, NNConstraint constraint) {
  235. return GetNearest(position, constraint);
  236. }
  237. /// <summary>
  238. /// Function for cleaning up references.
  239. /// This will be called on the same time as OnDisable on the gameObject which the AstarPath script is attached to (remember, not in the editor).
  240. /// Use for any cleanup code such as cleaning up static variables which otherwise might prevent resources from being collected.
  241. /// Use by creating a function overriding this one in a graph class, but always call base.OnDestroy () in that function.
  242. /// All nodes should be destroyed in this function otherwise a memory leak will arise.
  243. /// </summary>
  244. protected virtual void OnDestroy () {
  245. DestroyAllNodes();
  246. }
  247. /// <summary>
  248. /// Destroys all nodes in the graph.
  249. /// Warning: This is an internal method. Unless you have a very good reason, you should probably not call it.
  250. /// </summary>
  251. protected virtual void DestroyAllNodes () {
  252. GetNodes(node => node.Destroy());
  253. }
  254. /// <summary>
  255. /// Scan the graph.
  256. /// Deprecated: Use AstarPath.Scan() instead
  257. /// </summary>
  258. [System.Obsolete("Use AstarPath.Scan instead")]
  259. public void ScanGraph () {
  260. Scan();
  261. }
  262. /// <summary>
  263. /// Scan the graph.
  264. ///
  265. /// Consider using AstarPath.Scan() instead since this function only scans this graph and if you are using multiple graphs
  266. /// with connections between them, then it is better to scan all graphs at once.
  267. /// </summary>
  268. public void Scan () {
  269. active.Scan(this);
  270. }
  271. /// <summary>
  272. /// Internal method to scan the graph.
  273. /// Called from AstarPath.ScanAsync.
  274. /// Override this function to implement custom scanning logic.
  275. /// Progress objects can be yielded to show progress info in the editor and to split up processing
  276. /// over several frames when using async scanning.
  277. /// </summary>
  278. protected abstract IEnumerable<Progress> ScanInternal();
  279. /// <summary>
  280. /// Serializes graph type specific node data.
  281. /// This function can be overriden to serialize extra node information (or graph information for that matter)
  282. /// which cannot be serialized using the standard serialization.
  283. /// Serialize the data in any way you want and return a byte array.
  284. /// When loading, the exact same byte array will be passed to the DeserializeExtraInfo function.
  285. /// These functions will only be called if node serialization is enabled.
  286. /// </summary>
  287. protected virtual void SerializeExtraInfo (GraphSerializationContext ctx) {
  288. }
  289. /// <summary>
  290. /// Deserializes graph type specific node data.
  291. /// See: SerializeExtraInfo
  292. /// </summary>
  293. protected virtual void DeserializeExtraInfo (GraphSerializationContext ctx) {
  294. }
  295. /// <summary>
  296. /// Called after all deserialization has been done for all graphs.
  297. /// Can be used to set up more graph data which is not serialized
  298. /// </summary>
  299. protected virtual void PostDeserialization (GraphSerializationContext ctx) {
  300. }
  301. /// <summary>
  302. /// An old format for serializing settings.
  303. /// Deprecated: This is deprecated now, but the deserialization code is kept to
  304. /// avoid loosing data when upgrading from older versions.
  305. /// </summary>
  306. protected virtual void DeserializeSettingsCompatibility (GraphSerializationContext ctx) {
  307. guid = new Guid(ctx.reader.ReadBytes(16));
  308. initialPenalty = ctx.reader.ReadUInt32();
  309. open = ctx.reader.ReadBoolean();
  310. name = ctx.reader.ReadString();
  311. drawGizmos = ctx.reader.ReadBoolean();
  312. infoScreenOpen = ctx.reader.ReadBoolean();
  313. }
  314. /// <summary>Draw gizmos for the graph</summary>
  315. public virtual void OnDrawGizmos (RetainedGizmos gizmos, bool drawNodes) {
  316. if (!drawNodes) {
  317. return;
  318. }
  319. // This is a relatively slow default implementation.
  320. // subclasses of the base graph class may override
  321. // this method to draw gizmos in a more optimized way
  322. var hasher = new RetainedGizmos.Hasher(active);
  323. GetNodes(node => hasher.HashNode(node));
  324. // Update the gizmo mesh if necessary
  325. if (!gizmos.Draw(hasher)) {
  326. using (var helper = gizmos.GetGizmoHelper(active, hasher)) {
  327. GetNodes((System.Action<GraphNode>)helper.DrawConnections);
  328. }
  329. }
  330. if (active.showUnwalkableNodes) DrawUnwalkableNodes(active.unwalkableNodeDebugSize);
  331. }
  332. protected void DrawUnwalkableNodes (float size) {
  333. Gizmos.color = AstarColor.UnwalkableNode;
  334. GetNodes(node => {
  335. if (!node.Walkable) Gizmos.DrawCube((Vector3)node.position, Vector3.one*size);
  336. });
  337. }
  338. #region IGraphInternals implementation
  339. string IGraphInternals.SerializedEditorSettings { get { return serializedEditorSettings; } set { serializedEditorSettings = value; } }
  340. void IGraphInternals.OnDestroy () { OnDestroy(); }
  341. void IGraphInternals.DestroyAllNodes () { DestroyAllNodes(); }
  342. IEnumerable<Progress> IGraphInternals.ScanInternal () { return ScanInternal(); }
  343. void IGraphInternals.SerializeExtraInfo (GraphSerializationContext ctx) { SerializeExtraInfo(ctx); }
  344. void IGraphInternals.DeserializeExtraInfo (GraphSerializationContext ctx) { DeserializeExtraInfo(ctx); }
  345. void IGraphInternals.PostDeserialization (GraphSerializationContext ctx) { PostDeserialization(ctx); }
  346. void IGraphInternals.DeserializeSettingsCompatibility (GraphSerializationContext ctx) { DeserializeSettingsCompatibility(ctx); }
  347. #endregion
  348. }
  349. /// <summary>
  350. /// Handles collision checking for graphs.
  351. /// Mostly used by grid based graphs
  352. /// </summary>
  353. [System.Serializable]
  354. public class GraphCollision {
  355. /// <summary>
  356. /// Collision shape to use.
  357. /// See: <see cref="Pathfinding.ColliderType"/>
  358. /// </summary>
  359. public ColliderType type = ColliderType.Capsule;
  360. /// <summary>
  361. /// Diameter of capsule or sphere when checking for collision.
  362. /// When checking for collisions the system will check if any colliders
  363. /// overlap a specific shape at the node's position. The shape is determined
  364. /// by the <see cref="type"/> field.
  365. ///
  366. /// A diameter of 1 means that the shape has a diameter equal to the node's width,
  367. /// or in other words it is equal to <see cref="Pathfinding.GridGraph.nodeSize"/>.
  368. ///
  369. /// If <see cref="type"/> is set to Ray, this does not affect anything.
  370. ///
  371. /// [Open online documentation to see images]
  372. /// </summary>
  373. public float diameter = 1F;
  374. /// <summary>
  375. /// Height of capsule or length of ray when checking for collision.
  376. /// If <see cref="type"/> is set to Sphere, this does not affect anything.
  377. ///
  378. /// [Open online documentation to see images]
  379. ///
  380. /// Warning: In contrast to Unity's capsule collider and character controller this height does not include the end spheres of the capsule, but only the cylinder part.
  381. /// This is mostly for historical reasons.
  382. /// </summary>
  383. public float height = 2F;
  384. /// <summary>
  385. /// Height above the ground that collision checks should be done.
  386. /// For example, if the ground was found at y=0, collisionOffset = 2
  387. /// type = Capsule and height = 3 then the physics system
  388. /// will be queried to see if there are any colliders in a capsule
  389. /// for which the bottom sphere that is made up of is centered at y=2
  390. /// and the top sphere has its center at y=2+3=5.
  391. ///
  392. /// If type = Sphere then the sphere's center would be at y=2 in this case.
  393. /// </summary>
  394. public float collisionOffset;
  395. /// <summary>
  396. /// Direction of the ray when checking for collision.
  397. /// If <see cref="type"/> is not Ray, this does not affect anything
  398. /// </summary>
  399. public RayDirection rayDirection = RayDirection.Both;
  400. /// <summary>Layers to be treated as obstacles.</summary>
  401. public LayerMask mask;
  402. /// <summary>Layers to be included in the height check.</summary>
  403. public LayerMask heightMask = -1;
  404. /// <summary>
  405. /// The height to check from when checking height ('ray length' in the inspector).
  406. ///
  407. /// As the image below visualizes, different ray lengths can make the ray hit different things.
  408. /// The distance is measured up from the graph plane.
  409. ///
  410. /// [Open online documentation to see images]
  411. /// </summary>
  412. public float fromHeight = 100;
  413. /// <summary>
  414. /// Toggles thick raycast.
  415. /// See: https://docs.unity3d.com/ScriptReference/Physics.SphereCast.html
  416. /// </summary>
  417. public bool thickRaycast;
  418. /// <summary>
  419. /// Diameter of the thick raycast in nodes.
  420. /// 1 equals <see cref="Pathfinding.GridGraph.nodeSize"/>
  421. /// </summary>
  422. public float thickRaycastDiameter = 1;
  423. /// <summary>Make nodes unwalkable when no ground was found with the height raycast. If height raycast is turned off, this doesn't affect anything.</summary>
  424. public bool unwalkableWhenNoGround = true;
  425. /// <summary>
  426. /// Use Unity 2D Physics API.
  427. /// See: http://docs.unity3d.com/ScriptReference/Physics2D.html
  428. /// </summary>
  429. public bool use2D;
  430. /// <summary>Toggle collision check</summary>
  431. public bool collisionCheck = true;
  432. /// <summary>Toggle height check. If false, the grid will be flat</summary>
  433. public bool heightCheck = true;
  434. /// <summary>
  435. /// Direction to use as UP.
  436. /// See: Initialize
  437. /// </summary>
  438. public Vector3 up;
  439. /// <summary>
  440. /// <see cref="up"/> * <see cref="height"/>.
  441. /// See: Initialize
  442. /// </summary>
  443. private Vector3 upheight;
  444. /// <summary>Used for 2D collision queries</summary>
  445. private ContactFilter2D contactFilter;
  446. /// <summary>
  447. /// Just so that the Physics2D.OverlapPoint method has some buffer to store things in.
  448. /// We never actually read from this array, so we don't even care if this is thread safe.
  449. /// </summary>
  450. private static Collider2D[] dummyArray = new Collider2D[1];
  451. /// <summary>
  452. /// <see cref="diameter"/> * scale * 0.5.
  453. /// Where scale usually is <see cref="Pathfinding.GridGraph.nodeSize"/>
  454. /// See: Initialize
  455. /// </summary>
  456. private float finalRadius;
  457. /// <summary>
  458. /// <see cref="thickRaycastDiameter"/> * scale * 0.5.
  459. /// Where scale usually is <see cref="Pathfinding.GridGraph.nodeSize"/> See: Initialize
  460. /// </summary>
  461. private float finalRaycastRadius;
  462. /// <summary>Offset to apply after each raycast to make sure we don't hit the same point again in CheckHeightAll</summary>
  463. public const float RaycastErrorMargin = 0.005F;
  464. /// <summary>
  465. /// Sets up several variables using the specified matrix and scale.
  466. /// See: GraphCollision.up
  467. /// See: GraphCollision.upheight
  468. /// See: GraphCollision.finalRadius
  469. /// See: GraphCollision.finalRaycastRadius
  470. /// </summary>
  471. public void Initialize (GraphTransform transform, float scale) {
  472. up = (transform.Transform(Vector3.up) - transform.Transform(Vector3.zero)).normalized;
  473. upheight = up*height;
  474. finalRadius = diameter*scale*0.5F;
  475. finalRaycastRadius = thickRaycastDiameter*scale*0.5F;
  476. contactFilter = new ContactFilter2D { layerMask = mask, useDepth = false, useLayerMask = true, useNormalAngle = false, useTriggers = false };
  477. }
  478. /// <summary>
  479. /// Returns true if the position is not obstructed.
  480. /// If <see cref="collisionCheck"/> is false, this will always return true.
  481. /// </summary>
  482. public bool Check (Vector3 position) {
  483. if (!collisionCheck) {
  484. return true;
  485. }
  486. if (use2D) {
  487. switch (type) {
  488. case ColliderType.Capsule:
  489. case ColliderType.Sphere:
  490. return Physics2D.OverlapCircle(position, finalRadius, contactFilter, dummyArray) == 0;
  491. default:
  492. return Physics2D.OverlapPoint(position, contactFilter, dummyArray) == 0;
  493. }
  494. }
  495. position += up*collisionOffset;
  496. switch (type) {
  497. case ColliderType.Capsule:
  498. return !Physics.CheckCapsule(position, position+upheight, finalRadius, mask, QueryTriggerInteraction.Ignore);
  499. case ColliderType.Sphere:
  500. return !Physics.CheckSphere(position, finalRadius, mask, QueryTriggerInteraction.Ignore);
  501. default:
  502. switch (rayDirection) {
  503. case RayDirection.Both:
  504. return !Physics.Raycast(position, up, height, mask, QueryTriggerInteraction.Ignore) && !Physics.Raycast(position+upheight, -up, height, mask, QueryTriggerInteraction.Ignore);
  505. case RayDirection.Up:
  506. return !Physics.Raycast(position, up, height, mask, QueryTriggerInteraction.Ignore);
  507. default:
  508. return !Physics.Raycast(position+upheight, -up, height, mask, QueryTriggerInteraction.Ignore);
  509. }
  510. }
  511. }
  512. /// <summary>
  513. /// Returns the position with the correct height.
  514. /// If <see cref="heightCheck"/> is false, this will return position.
  515. /// </summary>
  516. public Vector3 CheckHeight (Vector3 position) {
  517. RaycastHit hit;
  518. bool walkable;
  519. return CheckHeight(position, out hit, out walkable);
  520. }
  521. /// <summary>
  522. /// Returns the position with the correct height.
  523. /// If <see cref="heightCheck"/> is false, this will return position.
  524. /// walkable will be set to false if nothing was hit.
  525. /// The ray will check a tiny bit further than to the grids base to avoid floating point errors when the ground is exactly at the base of the grid
  526. /// </summary>
  527. public Vector3 CheckHeight (Vector3 position, out RaycastHit hit, out bool walkable) {
  528. walkable = true;
  529. if (!heightCheck || use2D) {
  530. hit = new RaycastHit();
  531. return position;
  532. }
  533. if (thickRaycast) {
  534. var ray = new Ray(position+up*fromHeight, -up);
  535. if (Physics.SphereCast(ray, finalRaycastRadius, out hit, fromHeight+0.005F, heightMask, QueryTriggerInteraction.Ignore)) {
  536. return VectorMath.ClosestPointOnLine(ray.origin, ray.origin+ray.direction, hit.point);
  537. }
  538. walkable &= !unwalkableWhenNoGround;
  539. } else {
  540. // Cast a ray from above downwards to try to find the ground
  541. if (Physics.Raycast(position+up*fromHeight, -up, out hit, fromHeight+0.005F, heightMask, QueryTriggerInteraction.Ignore)) {
  542. return hit.point;
  543. }
  544. walkable &= !unwalkableWhenNoGround;
  545. }
  546. return position;
  547. }
  548. /// <summary>Internal buffer used by <see cref="CheckHeightAll"/></summary>
  549. RaycastHit[] hitBuffer = new RaycastHit[8];
  550. /// <summary>
  551. /// Returns all hits when checking height for position.
  552. /// Warning: Does not work well with thick raycast, will only return an object a single time
  553. ///
  554. /// Warning: The returned array is ephermal. It will be invalidated when this method is called again.
  555. /// If you need persistent results you should copy it.
  556. ///
  557. /// The returned array may be larger than the actual number of hits, the numHits out parameter indicates how many hits there actually were.
  558. /// </summary>
  559. public RaycastHit[] CheckHeightAll (Vector3 position, out int numHits) {
  560. if (!heightCheck || use2D) {
  561. hitBuffer[0] = new RaycastHit {
  562. point = position,
  563. distance = 0,
  564. };
  565. numHits = 1;
  566. return hitBuffer;
  567. }
  568. // Cast a ray from above downwards to try to find the ground
  569. #if UNITY_2017_1_OR_NEWER
  570. numHits = Physics.RaycastNonAlloc(position+up*fromHeight, -up, hitBuffer, fromHeight+0.005F, heightMask, QueryTriggerInteraction.Ignore);
  571. if (numHits == hitBuffer.Length) {
  572. // Try again with a larger buffer
  573. hitBuffer = new RaycastHit[hitBuffer.Length*2];
  574. return CheckHeightAll(position, out numHits);
  575. }
  576. return hitBuffer;
  577. #else
  578. var result = Physics.RaycastAll(position+up*fromHeight, -up, fromHeight+0.005F, heightMask, QueryTriggerInteraction.Ignore);
  579. numHits = result.Length;
  580. return result;
  581. #endif
  582. }
  583. public void DeserializeSettingsCompatibility (GraphSerializationContext ctx) {
  584. type = (ColliderType)ctx.reader.ReadInt32();
  585. diameter = ctx.reader.ReadSingle();
  586. height = ctx.reader.ReadSingle();
  587. collisionOffset = ctx.reader.ReadSingle();
  588. rayDirection = (RayDirection)ctx.reader.ReadInt32();
  589. mask = (LayerMask)ctx.reader.ReadInt32();
  590. heightMask = (LayerMask)ctx.reader.ReadInt32();
  591. fromHeight = ctx.reader.ReadSingle();
  592. thickRaycast = ctx.reader.ReadBoolean();
  593. thickRaycastDiameter = ctx.reader.ReadSingle();
  594. unwalkableWhenNoGround = ctx.reader.ReadBoolean();
  595. use2D = ctx.reader.ReadBoolean();
  596. collisionCheck = ctx.reader.ReadBoolean();
  597. heightCheck = ctx.reader.ReadBoolean();
  598. }
  599. }
  600. /// <summary>
  601. /// Determines collision check shape.
  602. /// See: <see cref="Pathfinding.GraphCollision"/>
  603. /// </summary>
  604. public enum ColliderType {
  605. /// <summary>Uses a Sphere, Physics.CheckSphere. In 2D this is a circle instead.</summary>
  606. Sphere,
  607. /// <summary>Uses a Capsule, Physics.CheckCapsule. This will behave identically to the Sphere mode in 2D.</summary>
  608. Capsule,
  609. /// <summary>Uses a Ray, Physics.Linecast. In 2D this is a single point instead.</summary>
  610. Ray
  611. }
  612. /// <summary>Determines collision check ray direction</summary>
  613. public enum RayDirection {
  614. Up, /// <summary>< Casts the ray from the bottom upwards</summary>
  615. Down, /// <summary>< Casts the ray from the top downwards</summary>
  616. Both /// <summary>< Casts two rays in both directions</summary>
  617. }
  618. }