public Vector3 GetForce(Steering steering)
            {
                if (isResponsibleForNeighbourUpdate)
                {
                    // TODO: figure out how to add or remove neighbours automatically here or in neighbours
                    neighbours.Update();
                }

                /*
                 * Avoid collisions by determining for each neighbor when their paths will be closest to each other
                 * and then steer laterally to avoid collision.
                 * https://www.red3d.com/cwr/steer/Unaligned.html
                 */
                float distanceToBeginReacting = 4f * (steering.GetSize() + steering.GetStoppingDistance());

                //Debug.Log(doubleStopDistance);
                foreach (Neighbour <Steering> neighbour in neighbours)
                {
                    if (neighbour.dd > distanceToBeginReacting * distanceToBeginReacting)
                    {
                        break;
                    }
                    Steering otherUnit        = neighbour.obj;
                    Vector3  offset           = otherUnit.GetPosition() - steering.GetPosition();
                    Vector3  relativeVelocity = steering.GetVelocity() - otherUnit.GetVelocity();
                    // Decrease the timeToCollision so that closestOffset is nonZero.
                    float combinedSize    = steering.GetSize() + otherUnit.GetSize();
                    float timeToCollision = (offset.magnitude - combinedSize) / SteeringUtilities.parallelComponent(relativeVelocity, offset).magnitude;
                    if (timeToCollision > 2 * steering.GetStoppingTime())
                    {
                        continue;
                    }
                    Vector3 closestOffset     = (offset - (timeToCollision * relativeVelocity));
                    float   preferredDistance = 1.5f * combinedSize;
                    if (closestOffset.sqrMagnitude > preferredDistance * preferredDistance)
                    {
                        continue;
                    }
                    SteeringUtilities.drawDebugVector(steering, timeToCollision * steering.GetVelocity(), Color.cyan);
                    SteeringUtilities.drawDebugPoint(steering.GetPosition() + timeToCollision * steering.GetVelocity(), Color.cyan);
                    SteeringUtilities.drawDebugVector(otherUnit, timeToCollision * otherUnit.GetVelocity(), Color.cyan);
                    SteeringUtilities.drawDebugPoint(otherUnit.GetPosition() + timeToCollision * otherUnit.GetVelocity(), Color.cyan);
                    // TODO: for head-on collisions steer to the right
                    // Steer in the direction of the component of the collision normal that is perpindicular to the current velocity.
                    // This way the unit will turn instead of just slowing down.

                    // TODO: use an amount of acceleration proportionate to the time until collision and the severity of the collision
                    return(SteeringUtilities.scaledVector(steering.GetAcceleration(), SteeringUtilities.perpindicularComponent(-closestOffset, steering.GetVelocity())));
                    //return SteeringUtilities.getForceForDirection(steering, -closestOffset);
                }
                return(Vector3.zero);
            }
Пример #2
0
            // TODO: add functions to get and modify preferredDistance

            public Vector3 GetForce(Steering steering)
            {
                Vector3 steeringVector = new Vector3(0f, 0f, 0f);

                // steer away from each object that is too close with a weight of up to 0.5 for each
                foreach (Neighbour <Steering> neighbour in neighbours)
                {
                    if (neighbour.dd > preferredDistance * preferredDistance)
                    {
                        break;
                    }
                    Steering otherUnit       = neighbour.obj;
                    Vector3  offset          = otherUnit.GetPosition() - steering.GetPosition();
                    float    currentDistance = Mathf.Sqrt(neighbour.dd);
                    // TODO: consider relative velocity when computing importance
                    float importance = (preferredDistance - currentDistance) / preferredDistance;
                    steeringVector += -importance * offset;
                }
                if (steeringVector.sqrMagnitude > 0)
                {
                    // TODO: do something like arrival to avoid over-separating
                    return(SteeringUtilities.getForceForDirection(steering, steeringVector));
                }
                return(Vector3.zero);
            }
Пример #3
0
            public Vector3 GetForce(Steering steering)
            {
                if (steering.GetVelocity().sqrMagnitude == 0f)
                {
                    float initialAngle = Random.Range(0f, 2 * Mathf.PI);
                    float sinAngle     = Mathf.Sin(initialAngle);
                    wanderPoint = 2.4f * new Vector3(Mathf.Cos(initialAngle), Steering.YMult * sinAngle, Steering.ZMult * sinAngle);
                }
                if (steering.GetVelocity().sqrMagnitude > 0f && !hasMoved)
                {
                    hasMoved    = true;
                    wanderPoint = SteeringUtilities.scaledVector(2.4f, steering.GetVelocity());
                }
                float xNoise  = Time.fixedDeltaTime * wanderNoise * Random.Range(-1f, 1f);
                float yzNoise = Time.fixedDeltaTime * wanderNoise * Random.Range(-1f, 1f);

                wanderPoint += new Vector3(xNoise, Steering.YMult * yzNoise, Steering.ZMult * yzNoise);
                Vector3 forwardPoint = steering.GetPosition() + SteeringUtilities.scaledVector(1.41f, steering.GetVelocity());

                // Constrain the wander point to the unit circle in front of the player.
                wanderPoint = forwardPoint + (wanderPoint - forwardPoint).normalized;
                //return SteeringUtilities.getForceForDirection(steering, wanderDirection);
                //SteeringUtilities.drawDebugCircle(forwardPoint, 1f, Color.black, 32);
                SteeringUtilities.drawDebugPoint(wanderPoint, Color.red);
                return(SteeringUtilities.getSeekForce(steering, wanderPoint));
            }
Пример #4
0
            private RaycastHit Raycast(Steering steering, Vector3 directionVector, float raycastDistance)
            {
                RaycastHit hitInfo;

                Physics.Raycast(steering.GetPosition(), directionVector, out hitInfo, raycastDistance, layerMask);
                //SteeringUtilities.drawDebugVector(steering, SteeringUtilities.scaledVector(raycastDistance, directionVector), Color.white);
                if (hitInfo.collider != null)
                {
                    SteeringUtilities.drawDebugPoint(hitInfo.point, Color.magenta);
                    SteeringUtilities.drawDebugVector(steering, hitInfo.point - steering.GetPosition(), Color.magenta);
                    SteeringUtilities.drawDebugVector(hitInfo.point, hitInfo.normal, Color.white);
                }
                else
                {
                    SteeringUtilities.drawDebugVector(steering, SteeringUtilities.scaledVector(raycastDistance, directionVector), new Color(Color.magenta.r, Color.magenta.g, Color.magenta.b, 0.25f));
                }
                return(hitInfo);
            }
Пример #5
0
 public Vector3 GetForce(Steering steering)
 {
     if (_target != null)
     {
         return(SteeringUtilities.getSeekForce(steering, _target.GetPosition()));
     }
     else
     {
         return(SteeringUtilities.getSeekForce(steering, _point));
     }
 }
Пример #6
0
 public static void drawDebugVector(Steering steering, Vector3 offsetVector, Color color)
 {
     drawDebugVector(steering.GetPosition(), offsetVector, color);
 }
Пример #7
0
 public static Vector3 getSeekForce(Steering steering, Vector3 targetPosition)
 {
     return(getForceForDirection(steering, targetPosition - steering.GetPosition()));
 }
Пример #8
0
            // Performs a raycast and returns the normal of the collision or the zero vector.
            private float RaycastDistance(Steering steering, Vector3 directionVector, float raycastDistance)
            {
                if (Steering.Using3D)
                {
                    RaycastHit hitInfo = Raycast(steering, directionVector, raycastDistance);
                    return(hitInfo.collider == null ? raycastDistance : (hitInfo.point - steering.GetPosition()).magnitude);
                }
                RaycastHit2D hitInfo2D = Raycast2D(steering, directionVector, raycastDistance);

                return(hitInfo2D.collider == null ? raycastDistance : ((Vector3)hitInfo2D.point - steering.GetPosition()).magnitude);
            }
Пример #9
0
            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()));
            }