#if MODULE_ENTITIES
using Unity.Entities;
using Unity.Mathematics;
namespace Pathfinding.ECS {
using Pathfinding;
using Pathfinding.PID;
public struct MovementState : IComponentData {
/// State of the PID controller for the movement
public PIDMovement.PersistentState followerState;
/// The next corner in the path
public float3 nextCorner;
///
/// 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.
///
public float3 endOfPath;
///
/// The closest point on the navmesh to the agent.
/// The agent will be snapped to this point.
///
public float3 closestOnNavmesh;
///
/// Offset from the agent's internal position to its visual position.
///
/// This is used when position smoothing is enabled. Otherwise it is zero.
///
public float3 positionOffset;
///
/// 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 . It is not guaranteed to be valid after that group has finished running, as graph updates may have changed the graph.
///
/// See:
///
public int hierarchicalNodeIndex;
/// The remaining distance until the end of the path, or the next off-mesh link
public float remainingDistanceToEndOfPart;
///
/// 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:
///
public float rotationOffset;
///
/// An additional, purely visual, rotation offset.
/// This is used for rotation smoothing, but does not affect the movement of the agent.
///
public float rotationOffset2;
///
/// Version number of when the movement state was last updated.
/// In particular, , , , , and will only
/// be considered up to date if this is equal to the current version number of the path tracer.
///
public ushort pathTracerVersion;
/// Bitmask for various flags
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;
///
/// 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 .
///
public bool reachedDestination {
get => (flags & ReachedDestinationFlag) != 0;
set => flags = (ushort)((flags & ~ReachedDestinationFlag) | (value ? ReachedDestinationFlag : 0));
}
///
/// 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:
/// - is true
/// - The agent is facing the desired facing direction as specified in .
///
public bool reachedDestinationAndOrientation {
get => (flags & reachedDestinationAndOrientationFlag) != 0;
set => flags = (ushort)((flags & ~reachedDestinationAndOrientationFlag) | (value ? reachedDestinationAndOrientationFlag : 0));
}
///
/// 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 .
///
public bool reachedEndOfPath {
get => (flags & ReachedEndOfPathFlag) != 0;
set => flags = (ushort)((flags & ~ReachedEndOfPathFlag) | (value ? ReachedEndOfPathFlag : 0));
}
///
/// 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:
/// - is true
/// - The agent is facing the desired facing direction as specified in .
///
public bool reachedEndOfPathAndOrientation {
get => (flags & reachedEndOfPathAndOrientationFlag) != 0;
set => flags = (ushort)((flags & ~reachedEndOfPathAndOrientationFlag) | (value ? reachedEndOfPathAndOrientationFlag : 0));
}
///
/// 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.
///
public bool reachedEndOfPart {
get => (flags & ReachedEndOfPartFlag) != 0;
set => flags = (ushort)((flags & ~ReachedEndOfPartFlag) | (value ? ReachedEndOfPartFlag : 0));
}
///
/// 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.
///
public bool traversingLastPart {
get => (flags & TraversingLastPartFlag) != 0;
set => flags = (ushort)((flags & ~TraversingLastPartFlag) | (value ? TraversingLastPartFlag : 0));
}
///
/// The index of the graph that the agent is currently traversing.
///
/// Will be if the agent has no path, or the node that the agent is traversing has been destroyed.
///
public uint graphIndex {
get => (uint)(flags >> 8);
internal set => flags = (ushort)((flags & 0xFF) | (ushort)(value << 8));
}
///
/// 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 and fields are invalid.
///
public bool isOnValidNode => hierarchicalNodeIndex != -1;
public MovementState(UnityEngine.Vector3 agentPosition) {
this = default;
SetPathIsEmpty(agentPosition);
}
/// Sets the appropriate fields to indicate that the agent has no path
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