Ejemplo n.º 1
0
    public bool IsGrounded()
    {
        Vector3 o = controller.Position + new Vector3(0, 3, 0);

        RaycastHit hit;

        if (Physics.SphereCast(o, controller.Radius, controller.Down, out hit, Mathf.Infinity, walkable))
        {
            DebugDraw.DrawMarker(o, controller.Radius, Color.green, 0f, false);
            DebugDraw.DrawMarker(hit.point, controller.Radius, Color.red, 0f, false);
            Vector3 p = Vector3.MoveTowards(hit.point, o, controller.Radius);

            controller.dp = p;

            if (controller.Position.y <= p.y)
            {
                Ground = new GroundHit(p);
                return(true);
            }
            else
            {
                clearGround();
                return(false);
            }
        }
        controller.dp = Vector3.zero;
        clearGround();
        return(false);
    }
    public void ProbeGround(Vector3 origin, float tolerance)
    {
        reset();

        Vector3 up   = controller.Up;
        Vector3 down = -up;

        Vector3 o = origin + (up * tolerance);

        float smallerRadius = controller.Radius - (tolerance * tolerance);

        RaycastHit hit;

        if (Physics.SphereCast(o, smallerRadius, down, out hit, Mathf.Infinity, walkable))
        {
            var hitcolliderType = hit.collider.gameObject.GetComponent <CollisionType>();
            if (hitcolliderType == null)
            {
                hitcolliderType = hit.collider.gameObject.AddComponent <CollisionType>();
            }

            transform = hit.transform;

            primaryGround = new GroundHit(hit.point, hit.normal, hit.distance);
        }
    }
 private void ResetGrounds()
 {
     primaryGround = null;
     nearGround    = null;
     farGround     = null;
     flushGround   = null;
     stepGround    = null;
 }
Ejemplo n.º 4
0
 /// <summary>
 /// 设置角色上一帧的信息
 /// </summary>
 /// <param name="player"></param>
 /// <param name="time"></param>
 private void SetPlayerPrevInfo(PlayerEntity player, float time)
 {
     LastVelocity    = Quaternion.Inverse(player.orientation.RotationYaw) * player.playerMove.Velocity.ToVector4();
     CurrentVelocity = LastVelocity.ToVector4();
     LastNormal      = GroundInfo.surfaceNormal;
     DeltaTime       = time;
     GroundInfo      = player.characterContoller.Value.GetGroundHit;
 }
 private void reset()
 {
     primaryGround = null;
     nearGround = null;
     farGround = null;
     stepGround = null;
     flushGround = null;
 }
Ejemplo n.º 6
0
    // Use this for initialization
    void Start()
    {
        startTime       = Time.time;
        groundHit       = GetComponentInChildren <GroundHit>();
        dropZone        = GetComponentInChildren <DropZone>();
        powerupSpawn    = GetComponentInChildren <PowerupSpawn>();
        craneController = GetComponentInChildren <CraneController>();

        gameOverText.text = "";
    }
Ejemplo n.º 7
0
        private void ResetGrounds()
        {
            primaryGround = null;
            nearGround    = null;
            farGround     = null;
            flushGround   = null;
            stepGround    = null;

            doubleEdgeGrounded = false;
        }
Ejemplo n.º 8
0
 void Jump()
 {
     if (!IsOnFloor())
     {
         velocity.y -= gravity;
     }
     else
     {
         velocity.y  = 0;
         velocity.y += jumpForce;
         GroundHit?.Invoke();
     }
 }
    public bool IsGrounded( bool currentlyGrounded, float distance, out Vector3 groundNormal )
    {
        groundNormal = Vector3.zero;

        if( primaryGround == null || primaryGround.distance > distance )
            return false;
        RaycastHit hit;
        if( Physics.SphereCast(controller.transform.position, controller.Radius, controller.Down, out hit, Mathf.Infinity, walkable) )
        {
            Debug.Log("Found it");
            primaryGround = new GroundHit(hit.point, hit.normal, hit.distance);
            return true;
        }

        return false;
    }
    public bool IsGrounded(bool currentlyGrounded, float distance, out Vector3 groundNormal)
    {
        groundNormal = Vector3.zero;

        if (primaryGround == null || primaryGround.distance > distance)
        {
            return(false);
        }
        RaycastHit hit;

        if (Physics.SphereCast(controller.transform.position, controller.Radius, controller.Down, out hit, Mathf.Infinity, walkable))
        {
            Debug.Log("Found it");
            primaryGround = new GroundHit(hit.point, hit.normal, hit.distance);
            return(true);
        }

        return(false);
    }
    public void ProbeGround( Vector3 origin, float tolerance )
    {
        reset();

        Vector3 up = controller.Up;
        Vector3 down = -up;

        Vector3 o = origin + ( up * tolerance );

        float smallerRadius = controller.Radius - ( tolerance * tolerance );

        RaycastHit hit;
        if( Physics.SphereCast( o, smallerRadius, down, out hit, Mathf.Infinity, walkable ) )
        {
            var hitcolliderType = hit.collider.gameObject.GetComponent<CollisionType>();
            if( hitcolliderType == null )
                hitcolliderType = hit.collider.gameObject.AddComponent<CollisionType>();

            transform = hit.transform;

            primaryGround = new GroundHit( hit.point, hit.normal, hit.distance );

        }
    }
        /// <summary>
        /// Scan the surface below us for ground. Follow up the initial scan with subsequent scans
        /// designed to test what kind of surface we are standing above and handle different edge cases
        /// </summary>
        /// <param name="origin">Center of the sphere for the initial SphereCast</param>
        /// <param name="iter">Debug tool to print out which ProbeGround iteration is being run (3 are run each frame for the controller)</param>
        public void ProbeGround(Vector3 origin, int iter)
        {
            ResetGrounds();

            Vector3 up   = controller.up;
            Vector3 down = -up;

            Vector3 o = origin + (up * Tolerance);

            // Reduce our radius by Tolerance squared to avoid failing the SphereCast due to clipping with walls
            float smallerRadius = controller.radius - (Tolerance * Tolerance);

            RaycastHit hit;

            if (Physics.SphereCast(o, smallerRadius, down, out hit, Mathf.Infinity, walkable, triggerInteraction))
            {
                var superColType = hit.collider.gameObject.GetComponent <SuperCollisionType>();

                if (superColType == null)
                {
                    superColType = defaultCollisionType;
                }

                superCollisionType = superColType;
                transform          = hit.transform;

                // By reducing the initial SphereCast's radius by Tolerance, our casted sphere no longer fits with
                // our controller's shape. Reconstruct the sphere cast with the proper radius
                SimulateSphereCast(hit.normal, out hit);

                primaryGround = new GroundHit(hit.point, hit.normal, hit.distance);

                // If we are standing on a perfectly flat surface, we cannot be either on an edge,
                // On a slope or stepping off a ledge
                if (Vector3.Distance(Math3d.ProjectPointOnPlane(controller.up, controller.transform.position, hit.point), controller.transform.position) < TinyTolerance)
                {
                    return;
                }

                // As we are standing on an edge, we need to retrieve the normals of the two
                // faces on either side of the edge and store them in nearHit and farHit

                Vector3 toCenter = Math3d.ProjectVectorOnPlane(up, (controller.transform.position - hit.point).normalized * TinyTolerance);

                Vector3 awayFromCenter = Quaternion.AngleAxis(-80.0f, Vector3.Cross(toCenter, up)) * -toCenter;

                Vector3 nearPoint = hit.point + toCenter + (up * TinyTolerance);
                Vector3 farPoint  = hit.point + (awayFromCenter * 3);

                RaycastHit nearHit;
                RaycastHit farHit;

                Physics.Raycast(nearPoint, down, out nearHit, Mathf.Infinity, walkable, triggerInteraction);
                Physics.Raycast(farPoint, down, out farHit, Mathf.Infinity, walkable, triggerInteraction);

                nearGround = new GroundHit(nearHit.point, nearHit.normal, nearHit.distance);
                farGround  = new GroundHit(farHit.point, farHit.normal, farHit.distance);

                // If we are currently standing on ground that should be counted as a wall,
                // we are likely flush against it on the ground. Retrieve what we are standing on
                if (Vector3.Angle(hit.normal, up) > superColType.StandAngle)
                {
                    // Retrieve a vector pointing down the slope
                    Vector3 r = Vector3.Cross(hit.normal, down);
                    Vector3 v = Vector3.Cross(r, hit.normal);

                    Vector3 flushOrigin = hit.point + hit.normal * TinyTolerance;

                    RaycastHit flushHit;

                    if (Physics.Raycast(flushOrigin, v, out flushHit, Mathf.Infinity, walkable, triggerInteraction))
                    {
                        RaycastHit sphereCastHit;

                        if (SimulateSphereCast(flushHit.normal, out sphereCastHit))
                        {
                            flushGround = new GroundHit(sphereCastHit.point, sphereCastHit.normal, sphereCastHit.distance);
                        }
                        else
                        {
                            // Uh oh
                        }
                    }
                }

                // If we are currently standing on a ledge then the face nearest the center of the
                // controller should be steep enough to be counted as a wall. Retrieve the ground
                // it is connected to at it's base, if there exists any
                if (Vector3.Angle(nearHit.normal, up) > superColType.StandAngle || nearHit.distance > Tolerance)
                {
                    var col = nearHit.collider.gameObject.GetComponent <SuperCollisionType>();

                    if (col == null)
                    {
                        col = defaultCollisionType;
                    }

                    // We contacted the wall of the ledge, rather than the landing. Raycast down
                    // the wall to retrieve the proper landing
                    if (Vector3.Angle(nearHit.normal, up) > col.StandAngle)
                    {
                        // Retrieve a vector pointing down the slope
                        Vector3 r = Vector3.Cross(nearHit.normal, down);
                        Vector3 v = Vector3.Cross(r, nearHit.normal);

                        RaycastHit stepHit;

                        if (Physics.Raycast(nearPoint, v, out stepHit, Mathf.Infinity, walkable, triggerInteraction))
                        {
                            stepGround = new GroundHit(stepHit.point, stepHit.normal, stepHit.distance);
                        }
                    }
                    else
                    {
                        stepGround = new GroundHit(nearHit.point, nearHit.normal, nearHit.distance);
                    }
                }
            }
            // If the initial SphereCast fails, likely due to the controller clipping a wall,
            // fallback to a raycast simulated to SphereCast data
            else if (Physics.Raycast(o, down, out hit, Mathf.Infinity, walkable, triggerInteraction))
            {
                var superColType = hit.collider.gameObject.GetComponent <SuperCollisionType>();

                if (superColType == null)
                {
                    superColType = defaultCollisionType;
                }

                superCollisionType = superColType;
                transform          = hit.transform;

                RaycastHit sphereCastHit;

                if (SimulateSphereCast(hit.normal, out sphereCastHit))
                {
                    primaryGround = new GroundHit(sphereCastHit.point, sphereCastHit.normal, sphereCastHit.distance);
                }
                else
                {
                    primaryGround = new GroundHit(hit.point, hit.normal, hit.distance);
                }
            }
            else
            {
                Debug.LogError("[SuperCharacterComponent]: No ground was found below the player; player has escaped level");
            }
        }
        /// <summary>
        /// Scan the surface below us for ground. Follow up the initial scan with subsequent scans
        /// designed to test what kind of surface we are standing above and handle different edge cases
        /// </summary>
        /// <param name="origin">Center of the sphere for the initial SphereCast</param>
        /// <param name="iter">Debug tool to print out which ProbeGround iteration is being run (3 are run each frame for the controller)</param>
        public void ProbeGround(Vector3 origin, int iter)
        {
            ResetGrounds();

            Vector3 up = controller.up;
            Vector3 down = -up;

            Vector3 o = origin + (up * Tolerance);

            // Reduce our radius by Tolerance squared to avoid failing the SphereCast due to clipping with walls
            float smallerRadius = controller.radius - (Tolerance * Tolerance);

            RaycastHit hit;

            if (Physics.SphereCast(o, smallerRadius, down, out hit, Mathf.Infinity, walkable))
            {
                var superColType = hit.collider.gameObject.GetComponent<SuperCollisionType>();

                if (superColType == null)
                {
                    superColType = defaultCollisionType;
                }

                superCollisionType = superColType;
                transform = hit.transform;

                // By reducing the initial SphereCast's radius by Tolerance, our casted sphere no longer fits with
                // our controller's shape. Reconstruct the sphere cast with the proper radius
                SimulateSphereCast(hit.normal, out hit);

                primaryGround = new GroundHit(hit.point, hit.normal, hit.distance);

                // If we are standing on a perfectly flat surface, we cannot be either on an edge,
                // On a slope or stepping off a ledge
                if (Vector3.Distance(Math3d.ProjectPointOnPlane(controller.up, controller.transform.position, hit.point), controller.transform.position) < TinyTolerance)
                {
                    return;
                }

                // As we are standing on an edge, we need to retrieve the normals of the two
                // faces on either side of the edge and store them in nearHit and farHit

                Vector3 toCenter = Math3d.ProjectVectorOnPlane(up, (controller.transform.position - hit.point).normalized * TinyTolerance);

                Vector3 awayFromCenter = Quaternion.AngleAxis(-80.0f, Vector3.Cross(toCenter, up)) * -toCenter;

                Vector3 nearPoint = hit.point + toCenter + (up * TinyTolerance);
                Vector3 farPoint = hit.point + (awayFromCenter * 3);

                RaycastHit nearHit;
                RaycastHit farHit;

                Physics.Raycast(nearPoint, down, out nearHit, Mathf.Infinity, walkable);
                Physics.Raycast(farPoint, down, out farHit, Mathf.Infinity, walkable);

                nearGround = new GroundHit(nearHit.point, nearHit.normal, nearHit.distance);
                farGround = new GroundHit(farHit.point, farHit.normal, farHit.distance);

                // If we are currently standing on ground that should be counted as a wall,
                // we are likely flush against it on the ground. Retrieve what we are standing on
                if (Vector3.Angle(hit.normal, up) > superColType.StandAngle)
                {
                    // Retrieve a vector pointing down the slope
                    Vector3 r = Vector3.Cross(hit.normal, down);
                    Vector3 v = Vector3.Cross(r, hit.normal);

                    Vector3 flushOrigin = hit.point + hit.normal * TinyTolerance;

                    RaycastHit flushHit;

                    if (Physics.Raycast(flushOrigin, v, out flushHit, Mathf.Infinity, walkable))
                    {
                        RaycastHit sphereCastHit;

                        if (SimulateSphereCast(flushHit.normal, out sphereCastHit))
                        {
                            flushGround = new GroundHit(sphereCastHit.point, sphereCastHit.normal, sphereCastHit.distance);
                        }
                        else
                        {
                            // Uh oh
                        }
                    }
                }

                // If we are currently standing on a ledge then the face nearest the center of the
                // controller should be steep enough to be counted as a wall. Retrieve the ground
                // it is connected to at it's base, if there exists any
                if (Vector3.Angle(nearHit.normal, up) > superColType.StandAngle || nearHit.distance > Tolerance)
                {
                    var col = nearHit.collider.gameObject.GetComponent<SuperCollisionType>();

                    if (col == null)
                    {
                        col = defaultCollisionType;
                    }

                    // We contacted the wall of the ledge, rather than the landing. Raycast down
                    // the wall to retrieve the proper landing
                    if (Vector3.Angle(nearHit.normal, up) > col.StandAngle)
                    {
                        // Retrieve a vector pointing down the slope
                        Vector3 r = Vector3.Cross(nearHit.normal, down);
                        Vector3 v = Vector3.Cross(r, nearHit.normal);

                        RaycastHit stepHit;

                        if (Physics.Raycast(nearPoint, v, out stepHit, Mathf.Infinity, walkable))
                        {
                            stepGround = new GroundHit(stepHit.point, stepHit.normal, stepHit.distance);
                        }
                    }
                    else
                    {
                        stepGround = new GroundHit(nearHit.point, nearHit.normal, nearHit.distance);
                    }
                }
            }
            // If the initial SphereCast fails, likely due to the controller clipping a wall,
            // fallback to a raycast simulated to SphereCast data
            else if (Physics.Raycast(o, down, out hit, Mathf.Infinity, walkable))
            {
                var superColType = hit.collider.gameObject.GetComponent<SuperCollisionType>();

                if (superColType == null)
                {
                    superColType = defaultCollisionType;
                }

                superCollisionType = superColType;
                transform = hit.transform;

                RaycastHit sphereCastHit;

                if (SimulateSphereCast(hit.normal, out sphereCastHit))
                {
                    primaryGround = new GroundHit(sphereCastHit.point, sphereCastHit.normal, sphereCastHit.distance);
                }
                else
                {
                    primaryGround = new GroundHit(hit.point, hit.normal, hit.distance);
                }
            }
            else
            {
                Debug.LogError("[SuperCharacterComponent]: No ground was found below the player; player has escaped level");
            }
        }
Ejemplo n.º 14
0
 // useless for now
 public void OnGroundHit(GroundHit ground, GroundHit lastground, LayerMask layermask)
 {
 }
Ejemplo n.º 15
0
        // PM_SlideMove() is one of the several variant Move() funcs available standard with the
        // Actor package provided. It's entire purpose is to 'slide' and 'snap' the Actor on 'stable'
        // surfaces whilst also dealing with the conventional issue of movement into and along blocking
        // planes in the physics scene. Use this method primarily if you plan on keeping your actor level
        // with the floor.
        public static void PM_SlideMove(
            IActorReceiver _rec,
            Actor _actor,
            ref Vector3 _pos,
            ref Vector3 _vel,
            Quaternion _orient,
            LayerMask _filter,
            float _fdt)
        {
            /* BASE CASES IN WHICH WE SHOULDN'T MOVE AT ALL */
            if (_rec == null)
            {
                return;
            }

            /* STEPS:
             *  RUN:
             *  GROUND TRACE & GROUND SNAP -> OVERLAP -> PUSHBACK -> CONVEX HULL NORMAL (NEARBY PLANE DETECTION) -> GENERATE GEOMETRY BITMASK -> TRACING -> REPEAT
             */

            ArchetypeHeader.Archetype _arc      = _actor.GetArchetype();
            SlideSnapType             _snaptype = _actor.SnapType;

            Collider[] _colliders = _actor.Colliders;
            Collider   _self      = _arc.Collider();

            Vector3[]    _normals = _actor.Normals;
            RaycastHit[] _traces  = _actor.Hits;

            Vector3 _tracepos       = _pos;
            Vector3 _groundtracepos = _pos;

            Vector3 _lastplane      = Vector3.zero;
            Vector3 _groundtracedir = _orient * new Vector3(0, -1, 0);
            Vector3 _up             = _orient * new Vector3(0, 1, 0);

            float _tf   = 1F;
            float _skin = ArchetypeHeader.GET_SKINEPSILON(_arc.PrimitiveType());
            float _bias = ArchetypeHeader.GET_TRACEBIAS(_arc.PrimitiveType());

            int _bumpcount       = 0;
            int _groundbumpcount = 0;
            int _pushbackcount   = 0;
            int _gflags          = 0;

            GroundHit _ground     = _actor.Ground;
            GroundHit _lastground = _actor.LastGround;

            _lastground.actorpoint = _ground.actorpoint;
            _lastground.normal     = _ground.normal;
            _lastground.point      = _ground.point;
            _lastground.stable     = _ground.stable;
            _lastground.snapped    = _ground.snapped;
            _lastground.distance   = _ground.distance;

            _ground.Clear();

            float _groundtracelen = (_lastground.stable && _lastground.snapped) ? 0.1F : 0.05F;

            while (_groundbumpcount++ < MAX_GROUNDBUMPS &&
                   _groundtracelen > 0F)
            {
                // trace along dir
                // if detected
                // if stable :
                // end trace and determine whether a snap is to occur
                // else :
                // clip along floor
                // continue
                // else :
                // break out of loop as no floor was detected
                _arc.Trace(_groundtracepos + (_up * 0.01F),
                           _groundtracedir,
                           _groundtracelen,
                           _orient,
                           _filter,
                           0F,
                           QueryTriggerInteraction.Ignore,
                           _traces,
                           out int _groundtraces);

                ArchetypeHeader.TraceFilters.FindClosestFilterInvalids(
                    ref _groundtraces,
                    out int _i0,
                    _bias,
                    _self,
                    _traces);

                if (_i0 >= 0) // an intersection has occured, but we aren't sure its ground yet
                {
                    RaycastHit _closest = _traces[_i0];

                    _ground.distance   = _closest.distance;
                    _ground.normal     = _closest.normal;
                    _ground.actorpoint = _groundtracepos;
                    _ground.stable     = _actor.DetermineGroundStability(_vel, _closest, _filter);

                    _groundtracepos += _groundtracedir * (_closest.distance);
                    // warp regardless of stablility. We'll only be setting our trace position
                    // to our ground trace position if a stable floor has been determined, and snapping is enabled.

                    if (_ground.stable)
                    {
                        bool _cansnap = _snaptype == SlideSnapType.Always;

                        switch (_snaptype)
                        {
                        case SlideSnapType.Never:
                            _cansnap = false;
                            break;

                        case SlideSnapType.Toggled:
                            _cansnap = _actor.SnapEnabled;
                            break;
                        }

                        if (_cansnap)
                        {
                            _ground.snapped = true;
                        }

                        _rec.OnGroundHit(_ground, _lastground, _filter);

                        // gonna keep the typo bc pog
                        // shoot up check for snap availability
                        _arc.Trace(
                            _groundtracepos,
                            _up,
                            _skin + 0.1F,
                            _orient,
                            _filter,
                            0F,
                            QueryTriggerInteraction.Ignore,
                            _traces,
                            out int _stepcunt);

                        ArchetypeHeader.TraceFilters.FindClosestFilterInvalids(ref _stepcunt,
                                                                               out int _i1,
                                                                               _bias,
                                                                               _self,
                                                                               _traces);

                        if (_i1 >= 0)
                        {
                            RaycastHit _snap = _traces[_i1];

                            Vector3 _c = Vector3.Cross(_snap.normal, _ground.normal);
                            _c.Normalize();

                            Vector3 _f = Vector3.Cross(_up, _c);
                            _f.Normalize();

                            if (VectorHeader.Dot(_vel, _f) <= 0F)
                            {
                                if (VectorHeader.Dot(_vel, _snap.normal) < 0F)
                                {
                                    _rec.OnTraceHit(_snap, _groundtracepos, _vel);
                                }

                                _gflags |= (1 << 1);
                                VectorHeader.ProjectVector(ref _vel, _c);
                            }

                            _groundtracepos += _up * Mathf.Max(
                                Mathf.Min(_snap.distance - _skin, _skin), 0F);
                        }
                        else
                        {
                            _groundtracepos += _up * (_skin);
                        }

                        if (_ground.snapped)
                        {
                            _tracepos = _groundtracepos;

                            _lastplane = _ground.normal;
                            _gflags   |= (1 << 0);

                            VectorHeader.ClipVector(ref _vel, _ground.normal);
                            //VectorHeader.CrossProjection(ref _vel, _up, _ground.normal);
                        }

                        _groundtracelen = 0F;
                    }
                    else
                    {
                        // clip, normalize, and continue:
                        VectorHeader.ClipVector(ref _groundtracedir, _closest.normal);
                        _groundtracedir.Normalize();
                        _groundtracelen -= _closest.distance;
                    }
                }
                else // nothing discovered, end out of our ground loop.
                {
                    _groundtracelen = 0F;
                }
            }

            while (_pushbackcount++ < ActorHeader.MAX_PUSHBACKS)
            {
                _arc.Overlap(
                    _tracepos,
                    _orient,
                    _filter,
                    0F,
                    QueryTriggerInteraction.Ignore,
                    _colliders,
                    out int _overlapsfound);

                ArchetypeHeader.OverlapFilters.FilterSelf(
                    ref _overlapsfound,
                    _self,
                    _colliders);

                if (_overlapsfound == 0) // nothing !
                {
                    break;
                }
                else
                {
                    for (int _colliderindex = 0; _colliderindex < _overlapsfound; _colliderindex++)
                    {
                        Collider  _other  = _colliders[_colliderindex];
                        Transform _otherT = _other.GetComponent <Transform>();

                        if (Physics.ComputePenetration(_self, _tracepos, _orient, _other, _otherT.position, _otherT.rotation, out Vector3 _normal, out float _distance))
                        {
                            _tracepos += _normal * (_distance + _skin);

                            PM_SlideDetermineImmediateGeometry(ref _vel,
                                                               ref _lastplane,
                                                               _actor.DeterminePlaneStability(_normal, _other),
                                                               _normal,
                                                               _ground.normal,
                                                               _ground.stable && _ground.snapped,
                                                               _up,
                                                               ref _gflags);
                            break;
                        }
                    }
                }
            }

            while (_bumpcount++ < ActorHeader.MAX_BUMPS &&
                   _tf > 0)
            {
                // Begin Trace
                Vector3 _trace    = _vel * _fdt;
                float   _tracelen = _trace.magnitude;

                // IF unable to trace any further, break and end
                if (_tracelen <= MIN_DISPLACEMENT)
                {
                    _tf = 0;
                }
                else
                {
                    _arc.Trace(_tracepos,
                               _trace / _tracelen,
                               _tracelen + _skin,
                               _orient,
                               _filter,
                               0F,
                               QueryTriggerInteraction.Ignore,
                               _traces,
                               out int _tracecount);

                    ArchetypeHeader.TraceFilters.FindClosestFilterInvalids(
                        ref _tracecount,
                        out int _i0,
                        _bias,
                        _self,
                        _traces);

                    if (_i0 <= -1)      // nothing discovered :::
                    {
                        _tf        = 0; // end move
                        _tracepos += _trace;
                        break;
                    }
                    else // discovered an obstruction:::
                    {
                        RaycastHit _closest = _traces[_i0];
                        Vector3    _normal  = _closest.normal;

                        float _rto = _closest.distance / _tracelen;
                        _tf -= _rto;

                        float _dis = _closest.distance - _skin;
                        _tracepos += (_trace / _tracelen) * _dis; // move back along the trace line!

                        _rec.OnTraceHit(_closest, _tracepos, _vel);

                        PM_SlideDetermineImmediateGeometry(ref _vel,
                                                           ref _lastplane,
                                                           _actor.DeterminePlaneStability(_normal, _closest.collider),
                                                           _normal,
                                                           _ground.normal,
                                                           _ground.stable && _ground.snapped,
                                                           _up,
                                                           ref _gflags);

                        continue;
                    }
                }
            }

            _pos = _tracepos;
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="origin"></param>
        /// <param name="iter"></param>
        public void ProbeGround(Vector3 origin, int iter)
        {
            //Reset
            _primaryGround = null;
            _nearGround    = null;
            _farGround     = null;
            _stepGround    = null;
            _flushGround   = null;

            _originHit = null;

            Vector3 up   = _controller.up;
            Vector3 down = _controller.down;

            //碰撞检测起始位置
            Vector3 o = origin + (up * _tolerance);

            //用于碰撞检测的Sphere要小一点
            float smallerRadius = _controller.radius * 0.9f;

            RaycastHit hit;

            //向正下方投射Sphere看是是否碰撞到物体了
            if (Physics.SphereCast(o, smallerRadius, down, out hit, Mathf.Infinity, _walkableLayer, _triggerInteraction))
            {
                float standAngle = 0;
                float slopeLimit = 0;
                //拿到地面物体的碰撞属性
                collisionAttribute = hit.collider.GetComponent <GroundCollisionAttribute>();
                if (collisionAttribute != null)
                {
                    standAngle = collisionAttribute.StandAngle;
                    slopeLimit = collisionAttribute.SlopeLimit;
                }
                else
                {
                    standAngle = GroundCollisionAttribute.DEFAULT_STAND_ANGLE;
                    slopeLimit = GroundCollisionAttribute.DEFAULT_SLOPE_LIMIT;
                }

                _originHit = new GroundHit(hit.point, hit.normal, hit.distance);

                //检测碰撞到是不是真正的地面(因为通过投射Sphere检测到的碰撞物体的法线是一个差值,需要得到地面的实际碰撞信息)
                SimulateSphereCast(hit.normal, out hit);

                _primaryGround = new GroundHit(hit.point, hit.normal, hit.distance);

                transform = hit.transform;

                //将碰撞点投射到控制器位置所在的平面,如果里控制器位置的距离足够小,表示碰撞到的是一个平坦的平面
                if (Vector3.Distance(Math3d.ProjectPointOnPlane(_controller.up, _controller.worldPosition, hit.point), _controller.worldPosition) < _tinyTolerance)
                {
                    return;
                }

                Vector3 toCenter = Math3d.ProjectVectorOnPlane(up, (_controller.worldPosition - hit.point).normalized * _tinyTolerance);

                Vector3 awayFromCenter = Quaternion.AngleAxis(-80.0f, Vector3.Cross(toCenter, _controller.up)) * -toCenter;

                Vector3 nearPoint = hit.point + toCenter + (_controller.up * _tolerance);

                Vector3 farPoint = hit.point + (awayFromCenter * 3);

                RaycastHit nearHit;
                RaycastHit farHit;

                Physics.Raycast(nearPoint, _controller.down, out nearHit, Mathf.Infinity, _walkableLayer, _triggerInteraction);
                Physics.Raycast(farPoint, _controller.down, out farHit, Mathf.Infinity, _walkableLayer, _triggerInteraction);

                _nearGround = new GroundHit(nearHit.point, nearHit.normal, nearHit.distance);
                _farGround  = new GroundHit(farHit.point, farHit.normal, farHit.distance);

                if (Vector3.Angle(hit.normal, _controller.up) > standAngle)
                {//碰撞到的面是了一个陡坡或墙(碰撞面的法线与控制器正上方向的夹角大于设置的标准角度)
                    //计算平行于碰撞表面且向下的向量
                    Vector3 r = Vector3.Cross(hit.normal, _controller.down);
                    Vector3 v = Vector3.Cross(r, hit.normal);

                    Vector3 flushOrigin = hit.point + hit.normal * _tolerance;

                    RaycastHit flushHit;

                    //沿着碰撞面向下发射射线检测碰撞的表面
                    if (Physics.Raycast(flushOrigin, v, out flushHit, Mathf.Infinity, _walkableLayer, _triggerInteraction))
                    {
                        RaycastHit forTruethfulNormal;
                        //校正法线
                        if (SimulateSphereCast(flushHit.normal, out forTruethfulNormal))
                        {
                            //_primaryGround = new GroundHit(forTruethfulNormal.point, forTruethfulNormal.normal, forTruethfulNormal.distance);
                            _flushGround = new GroundHit(forTruethfulNormal.point, forTruethfulNormal.normal, forTruethfulNormal.distance);
                        }
                    }
                }

                //// If we are currently standing on a ledge then the face nearest the center of the
                //// controller should be steep enough to be counted as a wall. Retrieve the ground
                //// it is connected to at it's base, if there exists any
                //if (Vector3.Angle(nearHit.normal, up) > standAngle || nearHit.distance > _tolerance)
                //{

                //    // We contacted the wall of the ledge, rather than the landing. Raycast down
                //    // the wall to retrieve the proper landing
                //    if (Vector3.Angle(nearHit.normal, up) > standAngle)
                //    {
                //        // Retrieve a vector pointing down the slope
                //        Vector3 r = Vector3.Cross(nearHit.normal, down);
                //        Vector3 v = Vector3.Cross(r, nearHit.normal);

                //        RaycastHit stepHit;

                //        if (Physics.Raycast(nearPoint, v, out stepHit, Mathf.Infinity, _walkableLayer, _triggerInteraction))
                //        {
                //            _stepGround = new GroundHit(stepHit.point, stepHit.normal, stepHit.distance);
                //        }
                //    }
                //    else
                //    {
                //        _stepGround = new GroundHit(nearHit.point, nearHit.normal, nearHit.distance);
                //    }
                //}
            }
            else if (Physics.Raycast(o, down, out hit, Mathf.Infinity, _walkableLayer, _triggerInteraction))
            {
                //拿到地面物体的碰撞属性
                collisionAttribute = hit.collider.GetComponent <GroundCollisionAttribute>();

                RaycastHit sphereHit;

                if (SimulateSphereCast(hit.normal, out sphereHit))
                {
                    _primaryGround = new GroundHit(sphereHit.point, sphereHit.normal, sphereHit.distance);
                }
                else
                {
                    _primaryGround = new GroundHit(hit.point, hit.normal, hit.distance);
                }
            }
            else
            {
                Debug.LogError("Not found ground!");
            }
        }
Ejemplo n.º 17
0
 private void clearGround()
 {
     Ground = null;
 }