diff options
author | chai <215380520@qq.com> | 2024-05-23 10:08:29 +0800 |
---|---|---|
committer | chai <215380520@qq.com> | 2024-05-23 10:08:29 +0800 |
commit | 8722a9920c1f6119bf6e769cba270e63097f8e25 (patch) | |
tree | 2eaf9865de7fb1404546de4a4296553d8f68cc3b /Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components | |
parent | 3ba4020b69e5971bb0df7ee08b31d10ea4d01937 (diff) |
+ astar project
Diffstat (limited to 'Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components')
41 files changed, 1831 insertions, 0 deletions
diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/AgentCylinderShape.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/AgentCylinderShape.cs new file mode 100644 index 0000000..9909d0f --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/AgentCylinderShape.cs @@ -0,0 +1,18 @@ +#if MODULE_ENTITIES +using Unity.Entities; + +namespace Pathfinding.ECS { + using Pathfinding; + using Pathfinding.ECS.RVO; + + /// <summary>An agent's shape represented as a cylinder</summary> + [System.Serializable] + public struct AgentCylinderShape : IComponentData { + /// <summary>Radius of the agent in world units</summary> + public float radius; + + /// <summary>Height of the agent in world units</summary> + public float height; + } +} +#endif diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/AgentCylinderShape.cs.meta b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/AgentCylinderShape.cs.meta new file mode 100644 index 0000000..aa81963 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/AgentCylinderShape.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e9dd6a4018eb50a48b69d83cb69a09b9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/AgentMovementPlane.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/AgentMovementPlane.cs new file mode 100644 index 0000000..3321294 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/AgentMovementPlane.cs @@ -0,0 +1,30 @@ +#if MODULE_ENTITIES +using Unity.Entities; + +namespace Pathfinding.ECS { + using Pathfinding; + using Pathfinding.Util; + using Unity.Mathematics; + + /// <summary>Holds an agent's movement plane</summary> + [System.Serializable] + public struct AgentMovementPlane : IComponentData { + /// <summary> + /// The movement plane for the agent. + /// + /// The movement plane determines what the "up" direction of the agent is. + /// For most typical 3D games, this will be aligned with the Y axis, but there are + /// games in which the agent needs to navigate on walls, or on spherical worlds. + /// For those games this movement plane will track the plane in which the agent is currently moving. + /// + /// See: spherical (view in online documentation for working links) + /// </summary> + public NativeMovementPlane value; + + /// <summary>Create a movement plane aligned with the XZ plane of the specified rotation</summary> + public AgentMovementPlane (quaternion rotation) { + value = new NativeMovementPlane(rotation); + } + } +} +#endif diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/AgentMovementPlane.cs.meta b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/AgentMovementPlane.cs.meta new file mode 100644 index 0000000..9e6ebba --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/AgentMovementPlane.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b7137ab6e696b37428b1bec8e09e78ad +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/AgentMovementPlaneSource.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/AgentMovementPlaneSource.cs new file mode 100644 index 0000000..1bcfbb4 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/AgentMovementPlaneSource.cs @@ -0,0 +1,15 @@ +#if MODULE_ENTITIES +using Unity.Entities; + +namespace Pathfinding.ECS { + /// <summary> + /// The movement plane source for an agent. + /// + /// See: <see cref="MovementPlaneSource"/> + /// </summary> + [System.Serializable] + public struct AgentMovementPlaneSource : ISharedComponentData { + public MovementPlaneSource value; + } +} +#endif diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/AgentMovementPlaneSource.cs.meta b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/AgentMovementPlaneSource.cs.meta new file mode 100644 index 0000000..e3a1b88 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/AgentMovementPlaneSource.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a2198aa10fd82b94db223e3dbec9352b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/AgentOffMeshLinkTraversal.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/AgentOffMeshLinkTraversal.cs new file mode 100644 index 0000000..0b79f59 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/AgentOffMeshLinkTraversal.cs @@ -0,0 +1,388 @@ +#if MODULE_ENTITIES +using Unity.Entities; +using Unity.Mathematics; +using Unity.Transforms; + +namespace Pathfinding.ECS { + using Pathfinding; + using Pathfinding.Util; + using Unity.Collections.LowLevel.Unsafe; + using UnityEngine; + + /// <summary> + /// Holds unmanaged information about an off-mesh link that the agent is currently traversing. + /// This component is added to the agent when it starts traversing an off-mesh link. + /// It is removed when the agent has finished traversing the link. + /// + /// See: <see cref="ManagedAgentOffMeshLinkTraversal"/> + /// </summary> + public struct AgentOffMeshLinkTraversal : IComponentData { + /// <summary>\copydocref{OffMeshLinks.OffMeshLinkTracer.relativeStart}</summary> + public float3 relativeStart; + + /// <summary>\copydocref{OffMeshLinks.OffMeshLinkTracer.relativeEnd}</summary> + public float3 relativeEnd; + + /// <summary>\copydocref{OffMeshLinks.OffMeshLinkTracer.relativeStart}. Deprecated: Use relativeStart instead</summary> + [System.Obsolete("Use relativeStart instead")] + public float3 firstPosition => relativeStart; + + /// <summary>\copydocref{OffMeshLinks.OffMeshLinkTracer.relativeEnd}. Deprecated: Use relativeEnd instead</summary> + [System.Obsolete("Use relativeEnd instead")] + public float3 secondPosition => relativeEnd; + + /// <summary>\copydocref{OffMeshLinks.OffMeshLinkTracer.isReverse}</summary> + public bool isReverse; + + public AgentOffMeshLinkTraversal (OffMeshLinks.OffMeshLinkTracer linkInfo) { + relativeStart = linkInfo.relativeStart; + relativeEnd = linkInfo.relativeEnd; + isReverse = linkInfo.isReverse; + } + } + + /// <summary> + /// Holds managed information about an off-mesh link that the agent is currently traversing. + /// This component is added to the agent when it starts traversing an off-mesh link. + /// It is removed when the agent has finished traversing the link. + /// + /// See: <see cref="AgentOffMeshLinkTraversal"/> + /// </summary> + public class ManagedAgentOffMeshLinkTraversal : IComponentData, System.ICloneable, ICleanupComponentData { + /// <summary>Internal context used to pass component data to the coroutine</summary> + public AgentOffMeshLinkTraversalContext context; + + /// <summary>Coroutine which is used to traverse the link</summary> + public System.Collections.IEnumerator coroutine; + public IOffMeshLinkHandler handler; + public IOffMeshLinkStateMachine stateMachine; + + public ManagedAgentOffMeshLinkTraversal() {} + + public ManagedAgentOffMeshLinkTraversal (AgentOffMeshLinkTraversalContext context, IOffMeshLinkHandler handler) { + this.context = context; + this.handler = handler; + this.coroutine = null; + this.stateMachine = null; + } + + public object Clone () { + // This will set coroutine and stateMachine to null. + // This is correct, as the coroutine cannot be cloned, and the state machine may be unique for a specific agent + return new ManagedAgentOffMeshLinkTraversal((AgentOffMeshLinkTraversalContext)context.Clone(), handler); + } + } + + public struct MovementTarget { + internal bool isReached; + public bool reached => isReached; + + public MovementTarget (bool isReached) { + this.isReached = isReached; + } + } + + /// <summary> + /// Context with helpers for traversing an off-mesh link. + /// + /// This will be passed to the code that is responsible for traversing the off-mesh link. + /// + /// Warning: This context should never be accessed outside of an implementation of the <see cref="IOffMeshLinkStateMachine"/> interface. + /// </summary> + public class AgentOffMeshLinkTraversalContext : System.ICloneable { + internal unsafe AgentOffMeshLinkTraversal* linkInfoPtr; + internal unsafe MovementControl* movementControlPtr; + internal unsafe MovementSettings* movementSettingsPtr; + internal unsafe LocalTransform* transformPtr; + internal unsafe AgentMovementPlane* movementPlanePtr; + + /// <summary>The entity that is traversing the off-mesh link</summary> + public Entity entity; + + /// <summary>Some internal state of the agent</summary> + [Unity.Properties.DontCreateProperty] + public ManagedState managedState; + + /// <summary> + /// The off-mesh link that is being traversed. + /// + /// See: <see cref="link"/> + /// </summary> + [Unity.Properties.DontCreateProperty] + internal OffMeshLinks.OffMeshLinkConcrete concreteLink; + + protected bool disabledRVO; + protected float backupRotationSmoothing = float.NaN; + + /// <summary> + /// Delta time since the last link simulation. + /// + /// During high time scales, the simulation may run multiple substeps per frame. + /// + /// This is not the same as Time.deltaTime. Inside the link coroutine, you should always use this field instead of Time.deltaTime. + /// </summary> + public float deltaTime; + + protected GameObject gameObjectCache; + + /// <summary> + /// GameObject associated with the agent. + /// + /// In most cases, an agent is associated with an agent, but this is not always the case. + /// For example, if you have created an entity without using the <see cref="FollowerEntity"/> component, this property may return null. + /// + /// Note: When directly modifying the agent's transform during a link traversal, you should use the <see cref="transform"/> property instead of modifying the GameObject's transform. + /// </summary> + public virtual GameObject gameObject { + get { + if (gameObjectCache == null) { + var follower = BatchedEvents.Find<FollowerEntity, Entity>(entity, (follower, entity) => follower.entity == entity); + if (follower != null) gameObjectCache = follower.gameObject; + } + return gameObjectCache; + } + } + + /// <summary>ECS LocalTransform component attached to the agent</summary> + public ref LocalTransform transform { + get { + unsafe { + return ref *transformPtr; + } + } + } + + /// <summary>The movement settings for the agent</summary> + public ref MovementSettings movementSettings { + get { + unsafe { + return ref *movementSettingsPtr; + } + } + } + + /// <summary> + /// How the agent should move. + /// + /// The agent will move according to this data, every frame. + /// </summary> + public ref MovementControl movementControl { + get { + unsafe { + return ref *movementControlPtr; + } + } + } + + /// <summary>Information about the off-mesh link that the agent is traversing</summary> + public OffMeshLinks.OffMeshLinkTracer link { + get { + unsafe { + return new OffMeshLinks.OffMeshLinkTracer(concreteLink, linkInfoPtr->relativeStart, linkInfoPtr->relativeEnd, linkInfoPtr->isReverse); + } + } + } + + /// <summary> + /// Information about the off-mesh link that the agent is traversing. + /// + /// Deprecated: Use the <see cref="link"/> property instead + /// </summary> + [System.Obsolete("Use the link property instead")] + public AgentOffMeshLinkTraversal linkInfo { + get { + unsafe { + return *linkInfoPtr; + } + } + } + + /// <summary> + /// The plane in which the agent is moving. + /// + /// In a 3D game, this will typically be the XZ plane, but in a 2D game + /// it will typically be the XY plane. Games on spherical planets could have planes that are aligned with the surface of the planet. + /// </summary> + public ref NativeMovementPlane movementPlane { + get { + unsafe { + return ref movementPlanePtr->value; + } + } + } + + public AgentOffMeshLinkTraversalContext (OffMeshLinks.OffMeshLinkConcrete link) { + this.concreteLink = link; + } + + /// <summary> + /// Internal method to set the data of the context. + /// + /// This is used by the job system to set the data of the context. + /// You should almost never need to use this. + /// </summary> + public virtual unsafe void SetInternalData (Entity entity, ref LocalTransform transform, ref AgentMovementPlane movementPlane, ref MovementControl movementControl, ref MovementSettings movementSettings, ref AgentOffMeshLinkTraversal linkInfo, ManagedState state, float deltaTime) { + this.linkInfoPtr = (AgentOffMeshLinkTraversal*)UnsafeUtility.AddressOf(ref linkInfo); + this.movementControlPtr = (MovementControl*)UnsafeUtility.AddressOf(ref movementControl); + this.movementSettingsPtr = (MovementSettings*)UnsafeUtility.AddressOf(ref movementSettings); + this.transformPtr = (LocalTransform*)UnsafeUtility.AddressOf(ref transform); + this.movementPlanePtr = (AgentMovementPlane*)UnsafeUtility.AddressOf(ref movementPlane); + this.managedState = state; + this.deltaTime = deltaTime; + this.entity = entity; + } + + /// <summary> + /// Disables local avoidance for the agent. + /// + /// Agents that traverse links are already marked as 'unstoppable' by the local avoidance system, + /// but calling this method will make other agents ignore them completely while traversing the link. + /// </summary> + public void DisableLocalAvoidance () { + if (managedState.enableLocalAvoidance) { + disabledRVO = true; + managedState.enableLocalAvoidance = false; + } + } + + /// <summary> + /// Disables rotation smoothing for the agent. + /// + /// This disables the effect of <see cref="MovementSettings.rotationSmoothing"/> while the agent is traversing the link. + /// Having rotation smoothing enabled can make the agent rotate towards its target rotation more slowly, + /// which is sometimes not desirable. + /// + /// Rotation smoothing will automatically be restored when the agent finishes traversing the link (if it was enabled before). + /// + /// The <see cref="MoveTowards"/> method automatically disables rotation smoothing when called. + /// </summary> + public void DisableRotationSmoothing () { + if (float.IsNaN(backupRotationSmoothing) && movementSettings.rotationSmoothing > 0) { + backupRotationSmoothing = movementSettings.rotationSmoothing; + movementSettings.rotationSmoothing = 0; + } + } + + /// <summary> + /// Restores the agent's settings to what it was before the link traversal started. + /// + /// This undos the changes made by <see cref="DisableLocalAvoidance"/> and <see cref="DisableRotationSmoothing"/>. + /// + /// This method is automatically called when the agent finishes traversing the link. + /// </summary> + public virtual void Restore () { + if (disabledRVO) { + managedState.enableLocalAvoidance = true; + disabledRVO = false; + } + if (!float.IsNaN(backupRotationSmoothing)) { + movementSettings.rotationSmoothing = backupRotationSmoothing; + backupRotationSmoothing = float.NaN; + } + } + + /// <summary>Teleports the agent to the given position</summary> + public virtual void Teleport (float3 position) { + transform.Position = position; + } + + /// <summary> + /// Thrown when the off-mesh link traversal should be aborted. + /// + /// See: <see cref="AgentOffMeshLinkTraversal.Abort"/> + /// </summary> + public class AbortOffMeshLinkTraversal : System.Exception {} + + /// <summary> + /// Aborts traversing the off-mesh link. + /// + /// This will immediately stop your off-mesh link traversal coroutine. + /// + /// This is useful if your agent was traversing an off-mesh link, but you have detected that it cannot continue. + /// Maybe the ladder it was climbing was destroyed, or the bridge it was walking on collapsed. + /// + /// Note: If you instead want to immediately make the agent move to the end of the link, you can call <see cref="Teleport"/>, and then use 'yield break;' from your coroutine. + /// </summary> + /// <param name="teleportToStart">If true, the agent will be teleported back to the start of the link (from the perspective of the agent). Its rotation will remain unchanged.</param> + public virtual void Abort (bool teleportToStart = true) { + if (teleportToStart) Teleport(link.relativeStart); + // Cancel the current path, as otherwise the agent will instantly try to traverse the off-mesh link again. + managedState.pathTracer.SetFromSingleNode(managedState.pathTracer.startNode, transform.Position, movementPlane); + throw new AbortOffMeshLinkTraversal(); + } + + /// <summary> + /// Move towards a point while ignoring the navmesh. + /// This method should be called repeatedly until the returned <see cref="MovementTarget.reached"/> property is true. + /// + /// Returns: A <see cref="MovementTarget"/> struct which can be used to check if the target has been reached. + /// + /// Note: This method completely ignores the navmesh. It also overrides local avoidance, if enabled (other agents will still avoid it, but this agent will not avoid other agents). + /// + /// TODO: The gravity property is not yet implemented. Gravity is always applied. + /// </summary> + /// <param name="position">The position to move towards.</param> + /// <param name="rotation">The rotation to rotate towards.</param> + /// <param name="gravity">If true, gravity will be applied to the agent.</param> + /// <param name="slowdown">If true, the agent will slow down as it approaches the target.</param> + public virtual MovementTarget MoveTowards (float3 position, quaternion rotation, bool gravity, bool slowdown) { + // If rotation smoothing was enabled, it could cause a very slow convergence to the target rotation. + // Therefore, we disable it here. + // The agent will try to remove its remaining rotation smoothing offset as quickly as possible. + // After the off-mesh link is traversed, the rotation smoothing will be automatically restored. + DisableRotationSmoothing(); + + var dirInPlane = movementPlane.ToPlane(position - transform.Position); + var remainingDistance = math.length(dirInPlane); + var maxSpeed = movementSettings.follower.Speed(slowdown ? remainingDistance : float.PositiveInfinity); + var speed = movementSettings.follower.Accelerate(movementControl.speed, movementSettings.follower.slowdownTime, deltaTime); + speed = math.min(speed, maxSpeed); + + var targetRot = movementPlane.ToPlane(rotation); + var currentRot = movementPlane.ToPlane(transform.Rotation); + var remainingRot = Mathf.Abs(AstarMath.DeltaAngle(currentRot, targetRot)); + movementControl = new MovementControl { + targetPoint = position, + endOfPath = position, + speed = speed, + maxSpeed = speed * 1.1f, + hierarchicalNodeIndex = -1, + overrideLocalAvoidance = true, + targetRotation = targetRot, + targetRotationHint = targetRot, + targetRotationOffset = 0, + rotationSpeed = math.radians(movementSettings.follower.rotationSpeed), + }; + + return new MovementTarget { + isReached = remainingDistance <= (slowdown ? 0.01f : speed * (1/30f)) && remainingRot < math.radians(1), + }; + } + + public virtual object Clone () { + var clone = (AgentOffMeshLinkTraversalContext)MemberwiseClone(); + clone.entity = Entity.Null; + clone.gameObjectCache = null; + clone.managedState = null; + unsafe { + linkInfoPtr = null; + movementControlPtr = null; + movementSettingsPtr = null; + transformPtr = null; + movementPlanePtr = null; + } + return clone; + } + } +} + +// ctx.MoveTowards (position, rotation, rvo = Auto | Disabled | AutoUnstoppable, gravity = auto|disabled) -> { reached() } + +// MovementTarget { ... } +// while (!movementTarget.reached) { +// ctx.SetMovementTarget(movementTarget); +// yield return null; +// } +// yield return ctx.MoveTo(position, rotation) +// ctx.TeleportTo(position, rotation) +#endif diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/AgentOffMeshLinkTraversal.cs.meta b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/AgentOffMeshLinkTraversal.cs.meta new file mode 100644 index 0000000..28f8e71 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/AgentOffMeshLinkTraversal.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e7b7b15e5b39fc142a7dd409c4c3a18d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/AutoRepathPolicy.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/AutoRepathPolicy.cs new file mode 100644 index 0000000..a9324c1 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/AutoRepathPolicy.cs @@ -0,0 +1,97 @@ +#if MODULE_ENTITIES +using Unity.Entities; +using Unity.Mathematics; + +namespace Pathfinding.ECS { + /// <summary> + /// Policy for how often to recalculate an agent's path. + /// + /// See: <see cref="FollowerEntity.autoRepath"/> + /// + /// This is the unmanaged equivalent of <see cref="Pathfinding.AutoRepathPolicy"/>. + /// </summary> + [System.Serializable] + public struct AutoRepathPolicy : IComponentData { + /// <summary> + /// How sensitive the agent should be to changes in its destination for Mode.Dynamic. + /// A higher value means the destination has to move less for the path to be recalculated. + /// + /// See: <see cref="AutoRepathPolicy.Mode"/> + /// </summary> + public const float Sensitivity = 10.0f; + + /// <summary> + /// Policy to use when recalculating paths. + /// + /// See: <see cref="Pathfinding.AutoRepathPolicy.Mode"/> for more details. + /// </summary> + public Pathfinding.AutoRepathPolicy.Mode mode; + + /// <summary>Number of seconds between each automatic path recalculation for Mode.EveryNSeconds, and the maximum interval for Mode.Dynamic</summary> + public float period; + + float3 lastDestination; + float lastRepathTime; + + public static AutoRepathPolicy Default => new AutoRepathPolicy { + mode = Pathfinding.AutoRepathPolicy.Mode.Dynamic, + period = 2, + lastDestination = float.PositiveInfinity, + lastRepathTime = float.NegativeInfinity + }; + + public AutoRepathPolicy (Pathfinding.AutoRepathPolicy policy) { + mode = policy.mode; + period = policy.mode == Pathfinding.AutoRepathPolicy.Mode.Dynamic ? policy.maximumPeriod : policy.period; + lastDestination = float.PositiveInfinity; + lastRepathTime = float.NegativeInfinity; + } + + /// <summary> + /// True if the path should be recalculated according to the policy + /// + /// The above parameters are relevant only if <see cref="mode"/> is <see cref="Mode.Dynamic"/>. + /// </summary> + /// <param name="position">The current position of the agent.</param> + /// <param name="radius">The radius of the agent. You may pass 0.0 if the agent doesn't have a radius.</param> + /// <param name="destination">The goal of the agent right now</param> + /// <param name="time">The current time in seconds</param> + public bool ShouldRecalculatePath (float3 position, float radius, float3 destination, float time) { + if (mode == Pathfinding.AutoRepathPolicy.Mode.Never || float.IsPositiveInfinity(destination.x)) return false; + + float timeSinceLast = time - lastRepathTime; + if (mode == Pathfinding.AutoRepathPolicy.Mode.EveryNSeconds) { + return timeSinceLast >= period; + } else { + // cost = change in destination / max(distance to destination, radius) + float squaredCost = math.lengthsq(destination - lastDestination) / math.max(math.lengthsq(position - lastDestination), radius*radius); + float fraction = squaredCost * (Sensitivity*Sensitivity); + if (float.IsNaN(fraction)) { + // The agent's radius is zero, and the destination is precisely at the agent's position, which is also the destination of the last calculated path + // This is a special case. It happens sometimes for the AILerp component when it reaches its + // destination, as the AILerp component has no radius. + // In this case we just use the maximum period. + fraction = 0; + } + + return timeSinceLast >= period*(1 - math.sqrt(fraction)); + } + } + + public void Reset () { + lastDestination = float.PositiveInfinity; + lastRepathTime = float.NegativeInfinity; + } + + /// <summary>Must be called when a path request has been scheduled</summary> + public void DidRecalculatePath (float3 destination, float time) { + lastRepathTime = time; + lastDestination = destination; + // Randomize the repath time slightly so that all agents don't request a path at the same time + // in the future. This is useful when there are a lot of agents instantiated at exactly the same time. + const float JITTER_AMOUNT = 0.3f; + lastRepathTime -= (UnityEngine.Random.value - 0.5f) * JITTER_AMOUNT * period; + } + } +} +#endif diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/AutoRepathPolicy.cs.meta b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/AutoRepathPolicy.cs.meta new file mode 100644 index 0000000..0f99f79 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/AutoRepathPolicy.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 49e745654af51f043a68a105c85e2bae +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/DestinationPoint.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/DestinationPoint.cs new file mode 100644 index 0000000..d3ff623 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/DestinationPoint.cs @@ -0,0 +1,26 @@ +#if MODULE_ENTITIES +using Unity.Entities; +using Unity.Mathematics; + +namespace Pathfinding.ECS { + /// <summary>Holds an agent's destination point</summary> + public struct DestinationPoint : IComponentData { + /// <summary> + /// The destination point that the agent is moving towards. + /// + /// This is the point that the agent is trying to reach, but it may not always be possible to reach it. + /// + /// See: <see cref="AIDestinationSetter"/> + /// See: <see cref="IAstarAI.destination"/> + /// </summary> + public float3 destination; + + /// <summary> + /// The direction the agent should face when it reaches the destination. + /// + /// If zero, the agent will not try to face any particular direction when reaching the destination. + /// </summary> + public float3 facingDirection; + } +} +#endif diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/DestinationPoint.cs.meta b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/DestinationPoint.cs.meta new file mode 100644 index 0000000..ca2370d --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/DestinationPoint.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 87fc1fca9dfafa64b98ec33b24a358fa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/GravityState.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/GravityState.cs new file mode 100644 index 0000000..4ab8700 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/GravityState.cs @@ -0,0 +1,16 @@ +#if MODULE_ENTITIES +using Unity.Entities; +using Unity.Mathematics; + +namespace Pathfinding.ECS { + /// <summary>Agent state related to gravity</summary> + public struct GravityState : IComponentData, IEnableableComponent { + /// <summary> + /// Current vertical velocity of the agent. + /// This is the velocity that the agent is moving with due to gravity. + /// It is not necessarily the same as the Y component of the estimated velocity. + /// </summary> + public float verticalVelocity; + } +} +#endif diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/GravityState.cs.meta b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/GravityState.cs.meta new file mode 100644 index 0000000..2275bbb --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/GravityState.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ed943911778141b4988cbdcd7f5b3a07 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/ManagedMovementOverride.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/ManagedMovementOverride.cs new file mode 100644 index 0000000..4f45dab --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/ManagedMovementOverride.cs @@ -0,0 +1,91 @@ +#if MODULE_ENTITIES +using Unity.Entities; + +namespace Pathfinding.ECS { + using Unity.Transforms; + + public delegate void BeforeControlDelegate(Entity entity, float dt, ref LocalTransform localTransform, ref AgentCylinderShape shape, ref AgentMovementPlane movementPlane, ref DestinationPoint destination, ref MovementState movementState, ref MovementSettings movementSettings); + public delegate void AfterControlDelegate(Entity entity, float dt, ref LocalTransform localTransform, ref AgentCylinderShape shape, ref AgentMovementPlane movementPlane, ref DestinationPoint destination, ref MovementState movementState, ref MovementSettings movementSettings, ref MovementControl movementControl); + public delegate void BeforeMovementDelegate(Entity entity, float dt, ref LocalTransform localTransform, ref AgentCylinderShape shape, ref AgentMovementPlane movementPlane, ref DestinationPoint destination, ref MovementState movementState, ref MovementSettings movementSettings, ref MovementControl movementControl, ref ResolvedMovement resolvedMovement); + + /// <summary> + /// Helper for adding and removing hooks to the FollowerEntity component. + /// This is used to allow other systems to override the movement of the agent. + /// + /// See: <see cref="FollowerEntity.movementOverrides"/> + /// </summary> + public ref struct ManagedMovementOverrides { + Entity entity; + World world; + + public ManagedMovementOverrides (Entity entity, World world) { + this.entity = entity; + this.world = world; + } + + public void AddBeforeControlCallback (BeforeControlDelegate value) { + AddCallback<ManagedMovementOverrideBeforeControl, BeforeControlDelegate>(value); + } + public void RemoveBeforeControlCallback (BeforeControlDelegate value) { + RemoveCallback<ManagedMovementOverrideBeforeControl, BeforeControlDelegate>(value); + } + + public void AddAfterControlCallback (AfterControlDelegate value) { + AddCallback<ManagedMovementOverrideAfterControl, AfterControlDelegate>(value); + } + public void RemoveAfterControlCallback (AfterControlDelegate value) { + RemoveCallback<ManagedMovementOverrideAfterControl, AfterControlDelegate>(value); + } + + public void AddBeforeMovementCallback (BeforeMovementDelegate value) { + AddCallback<ManagedMovementOverrideBeforeMovement, BeforeMovementDelegate>(value); + } + public void RemoveBeforeMovementCallback (BeforeMovementDelegate value) { + RemoveCallback<ManagedMovementOverrideBeforeMovement, BeforeMovementDelegate>(value); + } + + void AddCallback<C, T>(T callback) where T : System.Delegate where C : ManagedMovementOverride<T>, IComponentData, new() { + if (callback == null) throw new System.ArgumentNullException(nameof(callback)); + if (world == null || !world.EntityManager.Exists(entity)) throw new System.InvalidOperationException("The entity does not exist. You can only set a callback when the FollowerEntity is active and has been enabled. If you are trying to set this during Awake or OnEnable, try setting it during Start instead."); + if (!world.EntityManager.HasComponent<C>(entity)) world.EntityManager.AddComponentData(entity, new C()); + world.EntityManager.GetComponentData<C>(entity).AddCallback(callback); + } + + void RemoveCallback<C, T>(T callback) where T : System.Delegate where C : ManagedMovementOverride<T>, IComponentData, new() { + if (callback == null) throw new System.ArgumentNullException(nameof(callback)); + if (world == null || !world.EntityManager.Exists(entity)) return; + if (!world.EntityManager.HasComponent<C>(entity)) return; + + var comp = world.EntityManager.GetComponentData<C>(entity); + if (!comp.RemoveCallback(callback)) { + world.EntityManager.RemoveComponent<C>(entity); + } + } + } + + /// <summary> + /// Stores a delegate that can be used to override movement control and movement settings for a specific entity. + /// This is used by the FollowerEntity to allow other systems to override the movement of the entity. + /// + /// See: <see cref="FollowerEntity.movementOverrides"/> + /// </summary> + public class ManagedMovementOverride<T> : IComponentData where T : class, System.Delegate { + public T callback; + + public void AddCallback(T callback) => this.callback = (T)System.Delegate.Combine(this.callback, callback); + public bool RemoveCallback(T callback) => (this.callback = (T)System.Delegate.Remove(this.callback, callback)) != null; + } + + // IJobEntity does not support generic jobs yet, so we have to make concrete component types for each delegate type + public class ManagedMovementOverrideBeforeControl : ManagedMovementOverride<BeforeControlDelegate>, System.ICloneable { + // No fields in this class can be cloned safely + public object Clone() => new ManagedMovementOverrideBeforeControl(); + } + public class ManagedMovementOverrideAfterControl : ManagedMovementOverride<AfterControlDelegate> { + public object Clone() => new ManagedMovementOverrideAfterControl(); + } + public class ManagedMovementOverrideBeforeMovement : ManagedMovementOverride<BeforeMovementDelegate> { + public object Clone() => new ManagedMovementOverrideBeforeMovement(); + } +} +#endif diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/ManagedMovementOverride.cs.meta b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/ManagedMovementOverride.cs.meta new file mode 100644 index 0000000..409fc88 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/ManagedMovementOverride.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ce6a314668bdcdd498d5d9d3ebf753c2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/ManagedState.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/ManagedState.cs new file mode 100644 index 0000000..d219541 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/ManagedState.cs @@ -0,0 +1,222 @@ +#if MODULE_ENTITIES +using Unity.Entities; + +namespace Pathfinding.ECS { + using Pathfinding; + using Pathfinding.ECS.RVO; + using UnityEngine.Serialization; + + /// <summary> + /// Settings for agent movement that cannot be put anywhere else. + /// + /// The Unity ECS in general wants everything in components to be unmanaged types. + /// However, some things cannot be unmanaged types, for example delegates and interfaces. + /// There are also other things like path references and node references which are not unmanaged types at the moment. + /// + /// This component is used to store those things. + /// + /// It can also be used for things that are not used often, and so are best kept out-of-band to avoid bloating the ECS chunks too much. + /// </summary> + [System.Serializable] + public class ManagedState : IComponentData, System.IDisposable, System.ICloneable { + /// <summary> + /// Settings for when to recalculate the path. + /// + /// Deprecated: Use <see cref="FollowerEntity.autoRepath"/>, or the <see cref="Pathfinding.ECS.AutoRepathPolicy"/> component instead. + /// </summary> + [System.Obsolete("Use FollowerEntity.autoRepath, or the Pathfinding.ECS.AutoRepathPolicy component instead")] + public Pathfinding.AutoRepathPolicy autoRepath = new Pathfinding.AutoRepathPolicy(); + + /// <summary>Calculates in which direction to move to follow the path</summary> + public PathTracer pathTracer; + + /// <summary> + /// Local avoidance settings. + /// + /// When the agent has local avoidance enabled, these settings will be copied into a <see cref="Pathfinding.ECS.RVO.RVOAgent"/> component which is attached to the agent. + /// + /// See: <see cref="enableLocalAvoidance"/> + /// </summary> + [FormerlySerializedAs("rvoAgent")] + public RVOAgent rvoSettings = RVOAgent.Default; + + /// <summary>Callback for when the agent starts to traverse an off-mesh link</summary> + [System.NonSerialized] + public IOffMeshLinkHandler onTraverseOffMeshLink; + + public PathRequestSettings pathfindingSettings = PathRequestSettings.Default; + + /// <summary> + /// True if local avoidance is enabled for this agent. + /// + /// Enabling this will automatically add a <see cref="Pathfinding.ECS.RVO.RVOAgent"/> component to the entity. + /// + /// See: local-avoidance (view in online documentation for working links) + /// </summary> + [FormerlySerializedAs("rvoEnabled")] + public bool enableLocalAvoidance; + + /// <summary> + /// True if gravity is enabled for this agent. + /// + /// The agent will always fall down according to its own movement plane. + /// The gravity applied is Physics.gravity.y. + /// + /// Enabling this will add the <see cref="GravityState"/> component to the entity. + /// </summary> + public bool enableGravity = true; + + /// <summary>Path that is being calculated, if any</summary> + // Do not create a property visitor for this field, as otherwise the ECS infrastructure will try to patch entities inside it, and get very confused. + // I haven't been able to replicate this issue recently, but it has caused problems in the past. + // [Unity.Properties.DontCreateProperty] + public Path pendingPath { get; private set; } + + /// <summary> + /// Path that is being followed, if any. + /// + /// The agent may have moved away from this path since it was calculated. So it may not be up to date. + /// </summary> + // Do not create a property visitor for this field, as otherwise the ECS infrastructure will try to patch entities inside it, and get very confused. + // [Unity.Properties.DontCreateProperty] + public Path activePath { get; private set; } + + /// <summary> + /// \copydocref{IAstarAI.SetPath}. + /// + /// Warning: In almost all cases you should use <see cref="FollowerEntity.SetPath"/> instead of this method. + /// </summary> + public static void SetPath (Path path, ManagedState state, in AgentMovementPlane movementPlane, ref DestinationPoint destination) { + if (path == null) { + state.CancelCurrentPathRequest(); + state.ClearPath(); + } else if (path.PipelineState == PathState.Created) { + // Path has not started calculation yet + state.CancelCurrentPathRequest(); + state.pendingPath = path; + path.Claim(state); + AstarPath.StartPath(path); + } else if (path.PipelineState >= PathState.ReturnQueue) { + // Path has already been calculated + + if (state.pendingPath == path) { + // The pending path is now obviously no longer pending + state.pendingPath = null; + } else { + // We might be calculating another path at the same time, and we don't want that path to override this one. So cancel it. + state.CancelCurrentPathRequest(); + + // Increase the refcount on the path. + // If the path was already our pending path, then the refcount will have already been incremented + path.Claim(state); + } + + var abPath = path as ABPath; + if (abPath == null) throw new System.ArgumentException("This function only works with ABPaths, or paths inheriting from ABPath"); + + if (!abPath.error) { + try { + state.pathTracer.SetPath(abPath, movementPlane.value); + + // Release the previous path back to the pool, to reduce GC pressure + if (state.activePath != null) state.activePath.Release(state); + + state.activePath = abPath; + } catch (System.Exception e) { + // If the path was so invalid that the path tracer throws an exception, then we should not use it. + abPath.Release(state); + state.ClearPath(); + UnityEngine.Debug.LogException(e); + } + + // If a RandomPath or MultiTargetPath have just been calculated, then we need + // to patch our destination point, to ensure the agent continues to move towards the end of the path. + // For these path types, the end point of the path is not known before the calculation starts. + if (!abPath.endPointKnownBeforeCalculation) { + destination = new DestinationPoint { destination = abPath.originalEndPoint, facingDirection = default }; + } + + // Right now, the pathTracer is almost fully up to date. + // To make it fully up to date, we'd also have to call pathTracer.UpdateStart and pathTracer.UpdateEnd after this function. + // During normal path recalculations, the JobRepairPath will be scheduled right after this function, and it will + // call those functions. The incomplete state will not be observable outside the system. + // When called from FollowerEntity, the SetPath method on that component will ensure that these methods are called. + } else { + abPath.Release(state); + } + } else { + // Path calculation has been started, but it is not yet complete. Cannot really handle this. + throw new System.ArgumentException("You must call the SetPath method with a path that either has been completely calculated or one whose path calculation has not been started at all. It looks like the path calculation for the path you tried to use has been started, but is not yet finished."); + } + } + + public void ClearPath () { + pathTracer.Clear(); + if (activePath != null) { + activePath.Release(this); + activePath = null; + } + } + + public void CancelCurrentPathRequest () { + if (pendingPath != null) { + pendingPath.FailWithError("Canceled by script"); + pendingPath.Release(this); + pendingPath = null; + } + } + + public void Dispose () { + pathTracer.Dispose(); + if (pendingPath != null) { + pendingPath.FailWithError("Canceled because entity was destroyed"); + pendingPath.Release(this); + pendingPath = null; + } + if (activePath != null) { + activePath.Release(this); + activePath = null; + } + } + + /// <summary> + /// Pops the current part, and the next part from the start of the path. + /// + /// It is assumed that the agent is currently on a normal NodeSequence part, and that the next part in the path is an off-mesh link. + /// </summary> + public void PopNextLinkFromPath () { + if (pathTracer.partCount < 2 && pathTracer.GetPartType(1) != Funnel.PartType.OffMeshLink) { + throw new System.InvalidOperationException("The next part in the path is not an off-mesh link."); + } + pathTracer.PopParts(2, pathfindingSettings.traversalProvider, activePath); + } + + /// <summary> + /// Clones the managed state for when an entity is duplicated. + /// + /// Some fields are cleared instead of being cloned, such as the pending path, + /// which cannot reasonably be cloned. + /// </summary> + object System.ICloneable.Clone () { + return new ManagedState { + #pragma warning disable 618 + autoRepath = autoRepath.Clone(), + #pragma warning restore 618 + pathTracer = pathTracer.Clone(), + rvoSettings = rvoSettings, + pathfindingSettings = new PathRequestSettings { + graphMask = pathfindingSettings.graphMask, + tagPenalties = pathfindingSettings.tagPenalties != null ? (int[])pathfindingSettings.tagPenalties.Clone() : null, + traversableTags = pathfindingSettings.traversableTags, + traversalProvider = null, // Cannot be safely cloned or copied + }, + enableLocalAvoidance = enableLocalAvoidance, + enableGravity = enableGravity, + onTraverseOffMeshLink = null, // Cannot be safely cloned or copied + pendingPath = null, // Cannot be safely cloned or copied + activePath = null, // Cannot be safely cloned or copied + }; + } + } +} +#endif diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/ManagedState.cs.meta b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/ManagedState.cs.meta new file mode 100644 index 0000000..6320c9e --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/ManagedState.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 33d1c95731798be41b90302b91409645 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/MovementControl.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/MovementControl.cs new file mode 100644 index 0000000..dfd03eb --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/MovementControl.cs @@ -0,0 +1,85 @@ +#if MODULE_ENTITIES +using Unity.Entities; +using Unity.Mathematics; + +namespace Pathfinding.ECS { + using Pathfinding; + using Pathfinding.Util; + + /// <summary> + /// Desired movement for an agent. + /// This data will be fed to the local avoidance system to calculate the final movement of the agent. + /// If no local avoidance is used, it will be directly copied to <see cref="ResolvedMovement"/>. + /// + /// See: <see cref="ResolvedMovement"/> + /// </summary> + public struct MovementControl : IComponentData { + /// <summary>The point the agent should move towards</summary> + public float3 targetPoint; + + /// <summary> + /// The end of the current path. + /// + /// This informs the local avoidance system about the final desired destination for the agent. + /// This is used to make agents stop if the destination is crowded and it cannot reach its destination. + /// + /// If this is not set, agents will often move forever around a crowded destination, always trying to find + /// some way to get closer, but never finding it. + /// </summary> + public float3 endOfPath; + + /// <summary>The speed at which the agent should move towards <see cref="targetPoint"/>, in meters per second</summary> + public float speed; + + /// <summary> + /// The maximum speed at which the agent may move, in meters per second. + /// + /// It is recommended to keep this slightly above <see cref="speed"/>, to allow the local avoidance system to move agents around more efficiently when necessary. + /// </summary> + public float maxSpeed; + + /// <summary> + /// The index of the hierarchical node that the agent is currently in. + /// Will be -1 if the hierarchical node index is not known. + /// See: <see cref="HierarchicalGraph"/> + /// </summary> + public int hierarchicalNodeIndex; + + /// <summary> + /// The desired rotation of the agent, in radians, relative to the current movement plane. + /// See: <see cref="NativeMovementPlane.ToWorldRotation"/> + /// </summary> + public float targetRotation; + + /// <summary> + /// The desired rotation of the agent, in radians, over a longer time horizon, relative to the current movement plane. + /// + /// The <see cref="targetRotation"/> is usually only over a very short time-horizon, usually a single simulation time step. + /// This variable is used to provide a hint of where the agent wants to rotate to over a slightly longer time scale (on the order of a second or so). + /// It is not used to control movement directly, but it may be used to guide animations, or rotation smoothing. + /// + /// If no better hint is available, this should be set to the same value as <see cref="targetRotation"/>. + /// + /// See: <see cref="NativeMovementPlane.ToWorldRotation"/> + /// </summary> + public float targetRotationHint; + + /// <summary> + /// Additive modifier to <see cref="targetRotation"/>, in radians. + /// This is used by the local avoidance system to rotate the agent, without this causing a feedback loop. + /// This extra rotation will be ignored by the control system which decides how the agent *wants* to move. + /// It will instead be directly applied to the agent. + /// </summary> + public float targetRotationOffset; + + /// <summary>The speed at which the agent should rotate towards <see cref="targetRotation"/> + <see cref="targetRotationOffset"/>, in radians per second</summary> + public float rotationSpeed; + + /// <summary> + /// If true, this agent will ignore other agents during local avoidance, but other agents will still avoid this one. + /// This is useful for example for a player character which should not avoid other agents, but other agents should avoid the player. + /// </summary> + public bool overrideLocalAvoidance; + } +} +#endif diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/MovementControl.cs.meta b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/MovementControl.cs.meta new file mode 100644 index 0000000..4c0b87a --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/MovementControl.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 067b0510e83c84e43b21eb81fb804132 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/MovementSettings.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/MovementSettings.cs new file mode 100644 index 0000000..b6e2bef --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/MovementSettings.cs @@ -0,0 +1,113 @@ +#if MODULE_ENTITIES +using Unity.Entities; +using UnityEngine; +using Unity.Mathematics; + +namespace Pathfinding.ECS { + using Pathfinding.PID; + + /// <summary>How to calculate which direction is "up" for the agent</summary> + public enum MovementPlaneSource : byte { + /// <summary> + /// The graph's natural up direction will be used to align the agent. + /// This is the most common option. + /// </summary> + Graph, + /// <summary> + /// The agent will be aligned with the normal of the navmesh. + /// + /// This is useful when you have a spherical world, or some other strange shape. + /// + /// The agent will look at the normal of the navmesh around the point it is currently standing on to determine which way is up. + /// The radius of the agent will be used to determine the size of the area to sample the normal from. + /// A bit of smoothing is done to make sure sharp changes in the normal do not cause the agent to rotate too fast. + /// + /// Note: If you have a somewhat flat world, and you want to align the agent to the ground, this is not the option you want. + /// Instead, you might want to disable <see cref="FollowerEntity.updateRotation"/> and then align the transform using a custom script. + /// + /// Warning: Using this option has a performance penalty. + /// + /// [Open online documentation to see videos] + /// + /// See: spherical (view in online documentation for working links) + /// </summary> + NavmeshNormal, + /// <summary> + /// The agent will be aligned with the ground normal. + /// + /// This is useful when you have a spherical world, or some other strange shape. + /// + /// You may want to use this instead of the NavmeshNormal option if your collider is smoother than your navmesh. + /// For example, if you have a spherical world with a sphere collider, you may want to use this option instead of the NavmeshNormal option. + /// + /// Note: If you have a somewhat flat world, and you want to align the agent to the ground, this is not the option you want. + /// Instead, you might want to disable <see cref="FollowerEntity.updateRotation"/> and then align the transform using a custom script. + /// + /// Warning: Using this option has a performance penalty. + /// </summary> + Raycast, + } + + [System.Serializable] + public struct MovementSettings : IComponentData { + /// <summary>Additional movement settings</summary> + public PIDMovement follower; + + /// <summary>Flags for enabling debug rendering in the scene view</summary> + public PIDMovement.DebugFlags debugFlags; + + /// <summary> + /// How far away from the destination should the agent aim to stop, in world units. + /// + /// If the agent is within this distance from the destination point it will be considered to have reached the destination. + /// + /// Even if you want the agent to stop precisely at a given point, it is recommended to keep this slightly above zero. + /// If it is exactly zero, the agent may have a hard time deciding that it + /// has actually reached the end of the path, due to floating point errors and such. + /// + /// Note: This will not be multiplied the agent's scale. + /// </summary> + public float stopDistance; + + /// <summary> + /// How much to smooth the visual rotation of the agent. + /// + /// This does not affect movement, but smoothes out how the agent rotates visually. + /// + /// Recommended values are between 0.0 and 0.5. + /// A value of zero will disable smoothing completely. + /// + /// The smoothing is done primarily using an exponential moving average, but with + /// a small linear term to make the rotation converge faster when the agent is almost facing the desired direction. + /// + /// Adding smoothing will make the visual rotation of the agent lag a bit behind the actual rotation. + /// Too much smoothing may make the agent seem sluggish, and appear to move sideways. + /// + /// The unit for this field is seconds. + /// </summary> + public float rotationSmoothing; + public float positionSmoothing; + + /// <summary> + /// Layer mask to use for ground placement. + /// Make sure this does not include the layer of any colliders attached to this gameobject. + /// + /// See: <see cref="GravityState"/> + /// See: https://docs.unity3d.com/Manual/Layers.html + /// </summary> + public LayerMask groundMask; + + /// <summary> + /// How to calculate which direction is "up" for the agent. + /// See: <see cref="MovementPlaneSource"/> + /// + /// Deprecated: Use the AgentMovementPlaneSource component instead, or the movementPlaneSource property on the FollowerEntity component + /// </summary> + [System.Obsolete("Use the AgentMovementPlaneSource component instead, or the movementPlaneSource property on the FollowerEntity component")] + public MovementPlaneSource movementPlaneSource; + + /// <summary>\copydocref{IAstarAI.isStopped}</summary> + public bool isStopped; + } +} +#endif diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/MovementSettings.cs.meta b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/MovementSettings.cs.meta new file mode 100644 index 0000000..734fcc4 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/MovementSettings.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a4fafdd860735074e8ca2abad75c3992 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/MovementState.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/MovementState.cs new file mode 100644 index 0000000..0ea83ad --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/MovementState.cs @@ -0,0 +1,196 @@ +#if MODULE_ENTITIES +using Unity.Entities; +using Unity.Mathematics; + +namespace Pathfinding.ECS { + using Pathfinding; + using Pathfinding.PID; + + public struct MovementState : IComponentData { + /// <summary>State of the PID controller for the movement</summary> + public PIDMovement.PersistentState followerState; + + /// <summary>The next corner in the path</summary> + public float3 nextCorner; + + /// <summary> + /// The end of the current path. + /// Note that the agent may be heading towards an off-mesh link which is not the same as this point. + /// </summary> + public float3 endOfPath; + + /// <summary> + /// The closest point on the navmesh to the agent. + /// The agent will be snapped to this point. + /// </summary> + public float3 closestOnNavmesh; + + /// <summary> + /// Offset from the agent's internal position to its visual position. + /// + /// This is used when position smoothing is enabled. Otherwise it is zero. + /// </summary> + public float3 positionOffset; + + /// <summary> + /// The index of the hierarchical node that the agent is currently in. + /// Will be -1 if the hierarchical node index is not known. + /// + /// This field is valid during all system updates in the <see cref="AIMovementSystemGroup"/>. It is not guaranteed to be valid after that group has finished running, as graph updates may have changed the graph. + /// + /// See: <see cref="HierarchicalGraph"/> + /// </summary> + public int hierarchicalNodeIndex; + + /// <summary>The remaining distance until the end of the path, or the next off-mesh link</summary> + public float remainingDistanceToEndOfPart; + + /// <summary> + /// The current additional rotation that is applied to the agent. + /// This is used by the local avoidance system to rotate the agent, without this causing a feedback loop. + /// + /// See: <see cref="ResolvedMovement.targetRotationOffset"/> + /// </summary> + public float rotationOffset; + + /// <summary> + /// An additional, purely visual, rotation offset. + /// This is used for rotation smoothing, but does not affect the movement of the agent. + /// </summary> + public float rotationOffset2; + + /// <summary> + /// Version number of <see cref="PathTracer.version"/> when the movement state was last updated. + /// In particular, <see cref="closestOnNavmesh"/>, <see cref="nextCorner"/>, <see cref="endOfPath"/>, <see cref="remainingDistanceToEndOfPart"/>, <see cref="reachedDestination"/> and <see cref="reachedEndOfPath"/> will only + /// be considered up to date if this is equal to the current version number of the path tracer. + /// </summary> + public ushort pathTracerVersion; + + /// <summary>Bitmask for various flags</summary> + ushort flags; + + const int ReachedDestinationFlag = 1 << 0; + const int reachedDestinationAndOrientationFlag = 1 << 1; + const int ReachedEndOfPathFlag = 1 << 2; + const int reachedEndOfPathAndOrientationFlag = 1 << 3; + const int ReachedEndOfPartFlag = 1 << 4; + const int TraversingLastPartFlag = 1 << 5; + + /// <summary> + /// True if the agent has reached its destination. + /// The destination will be considered reached if all of these conditions are met: + /// - The agent has a path + /// - The path is not stale + /// - The destination is not significantly below the agent's feet. + /// - The destination is not significantly above the agent's head. + /// - The agent is on the last part of the path (there are no more remaining off-mesh links). + /// - The remaining distance to the end of the path + the distance from the end of the path to the destination is less than <see cref="MovementSettings.stopDistance"/>. + /// </summary> + public bool reachedDestination { + get => (flags & ReachedDestinationFlag) != 0; + set => flags = (ushort)((flags & ~ReachedDestinationFlag) | (value ? ReachedDestinationFlag : 0)); + } + + /// <summary> + /// True if the agent has reached its destination and is facing the desired orientation. + /// This will become true if all of these conditions are met: + /// - <see cref="reachedDestination"/> is true + /// - The agent is facing the desired facing direction as specified in <see cref="DestinationPoint.facingDirection"/>. + /// </summary> + public bool reachedDestinationAndOrientation { + get => (flags & reachedDestinationAndOrientationFlag) != 0; + set => flags = (ushort)((flags & ~reachedDestinationAndOrientationFlag) | (value ? reachedDestinationAndOrientationFlag : 0)); + } + + /// <summary> + /// True if the agent has reached the end of the path. + /// The end of the path will be considered reached if all of these conditions are met: + /// - The agent has a path + /// - The path is not stale + /// - The end of the path is not significantly below the agent's feet. + /// - The end of the path is not significantly above the agent's head. + /// - The agent is on the last part of the path (there are no more remaining off-mesh links). + /// - The remaining distance to the end of the path is less than <see cref="MovementSettings.stopDistance"/>. + /// </summary> + public bool reachedEndOfPath { + get => (flags & ReachedEndOfPathFlag) != 0; + set => flags = (ushort)((flags & ~ReachedEndOfPathFlag) | (value ? ReachedEndOfPathFlag : 0)); + } + + /// <summary> + /// True if the agent has reached its destination and is facing the desired orientation. + /// This will become true if all of these conditions are met: + /// - <see cref="reachedEndOfPath"/> is true + /// - The agent is facing the desired facing direction as specified in <see cref="DestinationPoint.facingDirection"/>. + /// </summary> + public bool reachedEndOfPathAndOrientation { + get => (flags & reachedEndOfPathAndOrientationFlag) != 0; + set => flags = (ushort)((flags & ~reachedEndOfPathAndOrientationFlag) | (value ? reachedEndOfPathAndOrientationFlag : 0)); + } + + /// <summary> + /// True if the agent has reached the end of the current part in the path. + /// The end of the current part will be considered reached if all of these conditions are met: + /// - The agent has a path + /// - The path is not stale + /// - The end of the current part is not significantly below the agent's feet. + /// - The end of the current part is not significantly above the agent's head. + /// - The remaining distance to the end of the part is not significantly larger than the agent's radius. + /// </summary> + public bool reachedEndOfPart { + get => (flags & ReachedEndOfPartFlag) != 0; + set => flags = (ushort)((flags & ~ReachedEndOfPartFlag) | (value ? ReachedEndOfPartFlag : 0)); + } + + /// <summary> + /// True if the agent is traversing the last part of the path. + /// + /// If false, the agent will have to traverse at least one off-mesh link before it gets to its destination. + /// </summary> + public bool traversingLastPart { + get => (flags & TraversingLastPartFlag) != 0; + set => flags = (ushort)((flags & ~TraversingLastPartFlag) | (value ? TraversingLastPartFlag : 0)); + } + + /// <summary> + /// The index of the graph that the agent is currently traversing. + /// + /// Will be <see cref="GraphNode.InvalidGraphIndex"/> if the agent has no path, or the node that the agent is traversing has been destroyed. + /// </summary> + public uint graphIndex { + get => (uint)(flags >> 8); + internal set => flags = (ushort)((flags & 0xFF) | (ushort)(value << 8)); + } + + /// <summary> + /// True if the agent is currently on a valid node. + /// + /// This is true if the agent has a path, and the node that the agent is traversing is walkable and not destroyed. + /// + /// If false, the <see cref="hierarchicalNodeIndex"/> and <see cref="graphIndex"/> fields are invalid. + /// </summary> + public bool isOnValidNode => hierarchicalNodeIndex != -1; + + public MovementState(UnityEngine.Vector3 agentPosition) { + this = default; + SetPathIsEmpty(agentPosition); + } + + /// <summary>Sets the appropriate fields to indicate that the agent has no path</summary> + public void SetPathIsEmpty (UnityEngine.Vector3 agentPosition) { + nextCorner = agentPosition; + endOfPath = agentPosition; + closestOnNavmesh = agentPosition; + hierarchicalNodeIndex = -1; + remainingDistanceToEndOfPart = float.PositiveInfinity; + reachedEndOfPath = false; + reachedDestination = false; + reachedEndOfPart = false; + reachedDestinationAndOrientation = false; + reachedEndOfPathAndOrientation = false; + traversingLastPart = true; + graphIndex = GraphNode.InvalidGraphIndex; + } + } +} +#endif diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/MovementState.cs.meta b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/MovementState.cs.meta new file mode 100644 index 0000000..71f1c38 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/MovementState.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cd27960b09d0034419af8c9451a551fb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/MovementStatistics.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/MovementStatistics.cs new file mode 100644 index 0000000..d29781c --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/MovementStatistics.cs @@ -0,0 +1,17 @@ +#if MODULE_ENTITIES +using Unity.Entities; +using Unity.Mathematics; + +namespace Pathfinding.ECS { + public struct MovementStatistics : IComponentData { + /// <summary> + /// The estimated velocity that the agent is moving with. + /// This includes all form of movement, including local avoidance and gravity. + /// </summary> + public float3 estimatedVelocity; + + /// <summary>The position of the agent at the end of the last movement simulation step</summary> + public float3 lastPosition; + } +} +#endif diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/MovementStatistics.cs.meta b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/MovementStatistics.cs.meta new file mode 100644 index 0000000..3b36a89 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/MovementStatistics.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 40111712788bfc3409f6b39341f91e2a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/RVO.meta b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/RVO.meta new file mode 100644 index 0000000..30598c4 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/RVO.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 233cdeb50c94c714ab4c82711f977368 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/RVO/AgentIndex.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/RVO/AgentIndex.cs new file mode 100644 index 0000000..72d4c4c --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/RVO/AgentIndex.cs @@ -0,0 +1,58 @@ +using Pathfinding.RVO; +#if MODULE_ENTITIES +using Unity.Entities; +using Unity.Transforms; +#endif +using UnityEngine; +using Unity.Mathematics; + +namespace Pathfinding.ECS.RVO { + using Pathfinding.RVO; + + /// <summary> + /// Index of an RVO agent in the local avoidance simulation. + /// + /// If this component is present, that indicates that the agent is part of a local avoidance simulation. + /// The <see cref="RVOSystem"/> is responsible for adding and removing this component as necessary. + /// Any other systems should only concern themselves with the <see cref="RVOAgent"/> component. + /// + /// Warning: This component does not support cloning. You must not clone entities that use this component. + /// There doesn't seem to be any way to make this work with the Unity.Entities API at the moment. + /// </summary> +#if MODULE_ENTITIES + [WriteGroup(typeof(ResolvedMovement))] +#endif + public readonly struct AgentIndex +#if MODULE_ENTITIES + : Unity.Entities.ICleanupComponentData +#endif + { + internal const int DeletedBit = 1 << 31; + internal const int IndexMask = (1 << 24) - 1; + internal const int VersionOffset = 24; + internal const int VersionMask = 0b1111_111 << VersionOffset; + + public readonly int packedAgentIndex; + public int Index => packedAgentIndex & IndexMask; + public int Version => packedAgentIndex & VersionMask; + public bool Valid => (packedAgentIndex & DeletedBit) == 0; + + public AgentIndex(int packedAgentIndex) { + this.packedAgentIndex = packedAgentIndex; + } + + public AgentIndex(int version, int index) { + version <<= VersionOffset; + UnityEngine.Assertions.Assert.IsTrue((index & IndexMask) == index); + packedAgentIndex = (version & VersionMask) | (index & IndexMask); + } + + public AgentIndex WithIncrementedVersion () { + return new AgentIndex((((packedAgentIndex & VersionMask) + (1 << VersionOffset)) & VersionMask) | Index); + } + + public AgentIndex WithDeleted () { + return new AgentIndex(packedAgentIndex | DeletedBit); + } + } +} diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/RVO/AgentIndex.cs.meta b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/RVO/AgentIndex.cs.meta new file mode 100644 index 0000000..b67b67e --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/RVO/AgentIndex.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cd00f859416fc5c4f984c5680d19fc7d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/RVO/RVOAgent.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/RVO/RVOAgent.cs new file mode 100644 index 0000000..5049190 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/RVO/RVOAgent.cs @@ -0,0 +1,94 @@ +#if MODULE_ENTITIES +using Pathfinding.RVO; +using Unity.Entities; +using UnityEngine; +using Unity.Transforms; +using Unity.Mathematics; + +namespace Pathfinding.ECS.RVO { + using Pathfinding.RVO; + + /// <summary> + /// Agent data for the local avoidance system. + /// + /// See: local-avoidance (view in online documentation for working links) + /// </summary> + [System.Serializable] + public struct RVOAgent : IComponentData { + /// <summary>How far into the future to look for collisions with other agents (in seconds)</summary> + [Tooltip("How far into the future to look for collisions with other agents (in seconds)")] + public float agentTimeHorizon; + + /// <summary>How far into the future to look for collisions with obstacles (in seconds)</summary> + [Tooltip("How far into the future to look for collisions with obstacles (in seconds)")] + public float obstacleTimeHorizon; + + /// <summary> + /// Max number of other agents to take into account. + /// A smaller value can reduce CPU load, a higher value can lead to better local avoidance quality. + /// </summary> + [Tooltip("Max number of other agents to take into account.\n" + + "A smaller value can reduce CPU load, a higher value can lead to better local avoidance quality.")] + public int maxNeighbours; + + /// <summary> + /// Specifies the avoidance layer for this agent. + /// The <see cref="collidesWith"/> mask on other agents will determine if they will avoid this agent. + /// </summary> + public RVOLayer layer; + + /// <summary> + /// Layer mask specifying which layers this agent will avoid. + /// You can set it as CollidesWith = RVOLayer.DefaultAgent | RVOLayer.Layer3 | RVOLayer.Layer6 ... + /// + /// This can be very useful in games which have multiple teams of some sort. For example you usually + /// want the agents in one team to avoid each other, but you do not want them to avoid the enemies. + /// + /// This field only affects which other agents that this agent will avoid, it does not affect how other agents + /// react to this agent. + /// + /// See: bitmasks (view in online documentation for working links) + /// See: http://en.wikipedia.org/wiki/Mask_(computing) + /// </summary> + [Pathfinding.EnumFlag] + public RVOLayer collidesWith; + + /// <summary>\copydocref{Pathfinding.RVO.IAgent.Priority}</summary> + [Tooltip("How strongly other agents will avoid this agent")] + [UnityEngine.Range(0, 1)] + public float priority; + + /// <summary> + /// Priority multiplier. + /// This functions identically to the <see cref="priority"/>, however it is not exposed in the Unity inspector. + /// It is primarily used by the <see cref="Pathfinding.RVO.RVODestinationCrowdedBehavior"/>. + /// </summary> + [System.NonSerialized] + public float priorityMultiplier; + + [System.NonSerialized] + public float flowFollowingStrength; + + /// <summary>Enables drawing debug information in the scene view</summary> + public AgentDebugFlags debug; + + /// <summary>A locked unit cannot move. Other units will still avoid it but avoidance quality is not the best.</summary> + [Tooltip("A locked unit cannot move. Other units will still avoid it. But avoidance quality is not the best")] + public bool locked; + + /// <summary>Good default settings for an RVO agent</summary> + public static readonly RVOAgent Default = new RVOAgent { + locked = false, + agentTimeHorizon = 1.0f, + obstacleTimeHorizon = 0.5f, + maxNeighbours = 10, + layer = RVOLayer.DefaultAgent, + collidesWith = (RVOLayer)(-1), + priority = 0.5f, + priorityMultiplier = 1.0f, + flowFollowingStrength = 0.0f, + debug = AgentDebugFlags.Nothing, + }; + } +} +#endif diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/RVO/RVOAgent.cs.meta b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/RVO/RVOAgent.cs.meta new file mode 100644 index 0000000..046cc35 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/RVO/RVOAgent.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 910690cbba23a2745a85046d13e5c03b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/ReadyToTraverseOffMeshLink.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/ReadyToTraverseOffMeshLink.cs new file mode 100644 index 0000000..43e179e --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/ReadyToTraverseOffMeshLink.cs @@ -0,0 +1,10 @@ +#if MODULE_ENTITIES +using Unity.Entities; + +namespace Pathfinding.ECS { + /// <summary>Enabled if the agnet is ready to start traversing an off-mesh link</summary> + [System.Serializable] + public struct ReadyToTraverseOffMeshLink : IComponentData, IEnableableComponent { + } +} +#endif diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/ReadyToTraverseOffMeshLink.cs.meta b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/ReadyToTraverseOffMeshLink.cs.meta new file mode 100644 index 0000000..bcfbe64 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/ReadyToTraverseOffMeshLink.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8473eb53e4d194545b1395c9301ffc55 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/ResolvedMovement.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/ResolvedMovement.cs new file mode 100644 index 0000000..d91a621 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/ResolvedMovement.cs @@ -0,0 +1,35 @@ +#if MODULE_ENTITIES +using Unity.Entities; +using Unity.Mathematics; + +namespace Pathfinding.ECS { + using Pathfinding; + using Pathfinding.Util; + + /// <summary> + /// Holds the final movement data for an entity. + /// This is the data that is used by the movement system to move the entity. + /// </summary> + public struct ResolvedMovement : IComponentData { + /// <summary>\copydocref{MovementControl.targetPoint}</summary> + public float3 targetPoint; + + /// <summary>\copydocref{MovementControl.speed}</summary> + public float speed; + + public float turningRadiusMultiplier; + + /// <summary>\copydocref{MovementControl.targetRotation}</summary> + public float targetRotation; + + /// <summary>\copydocref{MovementControl.targetRotationHint}</summary> + public float targetRotationHint; + + /// <summary>\copydocref{MovementControl.targetRotationOffset}</summary> + public float targetRotationOffset; + + /// <summary>\copydocref{MovementControl.rotationSpeed}</summary> + public float rotationSpeed; + } +} +#endif diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/ResolvedMovement.cs.meta b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/ResolvedMovement.cs.meta new file mode 100644 index 0000000..74542a5 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/ResolvedMovement.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 659b0f455df2f744189544436f88bf05 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/SearchState.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/SearchState.cs new file mode 100644 index 0000000..44c5eac --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/SearchState.cs @@ -0,0 +1,11 @@ +#if MODULE_ENTITIES +using Unity.Entities; +using Unity.Mathematics; + +namespace Pathfinding.ECS { + using Pathfinding; + + public struct SearchState : IComponentData { + } +} +#endif diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/SearchState.cs.meta b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/SearchState.cs.meta new file mode 100644 index 0000000..5198363 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/SearchState.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fe063c5087e811f47aec8d8889a66d68 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/SimulateMovement.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/SimulateMovement.cs new file mode 100644 index 0000000..49d316d --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/SimulateMovement.cs @@ -0,0 +1,46 @@ +#if MODULE_ENTITIES +using Unity.Entities; +using Unity.Mathematics; + +namespace Pathfinding.ECS { + using Pathfinding; + + /// <summary> + /// Tag component to enable movement for an entity. + /// Without this component, most systems will completely ignore the entity. + /// + /// There are some more specific components that can be used to selectively enable/disable some jobs: + /// - <see cref="SimulateMovementRepair"/> + /// - <see cref="SimulateMovementControl"/> + /// - <see cref="SimulateMovementFinalize"/> + /// + /// Removing one of the above components can be useful if you want to override the movement of an agent in some way. + /// </summary> + public struct SimulateMovement : IComponentData { + } + + /// <summary> + /// Tag component to allow the agent to repair its path and recalculate various statistics. + /// + /// Allows the <see cref="JobRepairPath"/> to run. + /// </summary> + public struct SimulateMovementRepair : IComponentData { + } + + /// <summary> + /// Tag component to allow the agent to calculate how it wants to move. + /// + /// Allows the <see cref="ControlJob"/> to run. + /// </summary> + public struct SimulateMovementControl : IComponentData { + } + + /// <summary> + /// Tag component to allow the agent to move according to its desired movement parameters. + /// + /// Allows <see cref="AIMoveSystem"/> to run the <see cref="JobApplyGravity"/>, <see cref="JobAlignAgentWithMovementDirection"/> and <see cref="JobMoveAgent"/> jobs. + /// </summary> + public struct SimulateMovementFinalize : IComponentData { + } +} +#endif diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/SimulateMovement.cs.meta b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/SimulateMovement.cs.meta new file mode 100644 index 0000000..485bb36 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/SimulateMovement.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 38abdbf4c8ebfd64aa17d17cfd43cc8e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/SyncWithTransform.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/SyncWithTransform.cs new file mode 100644 index 0000000..497b8b5 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/SyncWithTransform.cs @@ -0,0 +1,35 @@ +#if MODULE_ENTITIES +using Unity.Entities; +using Unity.Mathematics; + +namespace Pathfinding.ECS { + using Pathfinding; + + /// <summary> + /// Tag component to enable syncing between an agent's Transform and the agent entity's position. + /// + /// See: <see cref="FollowerEntity.updatePosition"/> + /// </summary> + public struct SyncPositionWithTransform : IComponentData { + } + + /// <summary> + /// Tag component to enable syncing between an agent's Transform and the agent entity's rotation. + /// + /// See: <see cref="FollowerEntity.updateRotation"/> + /// </summary> + public struct SyncRotationWithTransform : IComponentData { + } + + /// <summary> + /// Tag component to indicate that the agent's forward direction is along the Y axis. + /// + /// This is used to convert between the forward direction of the GameObject and the internal forward direction, which always uses +Z as forward. + /// + /// See: <see cref="FollowerEntity.orientation"/> + /// See: <see cref="OrientationMode"/> + /// </summary> + public struct OrientationYAxisForward : IComponentData { + } +} +#endif diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/SyncWithTransform.cs.meta b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/SyncWithTransform.cs.meta new file mode 100644 index 0000000..c3f179f --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Core/ECS/Components/SyncWithTransform.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 04e21506cb33eb847838b0a75fda6bf0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: |