public void Execute(Entity entity, int index, [ReadOnly] ref Target target, ref DeployToPosition deployToPosition, [ReadOnly] ref Translation translation, [ReadOnly] ref CombatMovement combatMovement, [ReadOnly] ref PursueTarget pursueTarget, [ReadOnly] ref MovementStats movementStats) { if (TranslationData.Exists(target.TargetEntity) && VelocityData.Exists(target.TargetEntity)) { var targetPosition = TranslationData[target.TargetEntity]; var targetVelocity = VelocityData[target.TargetEntity]; var distanceSq = math.distancesq(targetPosition.Value, translation.Value); if (distanceSq > combatMovement.OptimalRangeSq) { if (combatMovement.OptimalRangeSq != 0f) { var direction = targetPosition.Value - translation.Value; direction = math.normalizesafe(direction); var optimalPosition = translation.Value + (direction * math.sqrt(combatMovement.OptimalRangeSq)); NaNDebugger.IsNan(targetPosition.Value.x, "target nan"); deployToPosition.Position = optimalPosition; } else { // This version ignores the timestep and uses relative distance instead. var t = math.length(math.sqrt(distanceSq)) * movementStats.TopSpeed; var desiredPosition = targetPosition.Value + targetVelocity.Value * t * DeltaTime; //var desiredPosition = targetPosition.Value + targetVelocity.Value * LookAheadTimeStep * DeltaTime; deployToPosition.Position = desiredPosition; } } else { deployToPosition.Position = translation.Value; } } }
public void Execute(Entity entity, int jobIndex, [ReadOnly] ref DeployToPosition deployment, [ReadOnly] ref MovementStats stats, [ReadOnly] ref Rotation rotation, ref Translation translation, ref Velocity velocity, ref AngularVelocity angularVelocity) { NaNDebugger.IsNan(deployment.Position.x, $"[{jobIndex}, {entity.Index}] deployment.Position"); NaNDebugger.IsNan(translation.Value.x, $"[{jobIndex}, {entity.Index}] translation"); float3 toTarget = deployment.Position - translation.Value; float distance = math.length(toTarget); if (deployment.ShouldStop && distance <= k_DistanceTolerance) { velocity.Value = float3.zero; angularVelocity.Velocity = 0f; translation.Value = deployment.Position; //CompletedDeployments.Enqueue(new CompletedDeployment() { Entity = entity, JobIndex = jobIndex }); return; // we're there, stop. } float speed = math.length(velocity.Value); float3 forward = math.normalize(math.forward(rotation.Value)); float3 velocityDirection = speed == 0f ? forward : math.normalize(velocity.Value); toTarget = toTarget / distance; // normalize float costheta = distance == 0f ? 1 : math.dot(toTarget, forward); // Rotation if (distance != 0f) { float3 rotationAxis = costheta == -1 || costheta == 1 ? math.up() : math.normalize(math.cross(forward, toTarget)); float rotationDirection = math.saturate(math.sign(math.dot(rotationAxis, math.up())) + 1) * 2 - 1; // -1 or 1 float rotationSpeed = math.radians(stats.RotationSpeed) * rotationDirection; rotationAxis = rotationAxis * rotationDirection; if (costheta >= stats.ThrustTolerance) // have we turned enough to begin moving forward? { velocityDirection = forward; } else { rotationSpeed *= math.step(speed, /* < */ stats.MaxSpeedToTurn); // only turn if we've slowed down enough } if (costheta >= k_AngleTolerance) { float angleRadians = math.acos(costheta); rotationSpeed = (float.IsNaN(angleRadians) ? 0f : angleRadians) * rotationDirection / DeltaTime; // take us directly there this frame. } velocityDirection = math.rotate(quaternion.AxisAngle(rotationAxis, rotationSpeed * DeltaTime), velocityDirection); angularVelocity.Axis = rotationAxis; angularVelocity.Velocity = rotationSpeed; } NaNDebugger.IsNan(angularVelocity.Axis.x, $"[{jobIndex}, {entity.Index}] rotationAxis"); NaNDebugger.IsNan(angularVelocity.Axis.x, $"[{jobIndex}, {entity.Index}] rotationSpeed"); NaNDebugger.IsNan(velocityDirection.x, $"[{jobIndex}, {entity.Index}] velocityDirection"); // Translation { if (costheta >= stats.ThrustTolerance) // have we turned enough to begin moving forward? { if (deployment.ShouldStop) { // https://math.stackexchange.com/questions/233107/finding-minimum-distance-traveled-with-specified-deceleration-from-starting-spee float speedInDirection = math.dot(toTarget, velocityDirection * speed); float distanceTravelledIfDecelerating = (speedInDirection * speedInDirection) / (2 * stats.Deceleration); if (distanceTravelledIfDecelerating >= distance) { speed = math.clamp(speed - 0.5f * stats.Deceleration * DeltaTime, 0f, stats.TopSpeed); // t(v - at/2) } else { speed = math.clamp(speed + 0.5f * stats.Acceleration * DeltaTime, 0f, stats.TopSpeed); // t(v - at/2) } speedInDirection = math.dot(toTarget, velocityDirection * speed); float distanceThisFrame = distance - speedInDirection * DeltaTime; if (distanceThisFrame < k_DistanceTolerance) { speed = distance / DeltaTime; // take us right there this frame. } } else { // don't stop, just keep accelerating. speed = math.clamp(speed + 0.5f * stats.Acceleration * DeltaTime, 0f, stats.TopSpeed); // t(v - at/2) } } else { // decelerate speed = math.clamp(speed - 0.5f * stats.Deceleration * DeltaTime, 0f, stats.TopSpeed); // t(v - at/2) } velocity.Value = velocityDirection * speed; } NaNDebugger.IsNan(velocity.Value.x, $"[{jobIndex}, {entity.Index}] velocity"); }