public static Vector3 getForceForDirection(Steering steering, Vector3 desiredDirection) { return(getForceForDesiredVelocity(steering, scaledVector(steering.GetMaxSpeed(), desiredDirection))); }
public Vector3 GetForce(Steering steering) { float raycastDistance = 2f * (2f * steering.GetSize()) + 2f * (steering.GetMaxSpeed() * steering.GetMaxSpeed() / steering.GetAcceleration()); // TODO: send out 3 rays and define static quaternions to determine the rotated direction vectors. Vector3 directionVector = steering.GetVelocity(); // TODO: update the side raycast lengths based on steering's size, and the center raycast based on speed. // TODO: constrain hit normals to the relevant plane in case the collider has a complicated shape Vector3 hitNormal1 = RaycastNormal(steering, (Steering.UseXZ ? xzRotateLeft : xyRotateLeft) * directionVector, raycastDistance * 0.5f); Vector3 hitNormal2 = RaycastNormal(steering, directionVector, raycastDistance); Vector3 hitNormal3 = RaycastNormal(steering, (Steering.UseXZ ? xzRotateRight : xyRotateRight) * directionVector, raycastDistance * 0.5f); // If multiple raycasts hit, sum the normals. // TODO: weight the normals differently based on which collision point is closest. Vector3 combinedNormal = SteeringUtilities.scaledDownVector(1f, hitNormal1 + hitNormal2 + hitNormal3); if (combinedNormal.sqrMagnitude > 0f) { // For the normal of the wall ahead, steer to have a velocity that is perpindicular to it. Vector3 leftVector = new Vector3(combinedNormal.y + combinedNormal.z, -Steering.YMult * combinedNormal.x, -Steering.ZMult * combinedNormal.x); Vector3 rightVector = new Vector3((-combinedNormal.y) - combinedNormal.z, Steering.YMult * combinedNormal.x, Steering.ZMult * combinedNormal.x); float rayLeftDistance = RaycastDistance(steering, leftVector, raycastDistance); float rayRightDistance = RaycastDistance(steering, rightVector, raycastDistance); // TODO: Consider updating the logic when approaching a corner. // Currently the unit kind of turns toward the side that they are coming from even if the other turn is shorter. // Case 1: Wall in front, wall on left, wall on right. if (rayLeftDistance < raycastDistance && rayRightDistance < raycastDistance) { // Move towards the left/right wall that is closer. That should be moving away from the corner point. if (rayLeftDistance < rayRightDistance) { return(SteeringUtilities.getForceForDirection(steering, leftVector)); } else // rayRightDistance < rayLeftDistance { return(SteeringUtilities.getForceForDirection(steering, rightVector)); } } // Case 2: Wall in front, wall on left else if (rayLeftDistance < raycastDistance) { return(SteeringUtilities.getForceForDirection(steering, rightVector)); } // Case 3: Wall in front, wall on right else if (rayRightDistance < raycastDistance) { return(SteeringUtilities.getForceForDirection(steering, leftVector)); } // Case 4: Wall in front else { // Move towards whichever of left or right is closer to the current velocity Vector3 perpindicularVector = SteeringUtilities.perpindicularComponent(combinedNormal, steering.GetVelocity()); // Edge case: the normal is parallel to velocity. In this case, pick one of the two perpindicular vectors at random. if (perpindicularVector == Vector3.zero) { Debug.Log("Exact perpindicular!"); int randomSign = Random.value < .5 ? 1 : -1; perpindicularVector = new Vector3((-combinedNormal.y) - combinedNormal.z, Steering.YMult * combinedNormal.x * randomSign, Steering.ZMult * combinedNormal.x * randomSign); } return(SteeringUtilities.getForceForDirection(steering, perpindicularVector)); } } return(Vector3.zero); }
public Vector3 GetForce(Steering steering) { return(SteeringUtilities.getForceForDesiredVelocity(steering, SteeringUtilities.scaledVector(steering.GetMaxSpeed(), steering.GetDirection()))); }
public Vector3 GetForce(Steering steering) { Vector3 currentOffset = target.GetPosition() - steering.GetPosition(); float dist = currentOffset.magnitude; Vector3 unitV = steering.GetVelocity().normalized; float parallelness = Vector3.Dot(unitV, target.GetVelocity().normalized); float forwardness = Vector3.Dot(unitV, currentOffset / dist); float halfsqrt2 = 0.707f; int f = SteeringUtilities.intervalComp(forwardness, -halfsqrt2, halfsqrt2); int p = SteeringUtilities.intervalComp(parallelness, -halfsqrt2, halfsqrt2); // approximate how far to lead the target float timeFactor = 1f; // case logic based on (ahead, aside, behind) X (parallel, perp, anti-parallel) switch (f) { case 1: //target is ahead switch (p) { case 1: timeFactor = 4f; break; case 0: timeFactor = 1.8f; break; case -1: timeFactor = 0.85f; break; } break; case 0: //target is aside switch (p) { case 1: timeFactor = 1f; break; case 0: timeFactor = 0.8f; break; case -1: timeFactor = 4f; break; } break; case -1: //target is behind switch (p) { case 1: timeFactor = 0.5f; break; case 0: timeFactor = 2f; break; case -1: timeFactor = 2f; break; } break; } // Multiply the timeToArrive by some approximate constants based on how similar the two velocities are. float approximateArrivalTime = dist / steering.GetMaxSpeed(); float improvedArrivalTimeEstimate = Mathf.Min(MAX_PREDICTION_TIME, approximateArrivalTime * timeFactor); Vector3 newTargetPosition = (Vector3)target.GetPosition() + improvedArrivalTimeEstimate * target.GetVelocity(); SteeringUtilities.drawDebugVector(target, newTargetPosition - target.GetPosition(), Color.white); SteeringUtilities.drawDebugVector(steering, newTargetPosition - steering.GetPosition(), Color.magenta); return(SteeringUtilities.getForceForDirection(steering, newTargetPosition - steering.GetPosition())); }