/// <summary> /// A seek steering behavior. Will return the steering for the current game object to seek a given position /// </summary> public Vector3 Seek(Vector3 targetPosition, float maxSeekAccel) { /* Get the direction */ Vector3 acceleration = rb.ConvertVector(targetPosition - transform.position); acceleration.Normalize(); /* Accelerate to the target */ acceleration *= maxSeekAccel; return(acceleration); }
/// <summary> /// Finds the param for the closest point on the segment vw given the point p /// </summary> /// <returns>The parameter for segment.</returns> float GetParamForSegment(Vector3 p, Vector3 v, Vector3 w, MovementAIRigidbody rb) { Vector3 vw = w - v; vw = rb.ConvertVector(vw); float l2 = Vector3.Dot(vw, vw); if (l2 == 0) { return(0); } float t = Vector3.Dot(p - v, vw) / l2; if (t < 0) { t = 0; } else if (t > 1) { t = 1; } /* Multiple by (v - w).magnitude instead of Sqrt(l2) because we want the magnitude of the full 3D line segment */ return(t * (v - w).magnitude); }
/// <summary> /// Will return true if the character is at the end of the given path /// </summary> public bool IsAtEndOfPath(LinePath path) { /* If the path has only one node then just check the distance to that node. */ if (path.Length == 1) { Vector3 endPos = rb.ConvertVector(path[0]); return(Vector3.Distance(rb.Position, endPos) < stopRadius); } /* Else see if the character is at the end of the path. */ else { Vector3 finalDestination; /* Get the param for the closest position point on the path given the character's position */ float param = path.GetParam(transform.position, rb); return(IsAtEndOfPath(path, param, out finalDestination)); } }
public Vector3 GetSteering(ICollection <MovementAIRigidbody> targets) { Vector3 acceleration = Vector3.zero; foreach (MovementAIRigidbody r in targets) { /* Get the direction and distance from the target */ Vector3 direction = rb.ColliderPosition - r.ColliderPosition; float dist = direction.magnitude; if (dist < maxSepDist) { /* Calculate the separation strength (can be changed to use inverse square law rather than linear) */ var strength = sepMaxAcceleration * (maxSepDist - dist) / (maxSepDist - rb.Radius - r.Radius); /* Added separation acceleration to the existing steering */ direction = rb.ConvertVector(direction); direction.Normalize(); acceleration += direction * strength; } } return(acceleration); }
public Vector3 GetSteering(ICollection <MovementAIRigidbody> targets) { Vector3 acceleration = Vector3.zero; /* 1. Find the target that the character will collide with first */ /* The first collision time */ float shortestTime = float.PositiveInfinity; /* The first target that will collide and other data that * we will need and can avoid recalculating */ MovementAIRigidbody firstTarget = null; float firstMinSeparation = 0, firstDistance = 0, firstRadius = 0; Vector3 firstRelativePos = Vector3.zero, firstRelativeVel = Vector3.zero; foreach (MovementAIRigidbody r in targets) { /* Calculate the time to collision */ Vector3 relativePos = rb.ColliderPosition - r.ColliderPosition; Vector3 relativeVel = rb.RealVelocity - r.RealVelocity; float distance = relativePos.magnitude; float relativeSpeed = relativeVel.magnitude; if (relativeSpeed == 0) { continue; } float timeToCollision = -1 * Vector3.Dot(relativePos, relativeVel) / (relativeSpeed * relativeSpeed); /* Check if they will collide at all */ Vector3 separation = relativePos + relativeVel * timeToCollision; float minSeparation = separation.magnitude; if (minSeparation > rb.Radius + r.Radius + distanceBetween) { continue; } /* Check if its the shortest */ if (timeToCollision > 0 && timeToCollision < shortestTime) { shortestTime = timeToCollision; firstTarget = r; firstMinSeparation = minSeparation; firstDistance = distance; firstRelativePos = relativePos; firstRelativeVel = relativeVel; firstRadius = r.Radius; } } /* 2. Calculate the steering */ /* If we have no target then exit */ if (firstTarget == null) { return(acceleration); } /* If we are going to collide with no separation or if we are already colliding then * steer based on current position */ if (firstMinSeparation <= 0 || firstDistance < rb.Radius + firstRadius + distanceBetween) { acceleration = rb.ColliderPosition - firstTarget.ColliderPosition; } /* Else calculate the future relative position */ else { acceleration = firstRelativePos + firstRelativeVel * shortestTime; } /* Avoid the target */ acceleration = rb.ConvertVector(acceleration); acceleration.Normalize(); acceleration *= maxAcceleration; return(acceleration); }