Пример #1
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));
            }
            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);
            }
Пример #3
0
            public static Vector3 getForceForDesiredVelocity(Steering steering, Vector3 desiredVelocity)
            {
                // The velocity will be changed by force * deltaTime, so the desired force is deltaV/deltaTime.
                Vector3 desiredForce = (desiredVelocity - steering.GetVelocity()) / Time.fixedDeltaTime;

                return(scaledDownVector(steering.GetAcceleration(), desiredForce));
            }
Пример #4
0
            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);
            }
Пример #5
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()));
            }