コード例 #1
0
    // Update is called once per frame
    //FixedUpdate is called for every physics calculation
    void FixedUpdate()
    {
        GetInputFromInputManager();

        //The rest of this method controls the car
        WCFL.motorTorque = v;
        WCFR.motorTorque = v;

        UnityEngine.Profiling.Profiler.BeginSample("RimSpin");
        if (_rimSpin)
        {
            if (Mathf.Abs(WCFL.rpm) > 300)
            {
                _fLRimSpinRenderer.enabled = true;
                _fLRimRenderer.enabled     = false;
            }
            else
            {
                _fLRimRenderer.enabled     = true;
                _fLRimSpinRenderer.enabled = false;
            }
            if (Mathf.Abs(WCRL.rpm) > 300)
            {
                _rLRimSpinRenderer.enabled = true;
                _rLRimRenderer.enabled     = false;
            }
            else
            {
                _rLRimRenderer.enabled     = true;
                _rLRimSpinRenderer.enabled = false;
            }
            if (Mathf.Abs(WCFR.rpm) > 300)
            {
                _fRRimRenderer.enabled     = false;
                _fRRimSpinRenderer.enabled = true;
            }
            else
            {
                _fRRimRenderer.enabled     = true;
                _fRRimSpinRenderer.enabled = false;
            }
            if (Mathf.Abs(WCRR.rpm) > 300)
            {
                _rRRimRenderer.enabled     = false;
                _rRRimSpinRenderer.enabled = true;
            }
            else
            {
                _rRRimRenderer.enabled     = true;
                _rRRimSpinRenderer.enabled = false;
            }
        }
        UnityEngine.Profiling.Profiler.EndSample();



        //Adapt the tyre slip according to the road type

        if (Gps != null)
        {
            RoadMat = Gps.RoadMat;
            if (TestRoadMat != null)
            {
                RoadMat = TestRoadMat;
            }
            switch (RoadMat)
            {
            case "Tarmac":
                frontFrict          = frontFrictTarmac;
                rearFrict           = rearFrictTarmac;
                GravelSimulation    = false;
                WashboardSimulation = false;
                break;

            case "Washboard":
                frontFrict          = frontFrictTarmac;
                rearFrict           = rearFrictTarmac;
                GravelSimulation    = false;
                WashboardSimulation = true;
                break;

            case "DirtyRoad":
                frontFrict          = frontFrictDirtyRoad;
                rearFrict           = rearFrictDirtyRoad;
                GravelSimulation    = false;
                WashboardSimulation = false;
                break;

            default:
                frontFrict          = frontFrictDirt;
                rearFrict           = rearFrictDirt;
                GravelSimulation    = true;
                WashboardSimulation = false;
                break;
            }


            //For pendulum turns - if the angular velocity is big, reduce the rear side slip coeff:
            //PendulumSlipCoeff should be between 1 and 0.7
            //Vector3 _desiredVector = Road.Instance.XSecs[Gps.SegIdx + 20].MidPt - Road.Instance.XSecs[Gps.SegIdx + 10].MidPt;
            float PendulumForceCoeff;
            float TotSlip = 0;
            float Divisor = 0;
            if (WCFL.isGrounded)
            {
                float s = Mathf.Abs(WCRL.sideFriction.slip);
                LSlips.Enqueue(s);
                LSlipsum += s;
                if (LSlips.Count > 50)
                {
                    LSlipsum -= LSlips.Dequeue();
                    Divisor   = 50;
                }
                TotSlip = LSlipsum;
            }
            if (WCFR.isGrounded)
            {
                float rs = Mathf.Abs(WCRR.sideFriction.slip);
                RSlips.Enqueue(rs);
                RSlipsum += rs;
                if (RSlips.Count > 50)
                {
                    RSlipsum -= RSlips.Dequeue();
                    Divisor  += 50;
                }
                TotSlip += RSlipsum;
            }
            float MovingAvgSlip;
            if (Divisor == 0)
            {
                MovingAvgSlip = 0.7f;
            }
            else
            {
                MovingAvgSlip = TotSlip / Divisor;
            }
            //MovingAvgSlip stays around 0.01-0.02 and goes up to 0.2 when it breaks away. For a severe skid goes up to 0.7
            //Each Fixedframe it's changing by 0.002 to 0.009
            //So we can force it to increase fast and drop back slowly
            SlipQueue.Enqueue(MovingAvgSlip);
            if (SlipQueue.Count > 50)
            {
                DelayedSlip = SlipQueue.Dequeue();
            }
            else
            {
                DelayedSlip = MovingAvgSlip;
            }
            if (DelayedSlip < MovingAvgSlip)
            {
                DelayedSlip = MovingAvgSlip;
            }


            if (Mathf.Abs(h - _prevh) > 10)
            {
                SlipDelayTimer = 0;
            }
            if (SlipDelayTimer < 50)
            {
                DelayedSlip = 0.5f;
                SlipDelayTimer++;
            }
            _prevh = h;

            PendulumForceCoeff = Mathf.Clamp(1 - DelayedSlip * SlipEffect, 0.4f, 1f);
            WCRL.sideFriction.forceCoefficient = _rearslipCoeff * PendulumForceCoeff;  //normally forceCoeff = 5; Bigger = more turning force
            WCRR.sideFriction.forceCoefficient = _rearslipCoeff * PendulumForceCoeff;

            //Easy cornering - The GPS can manage the reverse steering
            float BendAnglePerSec = 0;
            if (Gps.CurrBend != null)
            {
                BendAnglePerSec = Gps.CurrBend.RacelineAnglePerSeg * Gps.SegsPerSec;
                float CorrectionAnglePerSec = (BendAnglePerSec - _rb.angularVelocity.y * 57.3f);
                if (Mathf.Sign(CorrectionAnglePerSec) != Mathf.Sign(BendAnglePerSec))     //only apply the correction if oversteering
                {
                    h += CorrectionAnglePerSec;
                }
                h = Mathf.Clamp(h, -40, 40);
            }
            //Feather the throttle if were understeering
            if (WCFL.sideFriction.slip > frontFrict.keys[1].time || WCFR.sideFriction.slip > frontFrict.keys[1].time)
            {
                WCFL.motorTorque *= 0.7f; WCFL.motorTorque *= 0.7f;
            }
            //txtTrace.text = "FSlip=" + WCFL.SlipVectorMagnitude;
            //txtTrace.color = (WCFL.SlipVectorMagnitude > frontFrict.keys[1].time)? Color.red: Color.yellow;
            //txtTrace2.text = "RSlip" + WCRL.SlipVectorMagnitude;
            //txtTrace2.color = (WCRL.SlipVectorMagnitude > rearFrict.keys[1].time) ? Color.red : Color.yellow;
        }
        else
        {
            frontFrict          = frontFrictDirt;
            rearFrict           = rearFrictDirt;
            RoadMat             = "Dirt";
            GravelSimulation    = true;
            WashboardSimulation = false;
        }

        //Comment out for testing

        WCFL.forwardFriction.frictionCurve = frontFrict;
        WCFR.forwardFriction.frictionCurve = frontFrict;
        WCRL.forwardFriction.frictionCurve = rearFrict;
        WCRR.forwardFriction.frictionCurve = rearFrict;
        WCFL.GravelSimulation    = GravelSimulation;
        WCFR.GravelSimulation    = GravelSimulation;
        WCRL.GravelSimulation    = GravelSimulation;
        WCRR.GravelSimulation    = GravelSimulation;
        WCFL.WashboardSimulation = WashboardSimulation;
        WCFR.WashboardSimulation = WashboardSimulation;
        WCRL.WashboardSimulation = WashboardSimulation;
        WCRR.WashboardSimulation = WashboardSimulation;

        WCFL.steerAngle = h;
        WCFR.steerAngle = h;

        //Limit max speed in reverse
        if (WCFL.rpm < -300)
        {
            WCFL.motorTorque = Mathf.Clamp(WCFL.motorTorque, 0, 10000);
            WCFR.motorTorque = Mathf.Clamp(WCFR.motorTorque, 0, 10000);
        }


        float travelL;
        float travelR;
        float AntiRoll = AntiRollForce * GetComponent <Rigidbody>().velocity.magnitude;

        bool  groundedFL     = WCFL.GetGroundHit(out hitFL);
        float ForwardSlipFL  = hitFL.forwardSlip;
        float SidewaysSlipFL = hitFL.sidewaysSlip;

        if (groundedFL)
        {
            travelL = (-WCFL.transform.InverseTransformPoint(hitFL.point).y - WCFL.radius) / WCFL.springLength;
            //if (hitFL.force > 150000 && FLRim != null)
            //{
            //    GameObject.Destroy(FLRim);
            //}
        }
        else
        {
            travelL = 1.0f;
        }
        float SkidL = Mathf.Abs(SidewaysSlipFL) + Mathf.Abs(ForwardSlipFL);

        if (SkidL > SkidThresh && RoadMat == "Tarmac")
        {
            IsSkiddingFL = true;
        }
        else
        {
            IsSkiddingFL = false; SkidAudioSource.Stop();
        }
        bool  groundedFR     = WCFR.GetGroundHit(out hitFR);
        float ForwardSlipFR  = hitFR.forwardSlip;
        float SidewaysSlipFR = hitFR.sidewaysSlip;

        if (groundedFR)
        {
            travelR = (-WCFR.transform.InverseTransformPoint(hitFR.point).y - WCFR.radius) / WCFR.springLength;
        }
        else
        {
            travelR = 1.0f;
        }
        float SkidR = Mathf.Abs(SidewaysSlipFR) + Mathf.Abs(ForwardSlipFR);

        if (SkidR > SkidThresh && RoadMat == "Tarmac")
        {
            IsSkiddingFR = true;
        }
        else
        {
            IsSkiddingFR = false;
        }

        //ContactAngle = Vector3.Angle (Vector3.up,WCFR.transform.InverseTransformPoint(hit.point))*2*Mathf.PI/360;
        //Fric.stiffness= Mathf.Sin (ContactAngle);
        var antiRollForce = (travelL - travelR) * AntiRoll;

        if (groundedFL)
        {
            GetComponent <Rigidbody>().AddForceAtPosition(WCFL.transform.up * antiRollForce, WCFR.transform.position);
            GetComponent <Rigidbody>().AddForceAtPosition(WCFL.transform.up * -antiRollForce, WCFL.transform.position);
        }
        if (groundedFR)
        {
            GetComponent <Rigidbody>().AddForceAtPosition(WCFR.transform.up * -antiRollForce, WCFL.transform.position);
            GetComponent <Rigidbody>().AddForceAtPosition(WCFR.transform.up * antiRollForce, WCFR.transform.position);
        }

        //BACK WHEEL ANTI-ROLL BAR
        //took this out dont know what it was for?
        //AntiRoll = 50f * GetComponent<Rigidbody>().velocity.magnitude;
        bool  groundedRL     = WCRL.GetGroundHit(out hitRL);
        float ForwardSlipRL  = hitRL.forwardSlip;
        float SidewaysSlipRL = hitRL.sidewaysSlip;

        if (groundedRL)
        {
            travelL = (-WCRL.transform.InverseTransformPoint(hitRL.point).y - WCRL.radius) / WCRL.springLength;
        }
        else
        {
            travelL = 1.0f;
        }
        bool  groundedRR     = WCRR.GetGroundHit(out hitRR);
        float ForwardSlipRR  = hitRR.forwardSlip;
        float SidewaysSlipRR = hitRR.sidewaysSlip;

        if (groundedRR)
        {
            travelR = (-WCRR.transform.InverseTransformPoint(hitRR.point).y - WCRR.radius) / WCRR.springLength;
        }
        else
        {
            travelR = 1.0f;
        }
        antiRollForce = (travelL - travelR) * AntiRoll;
        if (groundedRL)
        {
            GetComponent <Rigidbody>().AddForceAtPosition(WCRL.transform.up * antiRollForce, WCRR.transform.position);
            GetComponent <Rigidbody>().AddForceAtPosition(WCRL.transform.up * -antiRollForce, WCRL.transform.position);
        }
        if (groundedRR)
        {
            GetComponent <Rigidbody>().AddForceAtPosition(WCRR.transform.up * -antiRollForce, WCRL.transform.position);
            GetComponent <Rigidbody>().AddForceAtPosition(WCRR.transform.up * antiRollForce, WCRR.transform.position);
        }
        #region Spray and Smoke Particles Region
        //Spray dirt
        try
        {
            if (RoadMat == "Dirt")
            {
                //+ve ForwardSlip means spraying backwards
                //+ve SteerAngle = Right
                psSprayL.transform.localRotation = Quaternion.Euler(45, WCFL.steerAngle + (ForwardSlipFL >= 0 ? 0 : 180), 0);
                if (groundedFL && ((ForwardSlipFL < 0 && h < -0.01f) || (ForwardSlipFL > 0 && h > 0.01f)) && Mathf.Abs(WCFL.rpm) > 0)
                {
                    psSprayL.Play();
                    pmSprayL.startSpeed = -Mathf.Clamp((Mathf.Abs(ForwardSlipFL) + Mathf.Abs(SidewaysSlipFL)) * 14, 0, 7);
                    // THis was for the dust - peSprayFL.startSpeed = -Mathf.Abs(ForwardSlipFL) / 2;
                    peSprayL.rateOverTime = (Mathf.Abs(ForwardSlipFL) + Mathf.Abs(SidewaysSlipFL)) * 100;
                }
                else
                {
                    psSprayL.Stop();
                    pmSprayL.startSpeed = 0;
                }

                psSprayR.transform.localRotation = Quaternion.Euler(45, WCFR.steerAngle + (ForwardSlipFR >= 0 ? 0 : 180), 0);
                if (groundedFR && ((ForwardSlipFR < 0 && h > 0.01f) || (ForwardSlipFR > 0 && h < -0.01f)) && Mathf.Abs(WCFR.rpm) > 0)
                {
                    psSprayR.Play();
                    pmSprayR.startSpeed   = -Mathf.Clamp((Mathf.Abs(ForwardSlipFR) + Mathf.Abs(SidewaysSlipFR)) * 14, 0, 7);
                    peSprayR.rateOverTime = (Mathf.Abs(ForwardSlipFR) + Mathf.Abs(SidewaysSlipFR)) * 100;
                }
                else
                {
                    psSprayR.Stop();
                    pmSprayR.startSpeed = 0;
                }
            }
            else
            {
                psSprayR.Stop(); psSprayL.Stop(); psSprayR.startSpeed = 0; psSprayL.startSpeed = 0;
            }
        }
        catch (Exception e) { Debug.Log(e.ToString()); }

        //Spray dust on DirtyRoad
        try
        {
            psDustL.Stop();
            psDustR.Stop();

            if (RoadMat == "DirtyRoad")
            {
                psDustL.Play();
                psDustR.Play();
                float SlipFL = Mathf.Clamp(WCFL.SlipVectorMagnitude, 0, 0.1f);
                float SlipFR = Mathf.Clamp(WCFR.SlipVectorMagnitude, 0, 0.1f);
                peDustL.rateOverTime            = SlipFL * 500f;
                peDustR.rateOverTime            = SlipFR * 500f;
                psDustL.transform.localPosition = new Vector3(0, -0.4f, -WCFL.forwardFriction.slip / 6);
                psDustR.transform.localPosition = new Vector3(0, -0.4f, -WCFR.forwardFriction.slip / 6);
            }
            else
            {
                psDustL.Stop();
                psDustR.Stop();
            }
        }
        catch { }
        #endregion

        #region Wheel ruts and Skid marks
        //Make Wheel ruts
        try
        {
            if ((RoadMat == "DirtyRoad" && groundedFL && (Math.Abs(ForwardSlipFL) > 1 || Math.Abs(SidewaysSlipFL) > 1 || hitFL.force > 3000)) ||
                (RoadMat == "Dirt" && groundedFL && (Math.Abs(ForwardSlipFL) > 0.8f || Math.Abs(SidewaysSlipFL) > 0.5f || hitFL.force > 3000)))
            {
                IsRuttingFL = true;
            }
            else
            {
                IsRuttingFL = false;
            }

            if (IsRuttingFL)
            {
                if (!WasRuttingFL)
                {
                    //create a new rut
                    if (RutLeft != null)
                    {
                        Destroy(RutLeft);
                    }
                    if (RutLeftNodeCount < 20)
                    {
                        GameObject.Destroy(goRutLeft); Road.Instance.RutCount--;
                    }
                    goRutLeft          = new GameObject("RutLeft");
                    goRutLeft.isStatic = true;
                    goRutLeft.tag      = "Rut";
                    Road.Instance.RutCount++;
                    RutLeft = goRutLeft.AddComponent <FlatLineRenderer>();
                    RutLeft.Init();
                    RutLeft.SetMaterial(RutMatrl);
                    RutLeft.Width    = 0.233f;
                    RutLeftNodeCount = 0;
                }
                if (RutLeft != null)
                {
                    RutLeftNodeCount++;
                    RutLeft.AddNode(hitFL.point + Vector3.up * 0.05f);
                }
            }
            WasRuttingFL = IsRuttingFL;

            if ((RoadMat == "DirtyRoad" && groundedFR && (Math.Abs(ForwardSlipFR) > 1 || Math.Abs(SidewaysSlipFR) > 1 || hitFR.force > 3000)) ||
                (RoadMat == "Dirt" && groundedFR && (Math.Abs(ForwardSlipFR) > 0.6f || Math.Abs(SidewaysSlipFR) > 0.6f || hitFR.force > 3000)))
            {
                IsRuttingFR = true;
            }
            else
            {
                IsRuttingFR = false;
            }
            if (IsRuttingFR)
            {
                if (!WasRuttingFR)
                {
                    //create a new rut
                    if (RutRightNodeCount < 20)
                    {
                        GameObject.Destroy(goRutRight); Road.Instance.RutCount--;
                    }
                    goRutRight          = new GameObject("RutRight");
                    goRutRight.isStatic = true;
                    goRutRight.tag      = "Rut";
                    Road.Instance.RutCount++;
                    RutRight = goRutRight.AddComponent <FlatLineRenderer>();
                    RutRight.Init();
                    RutRight.SetMaterial(RutMatrl);
                    RutRight.Width    = 0.233f;
                    RutRightNodeCount = 0;
                }
                if (RutRight != null)
                {
                    RutRightNodeCount++;
                    RutRight.AddNode(hitFR.point + Vector3.up * 0.05f);
                }
            }
            WasRuttingFR = IsRuttingFR;
        }
        catch (Exception e)
        {
            Debug.Log(e.ToString());
        }

        //Skid Sounds
        if (IsSkiddingFL || IsSkiddingFR)
        {
            if (!SkidAudioSource.isPlaying)
            {
                SkidAudioSource.Play();
            }
        }
        else
        {
            SkidAudioSource.Stop();
        }

        //Skidmarks

        if (IsSkiddingFL)
        {
            if (!WasSkiddingFL)
            {
                //create a new rut
                if (SkidMkLeft != null)
                {
                    SkidMkLeft.enabled = false; Destroy(SkidMkLeft);
                }
                if (SkidMkLeftNodeCount < 50)
                {
                    GameObject.Destroy(goSkidMkLeft); Road.Instance.RutCount--;
                }
                goSkidMkLeft          = new GameObject("SkidMkLeft");
                goSkidMkLeft.isStatic = true;
                goSkidMkLeft.tag      = "Rut";
                Road.Instance.RutCount++;
                SkidMkLeft = goSkidMkLeft.AddComponent <FlatLineRenderer>();
                SkidMkLeft.Init();
                SkidMkLeft.SetMaterial(SkidMatrl);
                SkidMkLeft.Width    = 0.15f;
                SkidMkLeftNodeCount = 0;
            }
            SkidMkLeftNodeCount++;
            SkidMkLeft.AddNode(hitFL.point + Vector3.up * 0.05f);
        }
        WasSkiddingFL = IsSkiddingFL;
        if (IsSkiddingFR)
        {
            if (!WasSkiddingFR)
            {
                //create a new rut
                if (SkidMkRight != null)
                {
                    Destroy(SkidMkRight);
                }
                if (SkidMkRightNodeCount < 50)
                {
                    GameObject.DestroyImmediate(goSkidMkRight); Road.Instance.RutCount--;
                }
                goSkidMkRight          = new GameObject("SkidMkRight");
                goSkidMkRight.isStatic = true;
                goSkidMkRight.tag      = "Rut";
                Road.Instance.RutCount++;
                SkidMkRight = goSkidMkRight.AddComponent <FlatLineRenderer>();
                SkidMkRight.Init();
                SkidMkRight.SetMaterial(SkidMatrl);
                SkidMkRight.Width    = 0.15f;
                SkidMkRightNodeCount = 0;
            }
            SkidMkRightNodeCount++;
            SkidMkRight.AddNode(hitFR.point + Vector3.up * 0.05f);
        }
        WasSkiddingFR = IsSkiddingFR;
        if (EndSkidmarks)
        {
            WasSkiddingFL = false; WasSkiddingFR = false; WasRuttingFL = false; WasRuttingFR = false; EndSkidmarks = false;
        }

        #endregion

        WCFL.brakeTorque = BrakeForce;
        WCFR.brakeTorque = BrakeForce;
        WCRL.brakeTorque = BrakeForce;
        WCRR.brakeTorque = BrakeForce;
    }
コード例 #2
0
    // Update is called once per frame
    //FixedUpdate is called for every physics calculation
    void FixedUpdate()
    {
        GetInputFromInputManager();

        //The rest of this method controls the car

        WCFL.brakeTorque = BrakeForce;
        WCFR.brakeTorque = BrakeForce;
        WCRL.brakeTorque = BrakeForce;
        WCRR.brakeTorque = BrakeForce;

        WCRL.motorTorque = v;
        WCRR.motorTorque = v;

        if (WCRL.rpm < -300)
        {
            WCRL.motorTorque = Mathf.Clamp(WCRL.motorTorque, 0, 10000);
            WCRR.motorTorque = Mathf.Clamp(WCRR.motorTorque, 0, 10000);
        }

        if (_rimSpin)
        {
            if (Mathf.Abs(WCFL.rpm) > 300)
            {
                _fLRimSpinRenderer.enabled = true;
                _fLRimRenderer.enabled     = false;
            }
            else
            {
                _fLRimRenderer.enabled     = true;
                _fLRimSpinRenderer.enabled = false;
            }
            if (Mathf.Abs(WCRL.rpm) > 300)
            {
                _rLRimSpinRenderer.enabled = true;
                _rLRimRenderer.enabled     = false;
            }
            else
            {
                _rLRimRenderer.enabled     = true;
                _rLRimSpinRenderer.enabled = false;
            }
            if (Mathf.Abs(WCFR.rpm) > 300)
            {
                _fRRimRenderer.enabled     = false;
                _fRRimSpinRenderer.enabled = true;
            }
            else
            {
                _fRRimRenderer.enabled     = true;
                _fRRimSpinRenderer.enabled = false;
            }
            if (Mathf.Abs(WCRR.rpm) > 300)
            {
                _rRRimRenderer.enabled     = false;
                _rRRimSpinRenderer.enabled = true;
            }
            else
            {
                _rRRimRenderer.enabled     = true;
                _rRRimSpinRenderer.enabled = false;
            }
        }

        //Adapt the tyre slip according to the road type


        bool GravelSimulation = false;

        if (Gps != null)
        {
            UnityEngine.Profiling.Profiler.BeginSample("AdaptSlip");
            RoadMat = Gps.RoadMat;
            switch (RoadMat)
            {
            case "Tarmac":
            case "Washboard":
                frontFrict = frontFrictTarmac;
                rearFrict  = rearFrictTarmac;
                break;

            case "DirtyRoad":
                frontFrict = frontFrictDirtyRoad;
                rearFrict  = rearFrictDirtyRoad;
                //GravelSimulation = true;
                break;

            default:
                frontFrict       = frontFrictDirt;
                rearFrict        = rearFrictDirt;
                GravelSimulation = true;
                break;
            }
            SkidThresh = rearFrict.keys[1].time;

            UnityEngine.Profiling.Profiler.EndSample();
            UnityEngine.Profiling.Profiler.BeginSample("ReverseSteer");
            //For Rear wheel drive we give a little extra torque when reverse steering in a skid
            Vector3 _vel           = _rb.velocity;
            float   _rearSlideSlip = Vector3.Angle(_vel, transform.forward);
            if (WCRL.angularVelocity > 0)
            {
                //Easy cornering - The GPS can manage the reverse steering
                float BendAnglePerSec = 0;
                UnityEngine.Profiling.Profiler.BeginSample("CalcNewF");
                if (Gps.CurrBend != null)
                {
                    BendAnglePerSec = Gps.CurrBend.AnglePerSeg * Gps.SegsPerSec;
                    float CorrectionAnglePerSec = (BendAnglePerSec - _rb.angularVelocity.y * 57.3f);
                    if (Mathf.Sign(CorrectionAnglePerSec) != Mathf.Sign(BendAnglePerSec))     //only apply the correction if oversteering
                    {
                        h += CorrectionAnglePerSec;
                    }
                    h = Mathf.Clamp(h, -40, 40);
                }

                WCRL.fFriction.forceCoefficient    = FCoef;
                WCRR.fFriction.forceCoefficient    = FCoef;
                WCRL.sideFriction.forceCoefficient = SCoef;
                WCRR.sideFriction.forceCoefficient = SCoef;

                Vector3 cross = Vector3.Cross(_vel, transform.forward);
                if (Mathf.Abs(h) < 3 || Mathf.Sign(cross.y) != Mathf.Sign(h))
                {
                    WCRL.motorTorque *= (1 + Mathf.Abs(_rearSlideSlip) / 90f);
                    WCRR.motorTorque *= (1 + Mathf.Abs(_rearSlideSlip) / 90f);
                    WCRL.fFriction.forceCoefficient *= (1 + Mathf.Abs(_rearSlideSlip) / 90f);
                    WCRR.fFriction.forceCoefficient *= (1 + Mathf.Abs(_rearSlideSlip) / 90f);
                }
            }   //going forwrds

            //spinout
            //if (_rearSlideSlip > 90) { WCRL.sFriction.forceCoefficient = 0.2f; WCRR.sFriction.forceCoefficient = 0.2f; }
        }
        else  //if gps is null
        {
            frontFrict = frontFrictDirt;
            rearFrict  = rearFrictDirt;
            RoadMat    = "Dirt";
        }

        if (frontFrict == frontFrictTarmac && _rb.velocity.sqrMagnitude > 4)
        {
            h = h / 2;
        }
        WCFL.steerAngle = h;
        WCFR.steerAngle = h;


        //comment out this block for roadmat testing
        WCFL.forwardFriction.frictionCurve = frontFrict;
        WCFR.forwardFriction.frictionCurve = frontFrict;
        WCRL.forwardFriction.frictionCurve = rearFrict;
        WCRR.forwardFriction.frictionCurve = rearFrict;
        WCFL.GravelSimulation = GravelSimulation;
        WCFR.GravelSimulation = GravelSimulation;
        WCRL.GravelSimulation = GravelSimulation;
        WCRR.GravelSimulation = GravelSimulation;


        #region Anti-Roll bar Region
        float travelL;
        float travelR;
        float AntiRoll = AntiRollForce * GetComponent <Rigidbody>().velocity.magnitude;

        bool groundedFL = WCFL.GetGroundHit(out hitFL);

        //float ContactAngle;
        //WheelFrictionCurve Fric;
        //Fric = WCFL.forwardFriction;
        if (groundedFL)
        {
            travelL = 1 - WCFL.springCompression; // (-WCFL.transform.InverseTransformPoint(hitFL.point).y - WCFL.radius) / WCFL.springLength;
        }
        else
        {
            travelL = 1.0f;
        }

        bool groundedFR = WCFR.GetGroundHit(out hitFR);
        if (groundedFR)
        {
            travelR = 1 - WCFR.springCompression; // (-WCFR.transform.InverseTransformPoint(hitFR.point).y - WCFR.radius) / WCFR.springLength;
        }
        else
        {
            travelR = 1.0f;
        }

        var antiRollForce = (travelL - travelR) * AntiRoll;
        if (groundedFL)
        {
            GetComponent <Rigidbody>().AddForceAtPosition(WCFL.transform.up * antiRollForce, WCFR.transform.position);
            GetComponent <Rigidbody>().AddForceAtPosition(WCFL.transform.up * -antiRollForce, WCFL.transform.position);
        }
        if (groundedFR)
        {
            GetComponent <Rigidbody>().AddForceAtPosition(WCFR.transform.up * -antiRollForce, WCFL.transform.position);
            GetComponent <Rigidbody>().AddForceAtPosition(WCFR.transform.up * antiRollForce, WCFR.transform.position);
        }

        //BACK WHEEL ANTI-ROLL BAR

        bool groundedRL = WCRL.GetGroundHit(out hitRL);
        bool groundedRR = WCRR.GetGroundHit(out hitRR);

        float ForwardSlipRL = hitRL.forwardSlip;
        if (groundedRL)
        {
            travelL = (-WCRL.transform.InverseTransformPoint(hitRL.point).y - WCRL.radius) / WCRL.springLength;
        }
        else
        {
            travelL = 1.0f;
        }
        if (WCRL.SlipVectorMagnitude > SkidThresh * 2.25f && RoadMat == "Tarmac")
        {
            IsSkiddingRL = true;
        }
        else
        {
            IsSkiddingRL = false;
        }

        float ForwardSlipRR = hitRR.forwardSlip;
        if (groundedRR)
        {
            travelR = (-WCRR.transform.InverseTransformPoint(hitRR.point).y - WCRR.radius) / WCRR.springLength;
        }
        else
        {
            travelR = 1.0f;
        }

        if (WCRR.SlipVectorMagnitude > SkidThresh * 2.25f && RoadMat == "Tarmac")
        {
            IsSkiddingRR = true;
        }
        else
        {
            IsSkiddingRR = false;
        }

        antiRollForce = (travelL - travelR) * AntiRoll;
        if (groundedRL)
        {
            GetComponent <Rigidbody>().AddForceAtPosition(WCRL.transform.up * antiRollForce, WCRR.transform.position);
            GetComponent <Rigidbody>().AddForceAtPosition(WCRL.transform.up * -antiRollForce, WCRL.transform.position);
        }
        if (groundedRR)
        {
            GetComponent <Rigidbody>().AddForceAtPosition(WCRR.transform.up * -antiRollForce, WCRL.transform.position);
            GetComponent <Rigidbody>().AddForceAtPosition(WCRR.transform.up * antiRollForce, WCRR.transform.position);
        }
        #endregion

        #region Spray and Smoke Particles Region
        //Spray dirt
        try
        {
            if (RoadMat == "Dirt" || RoadMat == "Air")
            {
                if (groundedRL && ForwardSlipRL != 0)
                {
                    if (WCRL.motorTorque > 0)
                    {
                        psSprayLFwd.Stop();
                        psSprayL.Play();
                        var vel = psSprayL.velocityOverLifetime;
                        vel.x = WCRL.slipVectorNorm.y * Mathf.Sign(WCRL.motorTorque) * 3;
                        vel.y = 2;
                        vel.z = WCRL.slipVectorNorm.x * Mathf.Abs(WCRL.SlipVectorMagnitude) * 3.5f;
                        peSprayL.rateOverTime = Mathf.Clamp(WCRL.SlipVectorMagnitude * 50, 0, 50);
                    }
                    else   //goimg backwards
                    {
                        psSprayL.Stop();
                        psSprayLFwd.Play();
                        var vel = psSprayLFwd.velocityOverLifetime;
                        vel.x = WCRL.slipVectorNorm.y * Mathf.Sign(WCRL.motorTorque) * 3;
                        vel.y = Mathf.Abs(WCRL.SlipVectorMagnitude);
                        vel.z = WCRL.slipVectorNorm.x * Mathf.Abs(WCRL.SlipVectorMagnitude) * 3.5f;
                        //peSprayFLFwd.emissionRate = Mathf.Clamp(WCRL.SlipVectorMagnitude * 30, 0, 30);
                        ParticleSystem.EmissionModule e = psSprayLFwd.emission;
                        e.rateOverTime = Mathf.Clamp(WCRL.SlipVectorMagnitude * 30, 0, 30);
                    }
                }
                else
                {
                    psSprayLFwd.Stop();
                    psSprayL.Stop();
                }

                if (groundedRR && ForwardSlipRR != 0)
                {
                    if (WCRL.motorTorque > 0)
                    {
                        psSprayRFwd.Stop();
                        psSprayR.Play();
                        var vel = psSprayR.velocityOverLifetime;
                        vel.x = WCRR.slipVectorNorm.y * Mathf.Sign(WCRR.motorTorque) * 4;
                        vel.y = 2;
                        vel.z = WCRR.slipVectorNorm.x * Mathf.Abs(WCRR.SlipVectorMagnitude) * 5;
                        peSprayR.rateOverTime = Mathf.Clamp(WCRR.SlipVectorMagnitude * 50, 0, 50);
                    }
                    else
                    {
                        psSprayR.Stop();
                        psSprayRFwd.Play();
                        var vel = psSprayRFwd.velocityOverLifetime;
                        vel.x = WCRR.slipVectorNorm.y * Mathf.Sign(WCRR.motorTorque) * 4;
                        vel.y = 2;
                        vel.z = WCRR.slipVectorNorm.x * Mathf.Abs(WCRR.SlipVectorMagnitude) * 5;
                        //peSprayFRFwd.emissionRate = Mathf.Clamp(WCRR.SlipVectorMagnitude * 50, 0, 50);
                        ParticleSystem.EmissionModule e = psSprayRFwd.emission;
                        e.rateOverTime = Mathf.Clamp(WCRR.SlipVectorMagnitude * 30, 0, 30);
                    }
                }
                else
                {
                    psSprayRFwd.Stop();
                    psSprayR.Stop();
                }
            }
            else
            {
                psSprayR.Stop(); psSprayRFwd.Stop(); psSprayL.Stop(); psSprayLFwd.Stop();
            }
        }
        catch (Exception e) { Debug.Log(e.ToString()); }

        //Spray dust on DirtyRoad
        try
        {
            psDustL.Stop();
            psDustR.Stop();

            if (RoadMat == "DirtyRoad")
            {
                psDustL.Play();
                psDustR.Play();
                float SlipRL = Mathf.Clamp(WCRL.SlipVectorMagnitude, 0, 2f);
                float SlipRR = Mathf.Clamp(WCRR.SlipVectorMagnitude, 0, 2f);
                peDustL.rateOverTime            = SlipRL * 80f;
                peDustR.rateOverTime            = SlipRR * 80f;
                psDustL.transform.localPosition = new Vector3(0, -0.4f, -WCRL.forwardFriction.slip / 6);
                psDustR.transform.localPosition = new Vector3(0, -0.4f, -WCRR.forwardFriction.slip / 6);
            }
            else
            {
                psDustL.Stop();
                psDustR.Stop();
            }
        }
        catch { }
        #endregion

        #region Wheel Ruts and Skidmarks Region
        //Make Wheel ruts

        if ((RoadMat == "Dirt" || RoadMat == "DirtyRoad") && groundedRL && WCRL.SlipVectorMagnitude > SkidThresh / 2)
        {
            IsRuttingRL = true;
        }
        else
        {
            IsRuttingRL = false;
        }
        //Debug.Log(IsRuttingRL.ToString() + WasRuttingRL.ToString());
        if (IsRuttingRL)
        {
            if (!WasRuttingRL)
            {
                //create a new rut
                RutLeft = Road.Instance.NextSkidMk(RutLeft);
                if (RutLeft != null)
                {
                    RutLeft.SetMaterial(RutMatrl);
                    RutLeft.Width    = 0.233f;
                    RutLeftNodeCount = 0;
                }
            }
            if (RutLeft != null)
            {
                RutLeft.AddNode(hitRL.point + Vector3.up * 0.05f);
            }
        }
        WasRuttingRL = IsRuttingRL;

        if ((RoadMat == "Dirt" || RoadMat == "DirtyRoad") && groundedRR && WCRR.SlipVectorMagnitude > SkidThresh / 2)
        {
            IsRuttingRR = true;
        }
        else
        {
            IsRuttingRR = false;
        }

        if (IsRuttingRR)
        {
            if (!WasRuttingRR)
            {
                //create a new rut
                RutRight = Road.Instance.NextSkidMk(RutRight);
                if (RutRight != null)
                {
                    RutRight.SetMaterial(RutMatrl);
                    RutRight.Width    = 0.233f;
                    RutRightNodeCount = 0;
                }
            }
            if (RutRight != null)
            {
                RutRight.AddNode(hitRR.point + Vector3.up * 0.05f);
            }
        }
        WasRuttingRR = IsRuttingRR;


        //Skidmarks

        if (IsSkiddingRL)
        {
            if (!WasSkiddingRL)
            {
                //create a new rut
                RutLeft = Road.Instance.NextSkidMk(RutLeft);
                if (RutLeft != null)
                {
                    RutLeft.SetMaterial(SkidMatrl);
                    RutLeft.Width    = 0.233f;
                    RutLeftNodeCount = 0;
                }
            }
            if (RutLeft != null)
            {
                RutLeft.AddNode(hitRL.point + Vector3.up * 0.05f);
            }
        }
        WasSkiddingRL = IsSkiddingRL;

        if (IsSkiddingRR)
        {
            if (!WasSkiddingRR)
            {
                //create a new rut
                RutRight = Road.Instance.NextSkidMk(RutRight);
                if (RutRight != null)
                {
                    RutRight.SetMaterial(SkidMatrl);
                    RutRight.Width    = 0.233f;
                    RutRightNodeCount = 0;
                }
            }
            if (RutRight != null)
            {
                RutRight.AddNode(hitRR.point + Vector3.up * 0.05f);
            }
        }

        WasSkiddingRR = IsSkiddingRR;
        if (EndSkidmarks)
        {
            WasSkiddingRL = false; WasSkiddingRR = false; WasRuttingRL = false; WasRuttingRR = false; EndSkidmarks = false;
        }

        #endregion

        //Skid Sounds
        if (IsSkiddingRL || IsSkiddingRR)
        {
            if (!SkidAudioSource.isPlaying)
            {
                SkidAudioSource.Play();
            }
        }
        else
        {
            SkidAudioSource.Stop();
        }
    }
コード例 #3
0
    // Update is called once per frame
    //FixedUpdate is called for every physics calculation
    void FixedUpdate()
    {
        GetInputFromInputManager();

        //The rest of this method controls the car

        WCFL.brakeTorque = BrakeForce;
        WCFR.brakeTorque = BrakeForce;
        WCRL.brakeTorque = BrakeForce;
        WCRR.brakeTorque = BrakeForce;

        WCRL.motorTorque = v;
        WCRR.motorTorque = v;

        if (WCRL.rpm < -300)
        {
            WCRL.motorTorque = Mathf.Clamp(WCRL.motorTorque, 0, 10000);
            WCRR.motorTorque = Mathf.Clamp(WCRR.motorTorque, 0, 10000);
        }

        if (_rimSpin)
        {
            if (Mathf.Abs(WCFL.rpm) > 300)
            {
                _fLRimSpinRenderer.enabled = true;
                _fLRimRenderer.enabled     = false;
            }
            else
            {
                _fLRimRenderer.enabled     = true;
                _fLRimSpinRenderer.enabled = false;
            }
            if (Mathf.Abs(WCRL.rpm) > 300)
            {
                _rLRimSpinRenderer.enabled = true;
                _rLRimRenderer.enabled     = false;
            }
            else
            {
                _rLRimRenderer.enabled     = true;
                _rLRimSpinRenderer.enabled = false;
            }
            if (Mathf.Abs(WCFR.rpm) > 300)
            {
                _fRRimRenderer.enabled     = false;
                _fRRimSpinRenderer.enabled = true;
            }
            else
            {
                _fRRimRenderer.enabled     = true;
                _fRRimSpinRenderer.enabled = false;
            }
            if (Mathf.Abs(WCRR.rpm) > 300)
            {
                _rRRimRenderer.enabled     = false;
                _rRRimSpinRenderer.enabled = true;
            }
            else
            {
                _rRRimRenderer.enabled     = true;
                _rRRimSpinRenderer.enabled = false;
            }
        }

        //Adapt the tyre slip according to the road type

        bool GravelSimulation = false;

        if (Gps != null)
        {
            RoadMat = Gps.RoadMat;
            switch (RoadMat)
            {
            case "Tarmac":
            case "Washboard":
                frontFrict = frontFrictTarmac;
                rearFrict  = rearFrictTarmac;
                break;

            case "DirtyRoad":
                frontFrict = frontFrictDirtyRoad;
                rearFrict  = rearFrictDirtyRoad;
                //GravelSimulation = true;
                break;

            default:
                frontFrict       = frontFrictDirt;
                rearFrict        = rearFrictDirt;
                GravelSimulation = true;
                break;
            }



            Vector3 _vel           = _rb.velocity;
            float   _rearSlideSlip = Vector3.Angle(_vel, transform.forward);
            if (WCRL.angularVelocity > 0)
            {
                //Easy cornering - The GPS can manage the reverse steering
                float BendAnglePerSec = 0;
                if (Gps.CurrBend != null)
                {
                    BendAnglePerSec = Gps.CurrBend.AnglePerSeg * Gps.SegsPerSec;
                    float CorrectionAnglePerSec = (BendAnglePerSec - _rb.angularVelocity.y * 57.3f);
                    if (Mathf.Sign(CorrectionAnglePerSec) != Mathf.Sign(BendAnglePerSec))     //only apply the correction if oversteering
                    {
                        h += CorrectionAnglePerSec;
                    }
                    h = Mathf.Clamp(h, -40, 40);
                }

                //For Rear wheel drive we give a little extra torque when reverse steering in a skid
                Vector3 cross = Vector3.Cross(_vel, transform.forward);
                WCRL.fFriction.forceCoefficient    = FCoef;
                WCRR.fFriction.forceCoefficient    = FCoef;
                WCRL.sideFriction.forceCoefficient = SCoef;
                WCRR.sideFriction.forceCoefficient = SCoef;
                if (Mathf.Abs(h) < 3 || Mathf.Sign(cross.y) != Mathf.Sign(h))
                {
                    WCRL.motorTorque *= (1 + Mathf.Abs(_rearSlideSlip) / 90f);
                    WCRR.motorTorque *= (1 + Mathf.Abs(_rearSlideSlip) / 90f);
                    WCRL.fFriction.forceCoefficient *= (1 + Mathf.Abs(_rearSlideSlip) / 90f);
                    WCRR.fFriction.forceCoefficient *= (1 + Mathf.Abs(_rearSlideSlip) / 90f);
                }
            }   //going forwrds

            //spinout
            //if (_rearSlideSlip > 90) { WCRL.sFriction.forceCoefficient = 0.2f; WCRR.sFriction.forceCoefficient = 0.2f; }
        }
        else  //if gps is null
        {
            frontFrict = frontFrictDirt;
            rearFrict  = rearFrictDirt;
            RoadMat    = "Dirt";
        }

        if (frontFrict == frontFrictTarmac)
        {
            h = h / (1f + GetComponent <Rigidbody>().velocity.magnitude / 35);                                //The last number: bigger means sharper turns at high speed
        }
        WCFL.steerAngle = h;
        WCFR.steerAngle = h;

        //For testing comment out this block
        WCFL.forwardFriction.frictionCurve = frontFrict;
        WCFR.forwardFriction.frictionCurve = frontFrict;
        WCRL.forwardFriction.frictionCurve = rearFrict;
        WCRR.forwardFriction.frictionCurve = rearFrict;

        WCFL.GravelSimulation = GravelSimulation;
        WCFR.GravelSimulation = GravelSimulation;
        WCRL.GravelSimulation = GravelSimulation;
        WCRR.GravelSimulation = GravelSimulation;

        #region Anti-Roll bar Region

        float travelL;
        float travelR;
        float AntiRoll = AntiRollForce * GetComponent <Rigidbody>().velocity.magnitude;

        bool groundedFL = WCFL.GetGroundHit(out hitFL);

        //float ContactAngle;
        //WheelFrictionCurve Fric;
        //Fric = WCFL.forwardFriction;
        if (groundedFL)
        {
            travelL = WCFL.springCompression - 1;
        }
        else
        {
            travelL = 1.0f;
        }

        bool groundedFR = WCFR.GetGroundHit(out hitFR);
        if (groundedFR)
        {
            travelR = WCFR.springCompression - 1;
        }
        else
        {
            travelR = 1.0f;
        }

        var antiRollForce = (travelL - travelR) * AntiRoll;
        if (groundedFL)
        {
            GetComponent <Rigidbody>().AddForceAtPosition(WCFL.transform.up * antiRollForce, WCFR.transform.position);
            GetComponent <Rigidbody>().AddForceAtPosition(WCFL.transform.up * -antiRollForce, WCFL.transform.position);
        }
        if (groundedFR)
        {
            GetComponent <Rigidbody>().AddForceAtPosition(WCFR.transform.up * -antiRollForce, WCFL.transform.position);
            GetComponent <Rigidbody>().AddForceAtPosition(WCFR.transform.up * antiRollForce, WCFR.transform.position);
        }

        //BACK WHEEL ANTI-ROLL BAR

        bool groundedRL = WCRL.GetGroundHit(out hitRL);
        bool groundedRR = WCRR.GetGroundHit(out hitRR);

        float ForwardSlipRL  = hitRL.forwardSlip;
        float SidewaysSlipRL = hitRL.sidewaysSlip;
        if (groundedRL)
        {
            travelL = WCRL.springCompression - 1;
        }
        else
        {
            travelL = 1.0f;
        }
        if (WCRL.SlipVectorMagnitude > SkidThresh && RoadMat == "Tarmac")
        {
            IsSkiddingRL = true;
        }
        else
        {
            IsSkiddingRL = false;
        }

        float ForwardSlipRR  = hitRR.forwardSlip;
        float SidewaysSlipRR = hitRR.sidewaysSlip;

        if (groundedRR)
        {
            travelR = WCRR.springCompression - 1;
        }
        else
        {
            travelR = 1.0f;
        }

        if (WCRR.SlipVectorMagnitude > SkidThresh && RoadMat == "Tarmac")
        {
            IsSkiddingRR = true;
        }
        else
        {
            IsSkiddingRR = false;
        }

        antiRollForce = (travelL - travelR) * AntiRoll;
        if (groundedRL)
        {
            GetComponent <Rigidbody>().AddForceAtPosition(WCRL.transform.up * antiRollForce, WCRR.transform.position);
            GetComponent <Rigidbody>().AddForceAtPosition(WCRL.transform.up * -antiRollForce, WCRL.transform.position);
        }
        if (groundedRR)
        {
            GetComponent <Rigidbody>().AddForceAtPosition(WCRR.transform.up * -antiRollForce, WCRL.transform.position);
            GetComponent <Rigidbody>().AddForceAtPosition(WCRR.transform.up * antiRollForce, WCRR.transform.position);
        }

        #endregion

        #region Spray and Smoke Particles Region
        //Spray dirt
        try
        {
            if (RoadMat == "Dirt" || RoadMat == "Air")
            {
                if (groundedRL && ForwardSlipRL != 0)
                {
                    if (WCRL.motorTorque > 0)
                    {
                        psSprayLFwd.Stop();
                        psSprayL.Play();
                        var vel = psSprayL.velocityOverLifetime;
                        vel.x = WCRL.slipVectorNorm.y * Mathf.Sign(WCRL.motorTorque) * 7;
                        vel.y = 2;
                        vel.z = WCRL.slipVectorNorm.x * Mathf.Abs(WCRL.SlipVectorMagnitude) * 7;
                        peSprayL.rateOverTime = Mathf.Clamp(WCRL.SlipVectorMagnitude * 50, 0, 50);
                    }
                    else   //goimg backwards
                    {
                        psSprayL.Stop();
                        psSprayLFwd.Play();
                        var vel = psSprayLFwd.velocityOverLifetime;
                        vel.x = WCRL.slipVectorNorm.y * Mathf.Sign(WCRL.motorTorque) * 7;
                        vel.y = 2;
                        vel.z = WCRL.slipVectorNorm.x * Mathf.Abs(WCRL.SlipVectorMagnitude) * 7;
                        ParticleSystem.EmissionModule e = psSprayLFwd.emission;
                        e.rateOverTime = Mathf.Clamp(WCRL.SlipVectorMagnitude * 30, 0, 30);
                    }
                }
                else
                {
                    psSprayLFwd.Stop();
                    psSprayL.Stop();
                }

                if (groundedRR && ForwardSlipRR != 0)
                {
                    if (WCRL.motorTorque > 0)
                    {
                        psSprayRFwd.Stop();
                        psSprayR.Play();
                        var vel = psSprayR.velocityOverLifetime;
                        vel.x = WCRR.slipVectorNorm.y * Mathf.Sign(WCRR.motorTorque) * 7;
                        vel.y = 2;
                        vel.z = WCRR.slipVectorNorm.x * Mathf.Abs(WCRR.SlipVectorMagnitude) * 7;
                        peSprayR.rateOverTime = Mathf.Clamp(WCRR.SlipVectorMagnitude * 50, 0, 50);
                    }
                    else
                    {
                        psSprayR.Stop();
                        psSprayRFwd.Play();
                        var vel = psSprayRFwd.velocityOverLifetime;
                        vel.x = WCRR.slipVectorNorm.y * Mathf.Sign(WCRR.motorTorque) * 7;
                        vel.y = 2;
                        vel.z = WCRR.slipVectorNorm.x * Mathf.Abs(WCRR.SlipVectorMagnitude) * 7;
                        ParticleSystem.EmissionModule e = psSprayRFwd.emission;
                        e.rateOverTime = Mathf.Clamp(WCRR.SlipVectorMagnitude * 30, 0, 30);
                    }
                }
                else
                {
                    psSprayRFwd.Stop();
                    psSprayR.Stop();
                }
                //[email protected]
            }
            else
            {
                psSprayR.Stop(); psSprayRFwd.Stop(); psSprayL.Stop(); psSprayLFwd.Stop();
            }
        }
        catch (Exception e) { Debug.Log(e.ToString()); }

        //Spray dust on DirtyRoad
        try
        {
            psDustL.Stop();
            psDustR.Stop();

            if (RoadMat == "DirtyRoad")
            {
                psDustL.Play();
                psDustR.Play();
                float SlipRL = Mathf.Clamp(WCRL.SlipVectorMagnitude, 0, 2f);
                float SlipRR = Mathf.Clamp(WCRR.SlipVectorMagnitude, 0, 2f);
                ParticleSystem.EmissionModule emRL = psDustL.emission;
                peDustL.rateOverTime            = SlipRL * 80f;
                peDustR.rateOverTime            = SlipRR * 80f;
                psDustL.transform.localPosition = new Vector3(0, -0.4f, -WCRL.forwardFriction.slip / 6);
                psDustR.transform.localPosition = new Vector3(0, -0.4f, -WCRR.forwardFriction.slip / 6);
            }
            else
            {
                psDustL.Stop();
                psDustR.Stop();
            }
        }
        catch { }
        #endregion

        #region Wheel Ruts and Skidmarks Region
        //Make Wheel ruts
        try
        {
            if ((RoadMat == "Dirt" || RoadMat == "DirtyRoad") && groundedRL && ((Math.Abs(ForwardSlipRL) > 1f || Math.Abs(SidewaysSlipRL) > 0.1f) && WCRL.springCompression < 0.6f))
            {
                IsRuttingFL = true;
            }
            else
            {
                IsRuttingFL = false;
            }

            if (IsRuttingFL)
            {
                if (!WasRuttingFL)
                {
                    //create a new rut
                    if (RutLeft != null)
                    {
                        Destroy(RutLeft);
                    }
                    if (RutLeftNodeCount < 20)
                    {
                        GameObject.Destroy(goRutLeft); Road.Instance.RutCount--;
                    }
                    goRutLeft = new GameObject("RutLeft");
                    goRutLeft.transform.SetParent(_trSkidMarks);
                    goRutLeft.isStatic = true;
                    goRutLeft.tag      = "Rut";
                    Road.Instance.RutCount++;
                    RutLeft = goRutLeft.AddComponent <FlatLineRenderer>();
                    RutLeft.Init();
                    RutLeft.SetMaterial(RutMatrl);
                    RutLeft.Width    = 0.233f;
                    RutLeftNodeCount = 0;
                }
                if (RutLeft != null)
                {
                    RutLeftNodeCount++;
                    RutLeft.AddNode(hitRL.point + Vector3.up * 0.05f);
                }
            }
            WasRuttingFL = IsRuttingFL;

            if ((RoadMat == "Dirt" || RoadMat == "DirtyRoad") && groundedRR && ((Math.Abs(ForwardSlipRR) > 1f || Math.Abs(SidewaysSlipRR) > 0.1f) && WCRR.springCompression < 0.6f))
            {
                IsRuttingFR = true;
            }
            else
            {
                IsRuttingFR = false;
            }
            if (IsRuttingFR)
            {
                if (!WasRuttingFR)
                {
                    //create a new rut
                    if (RutRightNodeCount < 20)
                    {
                        GameObject.Destroy(goRutRight); Road.Instance.RutCount--;
                    }
                    goRutRight = new GameObject("RutRight");
                    goRutRight.transform.SetParent(_trSkidMarks);
                    goRutRight.isStatic = true;
                    goRutRight.tag      = "Rut";
                    Road.Instance.RutCount++;
                    RutRight = goRutRight.AddComponent <FlatLineRenderer>();
                    RutRight.Init();
                    RutRight.SetMaterial(RutMatrl);
                    RutRight.Width    = 0.233f;
                    RutRightNodeCount = 0;
                }
                if (RutRight != null)
                {
                    RutRightNodeCount++;
                    RutRight.AddNode(hitRR.point + Vector3.up * 0.05f);
                }
            }
            WasRuttingFR = IsRuttingFR;
        }
        catch (Exception e)
        {
            Debug.Log(e.ToString());
        }

        //Skid Sounds
        if (IsSkiddingRL || IsSkiddingRR)
        {
            if (!SkidAudioSource.isPlaying)
            {
                SkidAudioSource.Play();
            }
        }
        else
        {
            SkidAudioSource.Stop();
        }

        //Skidmarks

        if (IsSkiddingRL)
        {
            if (!WasSkiddingRL)
            {
                //create a new rut
                if (SkidMkLeft != null)
                {
                    SkidMkLeft.enabled = false; Destroy(SkidMkLeft);
                }
                if (SkidMkLeftNodeCount < 50)
                {
                    GameObject.Destroy(goSkidMkLeft); Road.Instance.RutCount--;
                }
                goSkidMkLeft = new GameObject("SkidMkLeft");
                goSkidMkLeft.transform.SetParent(_trSkidMarks);
                goSkidMkLeft.isStatic = true;
                goSkidMkLeft.tag      = "Rut";
                Road.Instance.RutCount++;
                SkidMkLeft = goSkidMkLeft.AddComponent <FlatLineRenderer>();
                SkidMkLeft.Init();
                SkidMkLeft.SetMaterial(SkidMatrl);
                SkidMkLeft.Width    = 0.15f;
                SkidMkLeftNodeCount = 0;
            }
            SkidMkLeftNodeCount++;
            SkidMkLeft.AddNode(hitRL.point + Vector3.up * 0.05f);
        }
        WasSkiddingRL = IsSkiddingRL;
        if (IsSkiddingRR)
        {
            if (!WasSkiddingRR)
            {
                //create a new rut
                if (SkidMkRight != null)
                {
                    Destroy(SkidMkRight);
                }
                if (SkidMkRightNodeCount < 50)
                {
                    GameObject.DestroyImmediate(goSkidMkRight); Road.Instance.RutCount--;
                }
                goSkidMkRight = new GameObject("SkidMkRight");
                goSkidMkRight.transform.SetParent(_trSkidMarks);
                goSkidMkRight.isStatic = true;
                goSkidMkRight.tag      = "Rut";
                Road.Instance.RutCount++;
                SkidMkRight = goSkidMkRight.AddComponent <FlatLineRenderer>();
                SkidMkRight.Init();
                SkidMkRight.SetMaterial(SkidMatrl);
                SkidMkRight.Width    = 0.15f;
                SkidMkRightNodeCount = 0;
            }
            SkidMkRightNodeCount++;
            SkidMkRight.AddNode(hitRR.point + Vector3.up * 0.05f);
        }
        WasSkiddingRR = IsSkiddingRR;
        if (EndSkidmarks)
        {
            WasSkiddingRL = false; WasSkiddingRR = false; WasRuttingFL = false; WasRuttingFR = false; EndSkidmarks = false;
        }
        #endregion
    }