Exemplo n.º 1
0
        public static void PM_FlyClipVelocity(ref Vector3 _velocity, Vector3 _plane)
        {
            float _m = _velocity.magnitude;

            if (_m <= 0F) // preventing NaN generation
            {
                return;
            }
            else if (VectorHeader.Dot(_velocity / _m, _plane) < 0F) // only clip if we're piercing into the infinite plane
            {
                VectorHeader.ClipVector(ref _velocity, _plane);
            }
        }
Exemplo n.º 2
0
        // The velocity 'clipping' algorithm that is ran any time a plane is detected throughout
        // the PM_SlideMove() func execution.
        // It is responsible for:
        //      Handling velocity orientation along stable planes
        //      Handling velocity clipping along unstable 'wall' planes
        public static void PM_SlideClipVelocity(
            ref Vector3 _velocity,
            bool _stability,
            Vector3 _plane,
            bool _groundstability,
            Vector3 _groundplane,
            Vector3 _up)
        {
            float _m = _velocity.magnitude;

            if (_m <= 0F) // preventing NaN generation
            {
                return;
            }
            else
            {
                if (VectorHeader.Dot(_velocity / _m, _plane) < 0F) // only clip if we're piercing into the infinite plane
                {
                    if (_stability)                                // if stable, just orient and maintain magnitude
                    {
                        // anyways just orient along the newly discovered stable plane
                        //VectorHeader.CrossProjection(ref _velocity, _up, _groundplane);
                        VectorHeader.ClipVector(ref _velocity, _plane);
                    }
                    else
                    {
                        if (_groundstability) // clip along the surface of the ground
                        {
                            // clip normally
                            VectorHeader.ClipVector(ref _velocity, _plane);
                            // orient velocity to ground plane
                            VectorHeader.CrossProjection(ref _velocity, _up, _groundplane);

                            // i'd originally used this but when orienting velocities above certain planes,
                            // issues would arise where velocities would be clipped and projected in the opposite
                            // direction of where the character should be moving, so I'm resorting to orienting
                            // in this particular scenario....
                            // VectorHeader.ClipVector(ref _vel, _groundplane);
                        }
                        else // wall clip
                        {
                            VectorHeader.ClipVector(ref _velocity, _plane);
                        }
                    }
                }
                else
                {
                    return;
                }
            }
        }
    public override void Simulate(ActorArgs _args)
    {
        ActorHeader.Actor     Actor      = _args.Actor;
        ActorHeader.GroundHit Ground     = Actor.Ground;
        ActorHeader.GroundHit LastGround = Actor.LastGround;
        Vector3 Velocity = Actor._velocity;
        Vector3 Wish     = _args.ViewWishDir;

        bool Grounded = Actor.SnapEnabled && Ground.stable;

        if (Grounded && !LastGround.stable) // Landing
        {
            VectorHeader.ClipVector(ref Velocity, Ground.normal);
        }

        // Orient Wish Velocity to grounding plane
        if (Grounded && OrientVelocityToGroundPlane)
        {
            VectorHeader.CrossProjection(ref Wish, new Vector3(0, 1, 0), Ground.normal);
        }
        else
        {
            // Clip Wish Velocity along upward plane if we're not orienting/stable as we may be able to fight gravity if not done
            VectorHeader.ClipVector(ref Wish, new Vector3(0, 1, 0));
            Wish.Normalize();
        }

        //if (Grounded) // Subtract max speed based on stability
        //    BehaviourHeader.DetermineWishVelocity(ref Velocity, Wish, MaximumGroundMoveSpeed, GroundAcceleration * GlobalTime.FDT);
        //else
        //    BehaviourHeader.DetermineWishVelocity(ref Velocity, Wish, MaximumAirMoveSpeed, AirAcceleration * GlobalTime.FDT);

        if (Grounded)
        {
            BehaviourHeader.ApplyAcceleration(ref Velocity, Wish, MaximumGroundMoveSpeed, GroundAcceleration);
        }
        else
        {
            BehaviourHeader.ApplyAcceleration(ref Velocity, Wish, MaximumAirMoveSpeed, AirAcceleration);
        }

        Actor.SetVelocity(Velocity);

        return;
    }
    public override void Simulate(ActorArgs _args)
    {
        ActorHeader.Actor     Actor  = _args.Actor;
        ActorHeader.GroundHit Ground = Actor.Ground;

        Vector3 Forward = _args.ActorView.forward;
        Vector3 Wish    = _args.ViewWishDir;

        bool Grounded    = Actor.SnapEnabled && Ground.stable;
        bool DashRequest = (GlobalTime.T - DashRequestSnapshot) > 0.1F &&
                           DashStamina >= DashCost &&
                           (_args.ActionFlags & (1 << 3)) != 0;

        if (DashRequest) // valid dash
        {
            bool UseViewDir = Wish.sqrMagnitude == 0;

            // Completely eradicate all velocity
            Actor.SetVelocity(Vector3.zero);
            DashStamina -= DashCost;

            Vector3 DashDirection = UseViewDir ? Forward : Wish;
            VectorHeader.ClipVector(ref DashDirection, new Vector3(0, 1, 0));
            DashDirection.Normalize();

            DashRequestSnapshot = GlobalTime.T;

            _args.AssignHold(ApplyDashDuration);

            Actor.SetVelocity(DashDirection * DashVelocityDelta);

            DashEvents?.Invoke(_args, DashState.Enter);
        }
        else if (Grounded) // If we aren't actually dashing, let's rejuvenate our stamina if we're grounded.
        {
            DashStamina += DashGrowthRate * GlobalTime.FDT;
            DashStamina  = Mathf.Min(DashStamina, DashCap);
        }
    }
Exemplo n.º 5
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;
        }