/// <summary> /// Constructor /// </summary> /// <param name="startTime">Playback time when this action starts</param> /// <param name="agent">Scenario agent that will be moved by this action</param> /// <param name="previousAction">Previous agent's move action used for initial parameters</param> /// <param name="destination">Agent's destination position applied when the action ends</param> /// <param name="rotation">Agent's rotation which will be applied when this action is performed</param> /// <param name="destinationSpeed">Agent's destination speed used during the playback movement</param> /// <param name="acceleration">Agent's acceleration used during the playback movement</param> public AgentMoveAction(float startTime, ScenarioAgent agent, AgentMoveAction previousAction, Vector3 destination, Quaternion rotation, float destinationSpeed, float acceleration) : base( startTime) { Agent = agent; InitialPosition = previousAction?.Destination ?? Agent.TransformForPlayback.position; InitialRotation = Agent.TransformForPlayback.rotation; Destination = destination; Rotation = rotation; InitialSpeed = previousAction?.DestinationSpeed ?? 0.0f; DestinationSpeed = destinationSpeed; Acceleration = acceleration; var distance = Vector3.Distance(InitialPosition, destination); if (acceleration > 0) { // If max speed is lower than the initial speed convert acceleration to deceleration if (destinationSpeed < InitialSpeed) { Acceleration *= -1; } if (!UniformlyAcceleratedMotion.CalculateDuration(acceleration, InitialSpeed, distance, ref destinationSpeed, out var accelerationDuration, out var accelerationDistance)) { // Max speed will not be reached with current acceleration AccelerationDestination = destination; DestinationSpeed = destinationSpeed; Duration = AccelerationDuration = accelerationDuration; } else { // Calculate mixed duration of accelerated and linear movements AccelerationDestination = InitialPosition + (destination - InitialPosition).normalized * accelerationDistance; var linearDistance = distance - accelerationDistance; AccelerationDuration = accelerationDuration; Duration = AccelerationDuration + linearDistance / DestinationSpeed; } }
public void SetFollowWaypoints(List <DriveWaypoint> waypoints, bool loop, WaypointsPathType pathType) { InitPos = transform.position; InitRot = transform.rotation; WaypointLoop = loop; PathType = pathType; // Process waypoints according to the selected waypoint path switch (PathType) { case WaypointsPathType.Linear: break; case WaypointsPathType.BezierSpline: // Disable BezierSpline if timestamps are set if (waypoints[0].TimeStamp >= 0.0f) { Debug.LogError("Bezier Spline path is not supported if the timestamps are set in the waypoints."); PathType = WaypointsPathType.Linear; break; } // Add the initial position for Bezier Spline calculations var initWaypoint = ((IWaypoint)waypoints[0]).Clone(); initWaypoint.Position = InitPos; waypoints.Insert(0, (DriveWaypoint)initWaypoint); var bezier = new BezierSpline <DriveWaypoint>(waypoints.ToArray(), 0.01f); waypoints = bezier.GetBezierWaypoints(); // Remove first waypoint as it will be added by another function waypoints.RemoveAt(0); break; default: throw new ArgumentOutOfRangeException(nameof(PathType), PathType, null); } LaneData = waypoints.Select(wp => wp.Position).ToList(); LaneSpeed = waypoints.Select(wp => wp.Speed).ToList(); LaneAcceleration = waypoints.Select(wp => wp.Acceleration).ToList(); LaneAngle = waypoints.Select(wp => Quaternion.Euler(wp.Angle)).ToList(); LaneIdle = waypoints.Select(wp => wp.Idle).ToList(); LaneDeactivate = waypoints.Select(wp => wp.Deactivate).ToList(); LaneTriggerDistance = waypoints.Select(wp => wp.TriggerDistance).ToList(); LaneTime = waypoints.Select(wp => wp.TimeStamp).ToList(); LaneTriggers = waypoints.Select(wp => wp.Trigger).ToList(); InitNPC(); AddPoseToFirstWaypoint(); // Check if the timestamps should be replaced by calculations if (LaneTime[1] < 0.0f) { Debug.LogWarning("Waypoint timestamps absent or invalid, calculating timestamps based on speed and acceleration."); // Calculate acceleration data only if there are no timestamps for (int i = 0; i < LaneData.Count - 1; i++) { var initialPosition = LaneData[i]; var destination = LaneData[i + 1]; var initialSpeed = LaneSpeed[i]; var destinationSpeed = LaneSpeed[i + 1]; var distance = Vector3.Distance(initialPosition, destination); float duration; if (LaneAcceleration[i + 1] > 0) { // If max speed is lower than the initial speed convert acceleration to deceleration if (destinationSpeed < initialSpeed) { LaneAcceleration[i + 1] *= -1; } if (!UniformlyAcceleratedMotion.CalculateDuration(LaneAcceleration[i + 1], initialSpeed, distance, ref destinationSpeed, out var accelerationDuration, out var accelerationDistance)) { // Max speed will not be reached with current acceleration AccelerationDestination.Add(destination); LaneSpeed[i + 1] = destinationSpeed; duration = accelerationDuration; AccelerationDuration.Add(accelerationDuration); } else { // Calculate mixed duration of accelerated and linear movements var accelerationDestination = initialPosition + (destination - initialPosition).normalized * accelerationDistance; AccelerationDestination.Add(accelerationDestination); var linearDistance = distance - accelerationDistance; AccelerationDuration.Add(accelerationDuration); duration = accelerationDuration + linearDistance / destinationSpeed; } } else { // There is no acceleration - apply max speed for uniform linear movement AccelerationDuration.Add(0.0f); AccelerationDestination.Add(initialPosition); duration = distance / destinationSpeed; } // Set waypoint time base on speed. LaneTime[i + 1] = LaneTime[i] + duration; }
public void SetFollowWaypoints(List <WalkWaypoint> waypoints, bool loop, WaypointsPathType pathType) { InitPos = transform.position; InitRot = transform.rotation; WaypointLoop = loop; PathType = pathType; // Process waypoints according to the selected waypoint path switch (PathType) { case WaypointsPathType.Linear: break; case WaypointsPathType.BezierSpline: // Add the initial position for Bezier Spline calculations var initWaypoint = ((IWaypoint)waypoints[0]).Clone(); initWaypoint.Position = InitPos; waypoints.Insert(0, (WalkWaypoint)initWaypoint); var bezier = new BezierSpline <WalkWaypoint>(waypoints.ToArray(), 0.01f); waypoints = bezier.GetBezierWaypoints(); // Remove first waypoint as it will be added by another function waypoints.RemoveAt(0); break; default: throw new ArgumentOutOfRangeException(nameof(PathType), PathType, null); } LaneData = waypoints.Select(wp => wp.Position).ToList(); LaneSpeed = waypoints.Select(wp => wp.Speed).ToList(); LaneAcceleration = waypoints.Select(wp => wp.Acceleration).ToList(); LaneAngle = waypoints.Select(wp => Quaternion.Euler(wp.Angle)).ToList(); LaneIdle = waypoints.Select(wp => wp.Idle).ToList(); LaneTriggerDistance = waypoints.Select(wp => wp.TriggerDistance).ToList(); LaneTriggers = waypoints.Select(wp => wp.Trigger).ToList(); LaneTime = new List <float>(); InitPedestrian(); AddPoseToFirstWaypoint(); // Calculate acceleration data only if there are no timestamps for (int i = 0; i < LaneData.Count - 1; i++) { var initialPosition = LaneData[i]; var destination = LaneData[i + 1]; var initialSpeed = LaneSpeed[i]; var destinationSpeed = LaneSpeed[i + 1]; var distance = Vector3.Distance(initialPosition, destination); float duration; if (LaneAcceleration[i + 1] > 0) { // If max speed is lower than the initial speed convert acceleration to deceleration if (destinationSpeed < initialSpeed) { LaneAcceleration[i + 1] *= -1; } if (!UniformlyAcceleratedMotion.CalculateDuration(LaneAcceleration[i + 1], initialSpeed, distance, ref destinationSpeed, out var accelerationDuration, out var accelerationDistance)) { // Max speed will not be reached with current acceleration AccelerationDestination.Add(destination); LaneSpeed[i + 1] = destinationSpeed; duration = accelerationDuration; AccelerationDuration.Add(accelerationDuration); } else { // Calculate mixed duration of accelerated and linear movements var accelerationDestination = initialPosition + (destination - initialPosition).normalized * accelerationDistance; AccelerationDestination.Add(accelerationDestination); var linearDistance = distance - accelerationDistance; AccelerationDuration.Add(accelerationDuration); duration = accelerationDuration + linearDistance / destinationSpeed; } }