Пример #1
0
    // Orbit a position while always facing straight ahead
    public void Orbit(Vector3 orbitCenter, float orbitAltitude, float orbitRadius = 1, float timeout = float.PositiveInfinity)
    {
        UpdateVectorCallback GetOrbitCenter   = (float deltaTime) => { return(orbitCenter); };
        UpdateScalarCallback GetOrbitAltitude = (float deltaTime) => { return(orbitAltitude); };

        LaunchMovementCoroutine(OrbitPositionCoroutine(GetOrbitCenter, GetOrbitAltitude, orbitRadius, timeout, null));
        LaunchDirectionCoroutine(LookFlightDirectionCoroutine());
    }
Пример #2
0
    // Orbit a target while always facing it
    public void OrbitAndLookAt(Transform orbitCenter, float relativeOrbitAltitude, float orbitRadius = 1, float timeout = float.PositiveInfinity, System.Action OnComplete = null)
    {
        UpdateVectorCallback GetOrbitCenter   = (float deltaTime) => { return(orbitCenter.position); };
        UpdateScalarCallback GetOrbitAltitude = (float deltaTime) => { return(orbitCenter.position.y + relativeOrbitAltitude); };

        LaunchMovementCoroutine(OrbitPositionCoroutine(GetOrbitCenter, GetOrbitAltitude, orbitRadius, timeout, OnComplete));
        LaunchDirectionCoroutine(LookAtCoroutine(orbitCenter));
    }
Пример #3
0
    private IEnumerator OrbitPositionCoroutine(UpdateVectorCallback GetOrbitCenter, UpdateScalarCallback GetOrbitAltitude, float orbitRadius, float timeout, System.Action OnComplete)
    {
        float   step          = 20;
        float   direction     = MathHelpers.RandomSign();
        Vector3 toHelicopter  = MathHelpers.Azimuthal(transform.position - GetOrbitCenter(Time.deltaTime));
        float   startRadius   = toHelicopter.magnitude;
        float   currentRadius = startRadius;
        float   startAngle    = currentRadius == 0 ? 0 : Mathf.Rad2Deg * Mathf.Acos(toHelicopter.x / currentRadius);

        if (startAngle < 0)
        {
            startAngle += 180;
        }
        float currentAngle    = startAngle;
        float degreesElapsed  = 0;
        float startAltitude   = transform.position.y;
        float currentAltitude = startAltitude;

        int   maxObstructionRetries    = (int)(360 / step);
        int   numObstructionRetries    = maxObstructionRetries;
        float nextObstructionCheckTime = 0;
        float timeoutTime = Time.time + timeout;

        while (true)
        {
            // Compute the next position along the circle
            float nextAngle   = currentAngle + direction * step;
            float nextRadians = Mathf.Deg2Rad * nextAngle;

            // Move to that position
            bool flying = true;
            do
            {
                float now = Time.time;

                if (now >= timeoutTime)
                {
                    if (OnComplete != null)
                    {
                        yield return(null); // always ensure one frame elapsed before callback

                        OnComplete();
                    }
                    Halt();
                    yield break;
                }

                // In case orbit center is a moving target, continually update the next
                // position
                Vector3 nextPosition = GetOrbitCenter(Time.deltaTime) + currentRadius * new Vector3(Mathf.Cos(nextRadians), 0, Mathf.Sin(nextRadians));
                nextPosition.y = currentAltitude;

                // This doesn't work very well but the idea is to check for
                // obstructions and move on to subsequent waypoints. If no point seems
                // reachable, we simply abort. For each attempt, we allow some time to
                // pass in case we were stuck.
                if (now > nextObstructionCheckTime && PathObstructed(nextPosition))
                {
                    if (numObstructionRetries > 0)
                    {
                        nextObstructionCheckTime = now + obstructionRetryTime;
                        numObstructionRetries--;
                        break;
                    }

                    // Need to abort
                    if (OnComplete != null)
                    {
                        yield return(null); // always ensure one frame elapsed before callback

                        OnComplete();
                    }
                    Halt();
                    yield break;
                }

                flying = GoTo(nextPosition);
                UpdateControls();
                yield return(null);
            } while (flying);

            // Restore number of avoidance attempts if we finally reached a waypoint
            if (flying == false)
            {
                numObstructionRetries = maxObstructionRetries;
            }

            // Advance the angle
            degreesElapsed += step;
            currentAngle    = nextAngle;
            float revolutionCompleted = degreesElapsed / 360;

            // Adjust the radius so that it converges to the desired radius within
            // one revolution
            currentRadius = Mathf.Lerp(startRadius, orbitRadius, revolutionCompleted);

            // Altitude convergence
            currentAltitude = Mathf.Lerp(startAltitude, GetOrbitAltitude(Time.deltaTime), revolutionCompleted);
        }
    }