Пример #1
0
        /// <summary>
        /// Calculates the velocity of the kart.
        /// </summary>
        void CalculateDrivingVelocity(float deltaTime, GroundInfo groundInfo, Quaternion rotationStream)
        {
            Vector3 localVelocity = Quaternion.Inverse(rotationStream) * Quaternion.Inverse(m_DriftOffset) * m_Velocity;

            if (groundInfo.isGrounded)
            {
                localVelocity.x = Mathf.MoveTowards(localVelocity.x, 0f, m_ModifiedStats.grip * deltaTime);

                float acceleration = m_HasControl ? m_Input.Acceleration : localVelocity.z > 0.05f ? -1f : 0f;

                if (acceleration > -k_Deadzone && acceleration < k_Deadzone)    // No acceleration input.
                {
                    localVelocity.z = Mathf.MoveTowards(localVelocity.z, 0f, m_ModifiedStats.coastingDrag * deltaTime);
                }
                else if (acceleration > k_Deadzone)                            // Positive acceleration input.
                {
                    localVelocity.z = Mathf.MoveTowards(localVelocity.z, m_ModifiedStats.topSpeed, acceleration * m_ModifiedStats.acceleration * deltaTime);
                }
                else if (localVelocity.z > k_Deadzone)                         // Negative acceleration input and going forwards.
                {
                    localVelocity.z = Mathf.MoveTowards(localVelocity.z, 0f, -acceleration * m_ModifiedStats.braking * deltaTime);
                }
                else                                                           // Negative acceleration input and not going forwards.
                {
                    localVelocity.z = Mathf.MoveTowards(localVelocity.z, -m_ModifiedStats.reverseSpeed, -acceleration * m_ModifiedStats.reverseAcceleration * deltaTime);
                }
            }

            if (groundInfo.isCapsuleTouching)
            {
                localVelocity.y = Mathf.Max(0f, localVelocity.y);
            }

            m_Velocity = m_DriftOffset * rotationStream * localVelocity;

            if (!groundInfo.isCapsuleTouching)
            {
                m_Velocity += Vector3.down * m_ModifiedStats.gravity * deltaTime;
            }
        }
        /// <summary>
        /// Starts a drift if the kart lands with a sufficient turn.
        /// </summary>
        void StartDrift(GroundInfo currentGroundInfo, GroundInfo nextGroundInfo, Quaternion rotationStream)
        {
            if (m_HasControl && m_DriftState == DriftState.NotDrifting)
            {
                Vector3 kartForward = rotationStream * Vector3.forward;
                kartForward.y = 0f;
                kartForward.Normalize();
                Vector3 flatVelocity = m_Velocity;
                flatVelocity.y = 0f;
                flatVelocity.Normalize();

                float signedAngle = Vector3.SignedAngle(kartForward, flatVelocity, Vector3.up);

                if (signedAngle > minDriftStartAngle && signedAngle < maxDriftStartAngle)
                {
                    m_DriftOffset = Quaternion.Euler(0f, signedAngle, 0f);
                    m_DriftState  = DriftState.FacingLeft;

                    OnDriftStarted.Invoke();
                }
                else if (signedAngle < -minDriftStartAngle && signedAngle > -maxDriftStartAngle)
                {
                    m_DriftOffset = Quaternion.Euler(0f, signedAngle, 0f);
                    m_DriftState  = DriftState.FacingRight;

                    OnDriftStarted.Invoke();
                }
                else
                {
                    StopDrift(Time.deltaTime);
                }
            }
            else
            {
                StopDrift(Time.deltaTime);
            }
        }
Пример #3
0
        /// <summary>
        /// Affects the rotation stream so that the kart is level with the ground.
        /// </summary>
        void GroundNormal(float deltaTime, ref Quaternion rotationStream, GroundInfo currentGroundInfo, GroundInfo nextGroundInfo)
        {
            Vector3    rigidbodyUp           = m_Rigidbody.rotation * Vector3.up;
            Quaternion currentTargetRotation = Quaternion.FromToRotation(rigidbodyUp, currentGroundInfo.normal);
            Quaternion nextTargetRotation    = Quaternion.FromToRotation(rigidbodyUp, nextGroundInfo.normal);

            if (nextGroundInfo.isCloseToGround)
            {
                rotationStream = Quaternion.RotateTowards(currentTargetRotation, nextTargetRotation, 0.5f) * rotationStream;
            }
            else
            {
                rotationStream = Quaternion.RotateTowards(rotationStream, nextTargetRotation, airborneOrientationSpeed * deltaTime);
            }
        }
Пример #4
0
        /// <summary>
        /// Checks whether or not the kart is grounded given a rotation and offset.
        /// </summary>
        /// <param name="deltaTime">The time between frames.</param>
        /// <param name="rotationStream">The rotation the kart will have.</param>
        /// <param name="offset">The offset from the kart's current position.</param>
        /// <returns>Information about the ground from the offset position.</returns>
        GroundInfo CheckForGround(float deltaTime, Quaternion rotationStream, Vector3 offset)
        {
            GroundInfo groundInfo      = new GroundInfo();
            Vector3    defaultPosition = offset + m_Velocity * deltaTime;
            Vector3    direction       = rotationStream * Vector3.down;

            float capsuleRadius           = m_Capsule.radius;
            float capsuleTouchingDistance = capsuleRadius + Physics.defaultContactOffset;
            float groundedDistance        = capsuleTouchingDistance + k_GroundToCapsuleOffsetDistance;
            float closeToGroundDistance   = Mathf.Max(groundedDistance + capsuleRadius, m_Velocity.y);

            int hitCount = 0;

            Ray ray = new Ray(defaultPosition + frontGroundRaycast.position, direction);

            bool didHitFront = GetNearestFromRaycast(ray, closeToGroundDistance, groundLayers, QueryTriggerInteraction.Ignore, out RaycastHit frontHit);

            if (didHitFront)
            {
                hitCount++;
            }

            ray.origin = defaultPosition + rightGroundRaycast.position;

            bool didHitRight = GetNearestFromRaycast(ray, closeToGroundDistance, groundLayers, QueryTriggerInteraction.Ignore, out RaycastHit rightHit);

            if (didHitRight)
            {
                hitCount++;
            }

            ray.origin = defaultPosition + leftGroundRaycast.position;

            bool didHitLeft = GetNearestFromRaycast(ray, closeToGroundDistance, groundLayers, QueryTriggerInteraction.Ignore, out RaycastHit leftHit);

            if (didHitLeft)
            {
                hitCount++;
            }

            ray.origin = defaultPosition + rearGroundRaycast.position;

            bool didHitRear = GetNearestFromRaycast(ray, closeToGroundDistance, groundLayers, QueryTriggerInteraction.Ignore, out RaycastHit rearHit);

            if (didHitRear)
            {
                hitCount++;
            }

            groundInfo.isCapsuleTouching = frontHit.distance <= capsuleTouchingDistance || rightHit.distance <= capsuleTouchingDistance || leftHit.distance <= capsuleTouchingDistance || rearHit.distance <= capsuleTouchingDistance;
            groundInfo.isGrounded        = frontHit.distance <= groundedDistance || rightHit.distance <= groundedDistance || leftHit.distance <= groundedDistance || rearHit.distance <= groundedDistance;
            groundInfo.isCloseToGround   = hitCount > 0;

            // No hits - normal = Vector3.up
            if (hitCount == 0)
            {
                groundInfo.normal = Vector3.up;
            }

            // 1 hit - normal = hit.normal
            else if (hitCount == 1)
            {
                if (didHitFront)
                {
                    groundInfo.normal = frontHit.normal;
                }
                else if (didHitRight)
                {
                    groundInfo.normal = rightHit.normal;
                }
                else if (didHitLeft)
                {
                    groundInfo.normal = leftHit.normal;
                }
                else if (didHitRear)
                {
                    groundInfo.normal = rearHit.normal;
                }
            }

            // 2 hits - normal = hits average
            else if (hitCount == 2)
            {
                groundInfo.normal = (frontHit.normal + rightHit.normal + leftHit.normal + rearHit.normal) * 0.5f;
            }

            // 3 hits - normal = normal of plane from 3 points
            else if (hitCount == 3)
            {
                if (!didHitFront)
                {
                    groundInfo.normal = Vector3.Cross(rearHit.point - rightHit.point, leftHit.point - rightHit.point);
                }

                if (!didHitRight)
                {
                    groundInfo.normal = Vector3.Cross(rearHit.point - frontHit.point, leftHit.point - frontHit.point);
                }

                if (!didHitLeft)
                {
                    groundInfo.normal = Vector3.Cross(rightHit.point - frontHit.point, rearHit.point - frontHit.point);
                }

                if (!didHitRear)
                {
                    groundInfo.normal = Vector3.Cross(leftHit.point - rightHit.point, frontHit.point - rightHit.point);
                }
            }

            // 4 hits - normal = average of normals from 4 planes
            else
            {
                Vector3 normal0 = Vector3.Cross(rearHit.point - rightHit.point, leftHit.point - rightHit.point);
                Vector3 normal1 = Vector3.Cross(rearHit.point - frontHit.point, leftHit.point - frontHit.point);
                Vector3 normal2 = Vector3.Cross(rightHit.point - frontHit.point, rearHit.point - frontHit.point);
                Vector3 normal3 = Vector3.Cross(leftHit.point - rightHit.point, frontHit.point - rightHit.point);

                groundInfo.normal = (normal0 + normal1 + normal2 + normal3) * 0.25f;
            }

            if (groundInfo.isGrounded)
            {
                float dot = Vector3.Dot(groundInfo.normal, m_Velocity.normalized);
                if (dot > k_VelocityNormalAirborneDot)
                {
                    groundInfo.isGrounded = false;
                }
            }

            return(groundInfo);
        }
Пример #5
0
        void FixedUpdate()
        {
            if (Mathf.Approximately(Time.timeScale, 0f))
            {
                return;
            }

            if (m_RepositionPositionDelta.sqrMagnitude > float.Epsilon || m_RepositionRotationDelta != Quaternion.identity)
            {
                m_Rigidbody.MovePosition(m_Rigidbody.position + m_RepositionPositionDelta);
                m_Rigidbody.MoveRotation(m_RepositionRotationDelta * m_Rigidbody.rotation);
                m_RepositionPositionDelta = Vector3.zero;
                m_RepositionRotationDelta = Quaternion.identity;
                return;
            }

            m_RigidbodyPosition = m_Rigidbody.position;

            KartStats.GetModifiedStats(m_CurrentModifiers, defaultStats, ref m_ModifiedStats);
            ClearTempModifiers();

            Quaternion rotationStream = m_Rigidbody.rotation;

            float deltaTime = Time.deltaTime;

            m_CurrentGroundInfo = CheckForGround(deltaTime, rotationStream, Vector3.zero);

            Hop(rotationStream, m_CurrentGroundInfo);

            if (m_CurrentGroundInfo.isGrounded && !m_IsGrounded)
            {
                OnBecomeGrounded.Invoke();
            }

            if (!m_CurrentGroundInfo.isGrounded && m_IsGrounded)
            {
                OnBecomeAirborne.Invoke();
            }

            m_IsGrounded = m_CurrentGroundInfo.isGrounded;

            ApplyAirborneModifier(m_CurrentGroundInfo);

            GroundInfo nextGroundInfo = CheckForGround(deltaTime, rotationStream, m_Velocity * deltaTime);

            GroundNormal(deltaTime, ref rotationStream, m_CurrentGroundInfo, nextGroundInfo);
            TurnKart(deltaTime, ref rotationStream);

            StartDrift(m_CurrentGroundInfo, nextGroundInfo, rotationStream);
            StopDrift(deltaTime);

            CalculateDrivingVelocity(deltaTime, m_CurrentGroundInfo, rotationStream);

            Vector3 penetrationOffset = SolvePenetration(rotationStream);

            penetrationOffset = ProcessVelocityCollisions(deltaTime, rotationStream, penetrationOffset);

            rotationStream = Quaternion.RotateTowards(m_Rigidbody.rotation, rotationStream, rotationCorrectionSpeed * deltaTime);

            AdjustVelocityByPenetrationOffset(deltaTime, ref penetrationOffset);

            m_Rigidbody.MoveRotation(rotationStream);
            m_Rigidbody.MovePosition(m_RigidbodyPosition + m_Movement);
        }
Пример #6
0
        void FixedUpdate()
        {
            if (Mathf.Approximately(Time.timeScale, 0f))
            {
                return;
            }

            if (m_RepositionPositionDelta.sqrMagnitude > float.Epsilon || m_RepositionRotationDelta != Quaternion.identity)
            {
                m_Rigidbody.MovePosition(m_Rigidbody.position + m_RepositionPositionDelta);
                m_Rigidbody.MoveRotation(m_RepositionRotationDelta * m_Rigidbody.rotation);
                m_RepositionPositionDelta = Vector3.zero;
                m_RepositionRotationDelta = Quaternion.identity;
                return;
            }

            m_RigidbodyPosition = m_Rigidbody.position;

            KartStats.GetModifiedStats(m_CurrentModifiers, defaultStats, ref m_ModifiedStats);
            ClearTempModifiers();

            Quaternion rotationStream = m_Rigidbody.rotation;

            float deltaTime = Time.deltaTime;

            //Para MRU
            if (m_Racer.GetLapTime() > 1 && m_ModifiedStats.acceleration == 5)
            {
                m_ModifiedStats.acceleration = 0f;
                //Debug.Log(deltaTime);
            }
            ;
            // Para MRUV
            if (m_Racer.GetLapTime() > 0f && m_Racer.GetLapTime() < 0.5f && m_ModifiedStats.acceleration == 1)
            {
                if (ace)
                {
                    acelerar_mruv += 1.5f;
                    ace            = false;
                }
                m_ModifiedStats.acceleration = acelerar_mruv;
                //Debug.Log(deltaTime);
            }
            ;
            if (m_Racer.GetLapTime() > 0.5f)
            {
                ace = true;
            }

            m_CurrentGroundInfo = CheckForGround(deltaTime, rotationStream, Vector3.zero);

            Hop(rotationStream, m_CurrentGroundInfo);

            if (m_CurrentGroundInfo.isGrounded && !m_IsGrounded)
            {
                OnBecomeGrounded.Invoke();
            }

            if (!m_CurrentGroundInfo.isGrounded && m_IsGrounded)
            {
                OnBecomeAirborne.Invoke();
            }

            m_IsGrounded = m_CurrentGroundInfo.isGrounded;

            ApplyAirborneModifier(m_CurrentGroundInfo);

            GroundInfo nextGroundInfo = CheckForGround(deltaTime, rotationStream, m_Velocity * deltaTime);

            GroundNormal(deltaTime, ref rotationStream, m_CurrentGroundInfo, nextGroundInfo);
            TurnKart(deltaTime, ref rotationStream);

            StartDrift(m_CurrentGroundInfo, nextGroundInfo, rotationStream);
            StopDrift(deltaTime);

            CalculateDrivingVelocity(deltaTime, m_CurrentGroundInfo, rotationStream);

            Vector3 penetrationOffset = SolvePenetration(rotationStream);

            penetrationOffset = ProcessVelocityCollisions(deltaTime, rotationStream, penetrationOffset);

            rotationStream = Quaternion.RotateTowards(m_Rigidbody.rotation, rotationStream, rotationCorrectionSpeed * deltaTime);

            AdjustVelocityByPenetrationOffset(deltaTime, ref penetrationOffset);

            m_Rigidbody.MoveRotation(rotationStream);
            m_Rigidbody.MovePosition(m_RigidbodyPosition + m_Movement);

            //rb.GetPointVelocity(transform.TransformPoint(localWheelPos));
            //Debug.Log(LocalSpeed);
        }