summaryrefslogtreecommitdiff
path: root/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Graphs/Grid/GraphCollision.cs
diff options
context:
space:
mode:
authorchai <215380520@qq.com>2024-05-23 10:08:29 +0800
committerchai <215380520@qq.com>2024-05-23 10:08:29 +0800
commit8722a9920c1f6119bf6e769cba270e63097f8e25 (patch)
tree2eaf9865de7fb1404546de4a4296553d8f68cc3b /Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Graphs/Grid/GraphCollision.cs
parent3ba4020b69e5971bb0df7ee08b31d10ea4d01937 (diff)
+ astar project
Diffstat (limited to 'Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Graphs/Grid/GraphCollision.cs')
-rw-r--r--Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Graphs/Grid/GraphCollision.cs387
1 files changed, 387 insertions, 0 deletions
diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Graphs/Grid/GraphCollision.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Graphs/Grid/GraphCollision.cs
new file mode 100644
index 0000000..a21f179
--- /dev/null
+++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Graphs/Grid/GraphCollision.cs
@@ -0,0 +1,387 @@
+using UnityEngine;
+using System.Collections.Generic;
+using Unity.Collections;
+
+namespace Pathfinding.Graphs.Grid {
+ using Pathfinding.Util;
+ using Pathfinding.Graphs.Grid.Jobs;
+ using Pathfinding.Jobs;
+
+ /// <summary>
+ /// Handles collision checking for graphs.
+ /// Mostly used by grid based graphs
+ /// </summary>
+ [System.Serializable]
+ public class GraphCollision {
+ /// <summary>
+ /// Collision shape to use.
+ /// See: <see cref="ColliderType"/>
+ /// </summary>
+ public ColliderType type = ColliderType.Capsule;
+
+ /// <summary>
+ /// Diameter of capsule or sphere when checking for collision.
+ /// When checking for collisions the system will check if any colliders
+ /// overlap a specific shape at the node's position. The shape is determined
+ /// by the <see cref="type"/> field.
+ ///
+ /// A diameter of 1 means that the shape has a diameter equal to the node's width,
+ /// or in other words it is equal to <see cref="Pathfinding.GridGraph.nodeSize"/>.
+ ///
+ /// If <see cref="type"/> is set to Ray, this does not affect anything.
+ ///
+ /// [Open online documentation to see images]
+ /// </summary>
+ public float diameter = 1F;
+
+ /// <summary>
+ /// Height of capsule or length of ray when checking for collision.
+ /// If <see cref="type"/> is set to Sphere, this does not affect anything.
+ ///
+ /// [Open online documentation to see images]
+ ///
+ /// 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.
+ /// This is mostly for historical reasons.
+ /// </summary>
+ public float height = 2F;
+
+ /// <summary>
+ /// Height above the ground that collision checks should be done.
+ /// For example, if the ground was found at y=0, collisionOffset = 2
+ /// type = Capsule and height = 3 then the physics system
+ /// will be queried to see if there are any colliders in a capsule
+ /// for which the bottom sphere that is made up of is centered at y=2
+ /// and the top sphere has its center at y=2+3=5.
+ ///
+ /// If type = Sphere then the sphere's center would be at y=2 in this case.
+ /// </summary>
+ public float collisionOffset;
+
+ /// <summary>
+ /// Direction of the ray when checking for collision.
+ /// If <see cref="type"/> is not Ray, this does not affect anything
+ ///
+ /// Deprecated: Only the Both mode is supported now.
+ /// </summary>
+ [System.Obsolete("Only the Both mode is supported now")]
+ public RayDirection rayDirection = RayDirection.Both;
+
+ /// <summary>Layers to be treated as obstacles.</summary>
+ public LayerMask mask;
+
+ /// <summary>Layers to be included in the height check.</summary>
+ public LayerMask heightMask = -1;
+
+ /// <summary>
+ /// The height to check from when checking height ('ray length' in the inspector).
+ ///
+ /// As the image below visualizes, different ray lengths can make the ray hit different things.
+ /// The distance is measured up from the graph plane.
+ ///
+ /// [Open online documentation to see images]
+ /// </summary>
+ public float fromHeight = 100;
+
+ /// <summary>
+ /// Toggles thick raycast.
+ /// See: https://docs.unity3d.com/ScriptReference/Physics.SphereCast.html
+ /// </summary>
+ public bool thickRaycast;
+
+ /// <summary>
+ /// Diameter of the thick raycast in nodes.
+ /// 1 equals <see cref="Pathfinding.GridGraph.nodeSize"/>
+ /// </summary>
+ public float thickRaycastDiameter = 1;
+
+ /// <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>
+ public bool unwalkableWhenNoGround = true;
+
+ /// <summary>
+ /// Use Unity 2D Physics API.
+ ///
+ /// If enabled, the 2D Physics API will be used, and if disabled, the 3D Physics API will be used.
+ ///
+ /// This changes the collider types (see <see cref="type)"/> from 3D versions to their corresponding 2D versions. For example the sphere shape becomes a circle.
+ ///
+ /// The <see cref="heightCheck"/> setting will be ignored when 2D physics is used.
+ ///
+ /// See: http://docs.unity3d.com/ScriptReference/Physics2D.html
+ /// </summary>
+ public bool use2D;
+
+ /// <summary>Toggle collision check</summary>
+ public bool collisionCheck = true;
+
+ /// <summary>
+ /// Toggle height check. If false, the grid will be flat.
+ ///
+ /// This setting will be ignored when 2D physics is used.
+ /// </summary>
+ public bool heightCheck = true;
+
+ /// <summary>
+ /// Direction to use as UP.
+ /// See: Initialize
+ /// </summary>
+ public Vector3 up;
+
+ /// <summary>
+ /// <see cref="up"/> * <see cref="height"/>.
+ /// See: Initialize
+ /// </summary>
+ private Vector3 upheight;
+
+ /// <summary>Used for 2D collision queries</summary>
+ private ContactFilter2D contactFilter;
+
+ /// <summary>
+ /// Just so that the Physics2D.OverlapPoint method has some buffer to store things in.
+ /// We never actually read from this array, so we don't even care if this is thread safe.
+ /// </summary>
+ private static Collider2D[] dummyArray = new Collider2D[1];
+
+ /// <summary>
+ /// <see cref="diameter"/> * scale * 0.5.
+ /// Where scale usually is <see cref="Pathfinding.GridGraph.nodeSize"/>
+ /// See: Initialize
+ /// </summary>
+ private float finalRadius;
+
+ /// <summary>
+ /// <see cref="thickRaycastDiameter"/> * scale * 0.5.
+ /// Where scale usually is <see cref="Pathfinding.GridGraph.nodeSize"/> See: Initialize
+ /// </summary>
+ private float finalRaycastRadius;
+
+ /// <summary>Offset to apply after each raycast to make sure we don't hit the same point again in CheckHeightAll</summary>
+ public const float RaycastErrorMargin = 0.005F;
+
+ /// <summary>
+ /// Sets up several variables using the specified matrix and scale.
+ /// See: GraphCollision.up
+ /// See: GraphCollision.upheight
+ /// See: GraphCollision.finalRadius
+ /// See: GraphCollision.finalRaycastRadius
+ /// </summary>
+ public void Initialize (GraphTransform transform, float scale) {
+ up = (transform.Transform(Vector3.up) - transform.Transform(Vector3.zero)).normalized;
+ upheight = up*height;
+ finalRadius = diameter*scale*0.5F;
+ finalRaycastRadius = thickRaycastDiameter*scale*0.5F;
+ contactFilter = new ContactFilter2D { layerMask = mask, useDepth = false, useLayerMask = true, useNormalAngle = false, useTriggers = false };
+ }
+
+ /// <summary>
+ /// Returns true if the position is not obstructed.
+ /// If <see cref="collisionCheck"/> is false, this will always return true.
+ /// </summary>
+ public bool Check (Vector3 position) {
+ if (!collisionCheck) {
+ return true;
+ }
+
+ if (use2D) {
+ switch (type) {
+ case ColliderType.Capsule:
+ case ColliderType.Sphere:
+ return Physics2D.OverlapCircle(position, finalRadius, contactFilter, dummyArray) == 0;
+ default:
+ return Physics2D.OverlapPoint(position, contactFilter, dummyArray) == 0;
+ }
+ }
+
+ position += up*collisionOffset;
+ switch (type) {
+ case ColliderType.Capsule:
+ return !Physics.CheckCapsule(position, position+upheight, finalRadius, mask, QueryTriggerInteraction.Ignore);
+ case ColliderType.Sphere:
+ return !Physics.CheckSphere(position, finalRadius, mask, QueryTriggerInteraction.Ignore);
+ default:
+ return !Physics.Raycast(position, up, height, mask, QueryTriggerInteraction.Ignore) && !Physics.Raycast(position+upheight, -up, height, mask, QueryTriggerInteraction.Ignore);
+ }
+ }
+
+ /// <summary>
+ /// Returns the position with the correct height.
+ /// If <see cref="heightCheck"/> is false, this will return position.
+ /// </summary>
+ public Vector3 CheckHeight (Vector3 position) {
+ RaycastHit hit;
+ bool walkable;
+
+ return CheckHeight(position, out hit, out walkable);
+ }
+
+ /// <summary>
+ /// Returns the position with the correct height.
+ /// If <see cref="heightCheck"/> is false, this will return position.
+ /// walkable will be set to false if nothing was hit.
+ /// 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
+ /// </summary>
+ public Vector3 CheckHeight (Vector3 position, out RaycastHit hit, out bool walkable) {
+ walkable = true;
+
+ if (!heightCheck || use2D) {
+ hit = new RaycastHit();
+ return position;
+ }
+
+ if (thickRaycast) {
+ var ray = new Ray(position+up*fromHeight, -up);
+ if (Physics.SphereCast(ray, finalRaycastRadius, out hit, fromHeight+0.005F, heightMask, QueryTriggerInteraction.Ignore)) {
+ return VectorMath.ClosestPointOnLine(ray.origin, ray.origin+ray.direction, hit.point);
+ }
+
+ walkable &= !unwalkableWhenNoGround;
+ } else {
+ // Cast a ray from above downwards to try to find the ground
+ if (Physics.Raycast(position+up*fromHeight, -up, out hit, fromHeight+0.005F, heightMask, QueryTriggerInteraction.Ignore)) {
+ return hit.point;
+ }
+
+ walkable &= !unwalkableWhenNoGround;
+ }
+ return position;
+ }
+
+ /// <summary>Internal buffer used by <see cref="CheckHeightAll"/></summary>
+ RaycastHit[] hitBuffer = new RaycastHit[8];
+
+ /// <summary>
+ /// Returns all hits when checking height for position.
+ /// Warning: Does not work well with thick raycast, will only return an object a single time
+ ///
+ /// Warning: The returned array is ephermal. It will be invalidated when this method is called again.
+ /// If you need persistent results you should copy it.
+ ///
+ /// The returned array may be larger than the actual number of hits, the numHits out parameter indicates how many hits there actually were.
+ /// </summary>
+ public RaycastHit[] CheckHeightAll (Vector3 position, out int numHits) {
+ if (!heightCheck || use2D) {
+ hitBuffer[0] = new RaycastHit {
+ point = position,
+ distance = 0,
+ };
+ numHits = 1;
+ return hitBuffer;
+ }
+
+ // Cast a ray from above downwards to try to find the ground
+#if UNITY_2017_1_OR_NEWER
+ numHits = Physics.RaycastNonAlloc(position+up*fromHeight, -up, hitBuffer, fromHeight+0.005F, heightMask, QueryTriggerInteraction.Ignore);
+ if (numHits == hitBuffer.Length) {
+ // Try again with a larger buffer
+ hitBuffer = new RaycastHit[hitBuffer.Length*2];
+ return CheckHeightAll(position, out numHits);
+ }
+ return hitBuffer;
+#else
+ var result = Physics.RaycastAll(position+up*fromHeight, -up, fromHeight+0.005F, heightMask, QueryTriggerInteraction.Ignore);
+ numHits = result.Length;
+ return result;
+#endif
+ }
+
+ /// <summary>
+ /// Returns if the position is obstructed for all nodes using the Ray collision checking method.
+ /// collisionCheckResult[i] = true if there were no obstructions, false otherwise
+ /// </summary>
+ public void JobCollisionRay (NativeArray<Vector3> nodePositions, NativeArray<bool> collisionCheckResult, Vector3 up, Allocator allocationMethod, JobDependencyTracker dependencyTracker) {
+ var collisionRaycastCommands1 = dependencyTracker.NewNativeArray<RaycastCommand>(nodePositions.Length, allocationMethod);
+ var collisionRaycastCommands2 = dependencyTracker.NewNativeArray<RaycastCommand>(nodePositions.Length, allocationMethod);
+ var collisionHits1 = dependencyTracker.NewNativeArray<RaycastHit>(nodePositions.Length, allocationMethod);
+ var collisionHits2 = dependencyTracker.NewNativeArray<RaycastHit>(nodePositions.Length, allocationMethod);
+
+ // Fire rays from above down to the nodes' positions
+ new JobPrepareRaycasts {
+ origins = nodePositions,
+ originOffset = up * (height + collisionOffset),
+ direction = -up,
+ distance = height,
+ mask = mask,
+ physicsScene = Physics.defaultPhysicsScene,
+ raycastCommands = collisionRaycastCommands1,
+ }.Schedule(dependencyTracker);
+
+ // Fire rays from the node up towards the sky
+ new JobPrepareRaycasts {
+ origins = nodePositions,
+ originOffset = up * collisionOffset,
+ direction = up,
+ distance = height,
+ mask = mask,
+ physicsScene = Physics.defaultPhysicsScene,
+ raycastCommands = collisionRaycastCommands2,
+ }.Schedule(dependencyTracker);
+
+ dependencyTracker.ScheduleBatch(collisionRaycastCommands1, collisionHits1, 2048);
+ dependencyTracker.ScheduleBatch(collisionRaycastCommands2, collisionHits2, 2048);
+
+ new JobMergeRaycastCollisionHits {
+ hit1 = collisionHits1,
+ hit2 = collisionHits2,
+ result = collisionCheckResult,
+ }.Schedule(dependencyTracker);
+ }
+
+#if UNITY_2022_2_OR_NEWER
+ public void JobCollisionCapsule (NativeArray<Vector3> nodePositions, NativeArray<bool> collisionCheckResult, Vector3 up, Allocator allocationMethod, JobDependencyTracker dependencyTracker) {
+ var commands = dependencyTracker.NewNativeArray<OverlapCapsuleCommand>(nodePositions.Length, allocationMethod);
+ var collisionHits = dependencyTracker.NewNativeArray<ColliderHit>(nodePositions.Length, allocationMethod);
+ new JobPrepareCapsuleCommands {
+ origins = nodePositions,
+ originOffset = up * collisionOffset,
+ direction = up * height,
+ radius = finalRadius,
+ mask = mask,
+ commands = commands,
+ physicsScene = Physics.defaultPhysicsScene,
+ }.Schedule(dependencyTracker);
+ dependencyTracker.ScheduleBatch(commands, collisionHits, 2048);
+ new JobColliderHitsToBooleans {
+ hits = collisionHits,
+ result = collisionCheckResult,
+ }.Schedule(dependencyTracker);
+ }
+
+ public void JobCollisionSphere (NativeArray<Vector3> nodePositions, NativeArray<bool> collisionCheckResult, Vector3 up, Allocator allocationMethod, JobDependencyTracker dependencyTracker) {
+ var commands = dependencyTracker.NewNativeArray<OverlapSphereCommand>(nodePositions.Length, allocationMethod);
+ var collisionHits = dependencyTracker.NewNativeArray<ColliderHit>(nodePositions.Length, allocationMethod);
+ new JobPrepareSphereCommands {
+ origins = nodePositions,
+ originOffset = up * collisionOffset,
+ radius = finalRadius,
+ mask = mask,
+ commands = commands,
+ physicsScene = Physics.defaultPhysicsScene,
+ }.Schedule(dependencyTracker);
+ dependencyTracker.ScheduleBatch(commands, collisionHits, 2048);
+ new JobColliderHitsToBooleans {
+ hits = collisionHits,
+ result = collisionCheckResult,
+ }.Schedule(dependencyTracker);
+ }
+#endif
+ }
+
+ /// <summary>
+ /// Determines collision check shape.
+ /// See: <see cref="GraphCollision"/>
+ /// </summary>
+ public enum ColliderType {
+ /// <summary>Uses a Sphere, Physics.CheckSphere. In 2D this is a circle instead.</summary>
+ Sphere,
+ /// <summary>Uses a Capsule, Physics.CheckCapsule. This will behave identically to the Sphere mode in 2D.</summary>
+ Capsule,
+ /// <summary>Uses a Ray, Physics.Linecast. In 2D this is a single point instead.</summary>
+ Ray
+ }
+
+ /// <summary>Determines collision check ray direction</summary>
+ public enum RayDirection {
+ Up, /// <summary>< Casts the ray from the bottom upwards</summary>
+ Down, /// <summary>< Casts the ray from the top downwards</summary>
+ Both /// <summary>< Casts two rays in both directions</summary>
+ }
+}