// 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; }
// 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(); } }
// 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 }