GetCurrentPart() 공개 메소드

public GetCurrentPart ( ) : RichPathPart
리턴 RichPathPart
예제 #1
0
        protected override void OnPathComplete(Path p)
        {
            waitingForPathCalculation = false;
            p.Claim(this);

            if (p.error)
            {
                p.Release(this);
                return;
            }

            if (traversingOffMeshLink)
            {
                delayUpdatePath = true;
            }
            else
            {
                richPath.Initialize(seeker, p, true, funnelSimplification);

                // Check if we have already reached the end of the path
                // We need to do this here to make sure that the #reachedEndOfPath
                // property is up to date.
                var part = richPath.GetCurrentPart() as RichFunnel;
                if (part != null)
                {
                    if (updatePosition)
                    {
                        simulatedPosition = tr.position;
                    }

                    // Note: UpdateTarget has some side effects like setting the nextCorners list and the lastCorner field
                    var localPosition = movementPlane.ToPlane(UpdateTarget(part));

                    // Target point
                    steeringTarget = nextCorners[0];
                    Vector2 targetPoint = movementPlane.ToPlane(steeringTarget);
                    distanceToSteeringTarget = (targetPoint - localPosition).magnitude;

                    if (lastCorner && nextCorners.Count == 1 && distanceToSteeringTarget <= endReachedDistance)
                    {
                        NextPart();
                    }
                }
            }
            p.Release(this);
        }
예제 #2
0
        void OnPathComplete(Path p)
        {
            waitingForPathCalc = false;
            p.Claim(this);

            if (p.error)
            {
                p.Release(this);
                return;
            }

            if (traversingSpecialPath)
            {
                delayUpdatePath = true;
            }
            else
            {
                richPath.Initialize(seeker, p, true, funnelSimplification);

                // Check if we have already reached the end of the path
                // We need to do this here to make sure that the #TargetReached
                // property is up to date.
                var part = richPath.GetCurrentPart() as RichFunnel;
                if (part != null)
                {
                    var position = movementPlane.ToPlane(UpdateTarget(part));
                    if (lastCorner && nextCorners.Count == 1)
                    {
                        // Target point
                        Vector2 targetPoint = waypoint = movementPlane.ToPlane(nextCorners[0]);
                        distanceToWaypoint = (targetPoint - position).magnitude;
                        if (distanceToWaypoint <= endReachedDistance)
                        {
                            NextPart();
                        }
                    }
                }
            }
            p.Release(this);
        }
예제 #3
0
        /** Update is called once per frame */
        protected virtual void Update()
        {
            deltaTime = Mathf.Min(Time.smoothDeltaTime * 2, Time.deltaTime);

            if (rp != null)
            {
                //System.Diagnostics.Stopwatch w = new System.Diagnostics.Stopwatch();
                //w.Start();
                RichPathPart pt = rp.GetCurrentPart();
                var          fn = pt as RichFunnel;
                if (fn != null)
                {
                    //Clear buffers for reuse
                    Vector3 position = UpdateTarget(fn);

                    //tr.position = ps;

                    //Only get walls every 5th frame to save on performance
                    if (Time.frameCount % 5 == 0 && wallForce > 0 && wallDist > 0)
                    {
                        wallBuffer.Clear();
                        fn.FindWalls(wallBuffer, wallDist);
                    }

                    /*for (int i=0;i<wallBuffer.Count;i+=2) {
                     *  Debug.DrawLine (wallBuffer[i],wallBuffer[i+1],Color.magenta);
                     * }*/

                    //Pick next waypoint if current is reached
                    int tgIndex = 0;

                    /*if (buffer.Count > 1) {
                     *  if ((buffer[tgIndex]-tr.position).sqrMagnitude < pickNextWaypointDist*pickNextWaypointDist) {
                     *      tgIndex++;
                     *  }
                     * }*/


                    //Target point
                    Vector3 tg  = buffer[tgIndex];
                    Vector3 dir = tg - position;
                    dir.y = 0;

                    bool passedTarget = Vector3.Dot(dir, currentTargetDirection) < 0;
                    //Check if passed target in another way
                    if (passedTarget && buffer.Count - tgIndex > 1)
                    {
                        tgIndex++;
                        tg = buffer[tgIndex];
                    }

                    if (tg != lastTargetPoint)
                    {
                        currentTargetDirection   = (tg - position);
                        currentTargetDirection.y = 0;
                        currentTargetDirection.Normalize();
                        lastTargetPoint = tg;
                        //Debug.DrawRay (tr.position, Vector3.down*2,Color.blue,0.2f);
                    }

                    //Direction to target
                    dir   = (tg - position);
                    dir.y = 0;
                    float magn = dir.magnitude;

                    //Write out for other scripts to read
                    distanceToWaypoint = magn;

                    //Normalize
                    dir = magn == 0 ? Vector3.zero : dir / magn;
                    Vector3 normdir = dir;

                    Vector3 force = Vector3.zero;

                    if (wallForce > 0 && wallDist > 0)
                    {
                        float wLeft  = 0;
                        float wRight = 0;

                        for (int i = 0; i < wallBuffer.Count; i += 2)
                        {
                            Vector3 closest = VectorMath.ClosestPointOnSegment(wallBuffer[i], wallBuffer[i + 1], tr.position);
                            float   dist    = (closest - position).sqrMagnitude;

                            if (dist > wallDist * wallDist)
                            {
                                continue;
                            }

                            Vector3 tang = (wallBuffer[i + 1] - wallBuffer[i]).normalized;

                            //Using the fact that all walls are laid out clockwise (seeing from inside)
                            //Then left and right (ish) can be figured out like this
                            float dot = Vector3.Dot(dir, tang) * (1 - System.Math.Max(0, (2 * (dist / (wallDist * wallDist)) - 1)));
                            if (dot > 0)
                            {
                                wRight = System.Math.Max(wRight, dot);
                            }
                            else
                            {
                                wLeft = System.Math.Max(wLeft, -dot);
                            }
                        }

                        Vector3 norm = Vector3.Cross(Vector3.up, dir);
                        force = norm * (wRight - wLeft);

                        //Debug.DrawRay (tr.position, force, Color.cyan);
                    }

                    //Is the endpoint of the path (part) the current target point
                    bool endPointIsTarget = lastCorner && buffer.Count - tgIndex == 1;

                    if (endPointIsTarget)
                    {
                        //Use 2nd or 3rd degree motion equation to figure out acceleration to reach target in "exact" [slowdownTime] seconds

                        //Clamp to avoid divide by zero
                        if (slowdownTime < 0.001f)
                        {
                            slowdownTime = 0.001f;
                        }

                        Vector3 diff = tg - position;
                        diff.y = 0;

                        if (preciseSlowdown)
                        {
                            //{ t = slowdownTime
                            //{ diff = vt + at^2/2 + qt^3/6
                            //{ 0 = at + qt^2/2
                            //{ solve for a
                            dir = (6 * diff - 4 * slowdownTime * velocity) / (slowdownTime * slowdownTime);
                        }
                        else
                        {
                            dir = 2 * (diff - slowdownTime * velocity) / (slowdownTime * slowdownTime);
                        }
                        dir = Vector3.ClampMagnitude(dir, acceleration);

                        force *= System.Math.Min(magn / 0.5f, 1);

                        if (magn < endReachedDistance)
                        {
                            //END REACHED
                            NextPart();
                        }
                    }
                    else
                    {
                        dir *= acceleration;
                    }

                    //Debug.DrawRay (tr.position+Vector3.up, dir*3, Color.blue);

                    velocity += (dir + force * wallForce) * deltaTime;

                    if (slowWhenNotFacingTarget)
                    {
                        float dot = (Vector3.Dot(normdir, tr.forward) + 0.5f) * (1.0f / 1.5f);
                        //velocity = Vector3.ClampMagnitude (velocity, maxSpeed * Mathf.Max (dot, 0.2f) );
                        float xzmagn = Mathf.Sqrt(velocity.x * velocity.x + velocity.z * velocity.z);
                        float prevy  = velocity.y;
                        velocity.y = 0;
                        float mg = Mathf.Min(xzmagn, maxSpeed * Mathf.Max(dot, 0.2f));
                        velocity = Vector3.Lerp(tr.forward * mg, velocity.normalized * mg, Mathf.Clamp(endPointIsTarget ? (magn * 2) : 0, 0.5f, 1.0f));

                        velocity.y = prevy;
                    }
                    else
                    {
                        // Clamp magnitude on the XZ axes
                        float xzmagn = Mathf.Sqrt(velocity.x * velocity.x + velocity.z * velocity.z);
                        xzmagn = maxSpeed / xzmagn;
                        if (xzmagn < 1)
                        {
                            velocity.x *= xzmagn;
                            velocity.z *= xzmagn;
                            //Vector3.ClampMagnitude (velocity, maxSpeed);
                        }
                    }

                    //Debug.DrawLine (tr.position, tg, lastCorner ? Color.red : Color.green);


                    if (endPointIsTarget)
                    {
                        Vector3 trotdir = Vector3.Lerp(velocity, currentTargetDirection, System.Math.Max(1 - magn * 2, 0));
                        RotateTowards(trotdir);
                    }
                    else
                    {
                        RotateTowards(velocity);
                    }

                    //Applied after rotation to enable proper checks on if velocity is zero
                    velocity += deltaTime * gravity;

                    if (rvoController != null && rvoController.enabled)
                    {
                        //Use RVOController
                        tr.position = position;
                        rvoController.Move(velocity);
                    }
                    else
                    if (controller != null && controller.enabled)
                    {
                        //Use CharacterController
                        tr.position = position;
                        controller.Move(velocity * deltaTime);
                    }
                    else
                    {
                        //Use Transform
                        float lasty = position.y;
                        position += velocity * deltaTime;

                        position = RaycastPosition(position, lasty);

                        tr.position = position;
                    }
                }
                else
                {
                    if (rvoController != null && rvoController.enabled)
                    {
                        //Use RVOController
                        rvoController.Move(Vector3.zero);
                    }
                }

                if (pt is RichSpecial)
                {
                    if (!traversingSpecialPath)
                    {
                        StartCoroutine(TraverseSpecial(pt as RichSpecial));
                    }
                }
                //w.Stop();
                //Debug.Log ((w.Elapsed.TotalMilliseconds*1000));
            }
            else
            {
                if (rvoController != null && rvoController.enabled)
                {
                    //Use RVOController
                    rvoController.Move(Vector3.zero);
                }
                else
                if (controller != null && controller.enabled)
                {
                }
                else
                {
                    tr.position = RaycastPosition(tr.position, tr.position.y);
                }
            }
        }
예제 #4
0
        /** Update is called once per frame */
        protected virtual void Update()
        {
            deltaTime = Mathf.Min(Time.smoothDeltaTime * 2, Time.deltaTime);

            if (rp != null)
            {
                RichPathPart currentPart = rp.GetCurrentPart();
                var          fn          = currentPart as RichFunnel;
                if (fn != null)
                {
                    // Clamp the current position to the navmesh
                    // and update the list of upcoming corners in the path
                    // and store that in the 'nextCorners' variable
                    Vector3 position = UpdateTarget(fn);

                    // Only get walls every 5th frame to save on performance
                    if (Time.frameCount % 5 == 0 && wallForce > 0 && wallDist > 0)
                    {
                        wallBuffer.Clear();
                        fn.FindWalls(wallBuffer, wallDist);
                    }

                    // Target point
                    int     tgIndex     = 0;
                    Vector3 targetPoint = nextCorners[tgIndex];
                    Vector3 dir         = targetPoint - position;
                    dir.y = 0;

                    bool passedTarget = Vector3.Dot(dir, currentTargetDirection) < 0;
                    // Check if passed target in another way
                    if (passedTarget && nextCorners.Count - tgIndex > 1)
                    {
                        tgIndex++;
                        targetPoint = nextCorners[tgIndex];
                    }

                    // Check if the target point changed compared to last frame
                    if (targetPoint != lastTargetPoint)
                    {
                        currentTargetDirection   = targetPoint - position;
                        currentTargetDirection.y = 0;
                        currentTargetDirection.Normalize();
                        lastTargetPoint = targetPoint;
                    }

                    // Direction to target
                    dir   = targetPoint - position;
                    dir.y = 0;

                    // Normalized direction
                    Vector3 normdir = VectorMath.Normalize(dir, out distanceToWaypoint);

                    // Is the endpoint of the path (part) the current target point
                    bool targetIsEndPoint = lastCorner && nextCorners.Count - tgIndex == 1;

                    // When very close to the target point, move directly towards the target
                    // instead of using accelerations as they tend to be a bit jittery in this case
                    if (targetIsEndPoint && distanceToWaypoint < 0.01f * maxSpeed)
                    {
                        // Velocity will be at most 1 times max speed, it will be further clamped below
                        velocity = (targetPoint - position) * 100;
                    }
                    else
                    {
                        // Calculate force from walls
                        Vector3 wallForceVector = CalculateWallForce(position, normdir);
                        Vector2 accelerationVector;

                        if (targetIsEndPoint)
                        {
                            accelerationVector = CalculateAccelerationToReachPoint(To2D(targetPoint - position), Vector2.zero, To2D(velocity));
                            //accelerationVector = Vector3.ClampMagnitude(accelerationVector, acceleration);

                            // Reduce the wall avoidance force as we get closer to our target
                            wallForceVector *= System.Math.Min(distanceToWaypoint / 0.5f, 1);

                            if (distanceToWaypoint < endReachedDistance)
                            {
                                // END REACHED
                                NextPart();
                            }
                        }
                        else
                        {
                            var nextNextCorner = tgIndex < nextCorners.Count - 1 ? nextCorners[tgIndex + 1] : (targetPoint - position) * 2 + position;
                            var targetVelocity = (nextNextCorner - targetPoint).normalized * maxSpeed;

                            accelerationVector = CalculateAccelerationToReachPoint(To2D(targetPoint - position), To2D(targetVelocity), To2D(velocity));
                        }

                        // Update the velocity using the acceleration
                        velocity += (new Vector3(accelerationVector.x, 0, accelerationVector.y) + wallForceVector * wallForce) * deltaTime;
                    }

                    var currentNode = fn.CurrentNode;

                    Vector3 closestOnNode;
                    if (currentNode != null)
                    {
                        closestOnNode = currentNode.ClosestPointOnNode(position);
                    }
                    else
                    {
                        closestOnNode = position;
                    }

                    // Distance to the end of the path (as the crow flies)
                    var distToEndOfPath = (fn.exactEnd - closestOnNode).magnitude;

                    // Max speed to use for this frame
                    var currentMaxSpeed = maxSpeed;
                    currentMaxSpeed *= Mathf.Sqrt(Mathf.Min(1, distToEndOfPath / (maxSpeed * slowdownTime)));

                    // Check if the agent should slow down in case it is not facing the direction it wants to move in
                    if (slowWhenNotFacingTarget)
                    {
                        // 1 when normdir is in the same direction as tr.forward
                        // 0.2 when they point in the opposite directions
                        float directionSpeedFactor = Mathf.Max((Vector3.Dot(normdir, tr.forward) + 0.5f) / 1.5f, 0.2f);
                        currentMaxSpeed *= directionSpeedFactor;
                        float currentSpeed = VectorMath.MagnitudeXZ(velocity);
                        float prevy        = velocity.y;
                        velocity.y   = 0;
                        currentSpeed = Mathf.Min(currentSpeed, currentMaxSpeed);

                        // Make sure the agent always moves in the forward direction
                        // except when getting close to the end of the path in which case
                        // the velocity can be in any direction
                        velocity = Vector3.Lerp(velocity.normalized * currentSpeed, tr.forward * currentSpeed, Mathf.Clamp(targetIsEndPoint ? distanceToWaypoint * 2 : 1, 0.0f, 0.5f));

                        velocity.y = prevy;
                    }
                    else
                    {
                        velocity = VectorMath.ClampMagnitudeXZ(velocity, currentMaxSpeed);
                    }

                    // Apply gravity
                    velocity += deltaTime * gravity;

                    if (rvoController != null && rvoController.enabled)
                    {
                        // Send a message to the RVOController that we want to move
                        // with this velocity. In the next simulation step, this velocity
                        // will be processed and it will be fed back the rvo controller
                        // and finally it will be used by this script when calling the
                        // CalculateMovementDelta method below

                        // Make sure that we don't move further than to the end point of the path
                        // If the RVO simulation FPS is low and we did not do this, the agent
                        // might overshoot the target a lot.
                        var rvoTarget = position + VectorMath.ClampMagnitudeXZ(velocity, distToEndOfPath);
                        rvoController.SetTarget(rvoTarget, VectorMath.MagnitudeXZ(velocity), maxSpeed);
                    }

                    // Direction and distance to move during this frame
                    Vector3 deltaPosition;
                    if (rvoController != null && rvoController.enabled)
                    {
                        // Use RVOController to get a processed delta position
                        // such that collisions will be avoided if possible
                        deltaPosition = rvoController.CalculateMovementDelta(position, deltaTime);

                        // The RVOController does not know about gravity
                        // so we copy it from the normal velocity calculation
                        deltaPosition.y = velocity.y * deltaTime;
                    }
                    else
                    {
                        deltaPosition = velocity * deltaTime;
                    }

                    if (targetIsEndPoint)
                    {
                        // Rotate towards the direction that the agent was in
                        // when the target point was seen for the first time
                        // TODO: Some magic constants here, should probably compute them from other variables
                        // or expose them as separate variables
                        Vector3 trotdir = Vector3.Lerp(deltaPosition.normalized, currentTargetDirection, System.Math.Max(1 - distanceToWaypoint * 2, 0));
                        RotateTowards(trotdir);
                    }
                    else
                    {
                        // Rotate towards the direction we are moving in
                        RotateTowards(deltaPosition);
                    }

                    if (controller != null && controller.enabled)
                    {
                        // Use CharacterController
                        tr.position = position;
                        controller.Move(deltaPosition);
                        // Grab the position after the movement to be able to take physics into account
                        position = tr.position;
                    }
                    else
                    {
                        // Use Transform
                        float lastY = position.y;
                        position += deltaPosition;
                        // Position the character on the ground
                        position = RaycastPosition(position, lastY);
                    }

                    // Clamp the position to the navmesh after movement is done
                    var clampedPosition = fn.ClampToNavmesh(position);

                    if (position != clampedPosition)
                    {
                        // The agent was outside the navmesh. Remove that component of the velocity
                        // so that the velocity only goes along the direction of the wall, not into it
                        var difference = clampedPosition - position;
                        velocity -= difference * Vector3.Dot(difference, velocity) / difference.sqrMagnitude;

                        // Make sure the RVO system knows that there was a collision here
                        // Otherwise other agents may think this agent continued to move forwards
                        // and avoidance quality may suffer
                        if (rvoController != null && rvoController.enabled)
                        {
                            rvoController.SetCollisionNormal(difference);
                        }
                    }

                    tr.position = clampedPosition;
                }
                else
                {
                    if (rvoController != null && rvoController.enabled)
                    {
                        //Use RVOController
                        rvoController.Move(Vector3.zero);
                    }
                }
                if (currentPart is RichSpecial)
                {
                    // The current path part is a special part, for example a link
                    // Movement during this part of the path is handled by the TraverseSpecial coroutine
                    if (!traversingSpecialPath)
                    {
                        StartCoroutine(TraverseSpecial(currentPart as RichSpecial));
                    }
                }
            }
            else
            {
                if (rvoController != null && rvoController.enabled)
                {
                    // Use RVOController
                    rvoController.Move(Vector3.zero);
                }
                else
                if (controller != null && controller.enabled)
                {
                }
                else
                {
                    tr.position = RaycastPosition(tr.position, tr.position.y);
                }
            }
        }