Exemplo n.º 1
0
    private void FixedUpdate()
    {
        //Rotate
        transform.Rotate(Input.GetAxis("Mouse X") * Vector3.up * rotateSpeed.x);
        cam.transform.Rotate(Input.GetAxis("Mouse Y") * Vector3.left * rotateSpeed.y);

        //Normalize input
        Vector3 inXZ = new Vector3(input.x, 0, input.z) * Time.deltaTime * charSpeed;

        //Gravity
        acceleration += input.y;
        acceleration  = (acceleration - gravity * Time.deltaTime);
        velocity.y    = acceleration;
        if (!isGrounded)
        {
            //Add input without modification
            velocity += transform.forward * inXZ.x;
            velocity += Vector3.Cross(transform.forward, Vector3.up) * inXZ.z;
            //Calculate in air momentum
            Momentum  = Momentum.normalized * (Momentum.magnitude - airFriction * Time.deltaTime);
            velocity += Momentum;
        }
        else
        {
            //Add input mapped to the surface of platform
            inXZ = transform.forward * inXZ.x + Vector3.Cross(transform.forward, Vector3.up) * inXZ.z;
            Vector3 perpPlaneDir = Vector3.Cross(lasthit.normal, inXZ);
            Vector3 planeDir     = Vector3.Cross(perpPlaneDir, lasthit.normal);
            planeDir  = planeDir * Mathf.Sign(Vector3.Dot(planeDir, inXZ));
            velocity += planeDir.normalized * inXZ.magnitude;
        }

        //Clamp Velocity
        velocity = velocity * Mathf.Clamp(velocity.magnitude, -maxVelocity, maxVelocity);

        //pushout if in object at start
        Pushout();

        isGrounded = false;

        //Collisions variables
        RaycastHit hit;
        int        maxLoops = 0;
        Vector3    loopStartVec;
        //Top and bottom sphere position of player capsule
        Vector3 TopSphere = transform.position + new Vector3(0, capsule.height / 2 - capsule.radius, 0) + capsule.center;
        Vector3 BotSphere = transform.position - new Vector3(0, capsule.height / 2 - capsule.radius, 0) + capsule.center;

        /*Main Collision Detection*/
        while (Physics.CapsuleCast(
                   TopSphere, BotSphere, capsule.radius,
                   velocity.normalized,           //Direction vector
                   out hit,
                   Mathf.Abs(velocity.magnitude), //Direction Length
                   raycastLayerMask))
        {
            maxLoops++;
            loopStartVec = velocity;
            Vector3 XZ = new Vector3(velocity.x, 0, velocity.z);
            if ((-hit.normal.y + 1) * 90 < maxSlope)//hit normal is 1 for flat and 0 for wall so invert that then times it by 90 to get the proper degree then compare it
            {
                /*Traversable slope*/
                //currently will step over anything less than 1/4th the radius of capsule
                Vector3 perpPlaneDir = Vector3.Cross(hit.normal, XZ);            //this is a vector that will be parrallel to the slope but it will be perpindicular to the direction we want to go
                Vector3 planeDir     = Vector3.Cross(perpPlaneDir, hit.normal);  //This will be the an axis line of were we are walking, but we dont know if its forwards or backwards right now
                planeDir     = planeDir * Mathf.Sign(Vector3.Dot(planeDir, XZ)); //dot returns pos if they are headed in the same direction. so multiplying the planedir by its sign will give us the correct direction on the vector
                velocity     = velocity.normalized * (hit.distance);             //this will set velocity to go the un obstructed amount of the cast
                XZ          -= new Vector3(velocity.x, 0, velocity.z);           //this makes xv the remainder xv distance
                velocity    += planeDir.normalized * XZ.magnitude;
                velocity.y  += Mathf.Sign(hit.normal.y) * .001f;                 //sets the final position slightly offset from the ground so we dont clip through next frame
                acceleration = 0;
                isGrounded   = true;
                lasthit      = hit;
            }
            else
            {
                /*Walls and Ceilings*/
                //get the vectors of the plane we hit
                Vector3 parallelSide = Vector3.Cross(Vector3.up, hit.normal);
                Vector3 parallelDown = Vector3.Cross(parallelSide, hit.normal);
                //Correct the direction of the xz vector on our plane
                parallelSide = parallelSide * Mathf.Sign(Vector3.Dot(parallelSide, XZ));
                float angle             = Vector3.Angle(-new Vector3(velocity.x, 0, velocity.z).normalized, hit.normal);//get our angle between our direction and the colliders normal
                float VerticalRemainder = velocity.y;
                float XZPlaneRemainder  = XZ.magnitude;
                velocity           = velocity.normalized * (hit.distance);             //set our vector to the hit
                VerticalRemainder -= velocity.y;                                       //Get the acurate remainder of y from our origional y
                XZPlaneRemainder  -= new Vector3(velocity.x, 0, velocity.z).magnitude; //Get our xz remainder from initial xz vector
                if (velocity.y <= 0)
                {
                    //Slopes slide
                    velocity += parallelDown.normalized * Mathf.Abs(VerticalRemainder);
                }
                else if ((-hit.normal.y + 1) * 90 > 90)
                {
                    //ceilings stop our acceleration
                    acceleration = 0;
                }
                else
                {
                    velocity.y += VerticalRemainder;
                }
                velocity += parallelSide.normalized * (XZPlaneRemainder * (angle / 90)); //get our xzremainder and add it reduced by the angle we hit the collider at
                velocity += hit.normal * .001f;                                          //offset our velocity a tad so it doesnt jitter or clip through next frame
            }


            /*Loop Breaks*/
            //if we loop too much just exit and set velocity to just before collision and exit
            if (maxLoops == maximumPhysicsLoops)
            {
                Debug.Log("max loops");
                velocity = velocity.normalized * (hit.distance) + hit.normal * .001f;
                break;
            }
            //if last position velocity was the same as the new calculation set velocity to just before collision and exit
            if (loopStartVec == velocity)
            {
                Debug.Log("Same vector");
                velocity = velocity.normalized * (hit.distance) + hit.normal * .001f;
                break;
            }
        }

        /*Fall Back Fill Check*/
        if (Physics.CheckCapsule(TopSphere + velocity, BotSphere + velocity, capsule.radius, raycastLayerMask))
        {
            Debug.Log("End Capsule Fail");
            //Ditch Velocity
            acceleration = 0;
            velocity     = Vector3.zero;
        }

        if (isGrounded)
        {
            Momentum = Vector3.zero;
            mover.SetCollisionInfo(lasthit);
            mover.IsMoveObject(lasthit.collider);
        }
        else
        {
            mover.Unhook();
        }

        //Apply velocity and clear containers
        transform.position += velocity;

        //clear input
        input    = Vector3.zero;
        velocity = Vector3.zero;
    }