2527 lines
86 KiB
C#
2527 lines
86 KiB
C#
using UnityEngine;
|
|
using UnityEngine.Audio;
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine.EventSystems;
|
|
|
|
[AddComponentMenu("BoneCracker Games/Realistic Car Controller/Main/RCC Realistic Car Controller V3")]
|
|
[RequireComponent(typeof(Rigidbody))]
|
|
/// <summary>
|
|
/// Main vehicle controller script that includes Wheels, Steering, Suspensions, Mechanic Configuration, Stability, Lights, Sounds, and Damage in AIO.
|
|
/// </summary>
|
|
public class RCC_CarControllerV3 : RCC_Core {
|
|
|
|
#region OBSOLETE VARIABLES
|
|
|
|
[System.Obsolete("Use AllWheelColliders instead of allWheelColliders")]
|
|
public RCC_WheelCollider[] allWheelColliders {
|
|
|
|
get {
|
|
|
|
return AllWheelColliders;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
[System.Obsolete("Use Rigid instead of rigid")]
|
|
public Rigidbody rigid
|
|
{
|
|
|
|
get
|
|
{
|
|
|
|
return Rigid;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
[System.Obsolete("Use RunEngineAtAwake instead of runEngineAtAwake")]
|
|
public bool runEngineAtAwake {
|
|
|
|
get {
|
|
|
|
return RunEngineAtAwake;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
[System.Obsolete("Use AutoReverse instead of autoReverse")]
|
|
public bool autoReverse {
|
|
|
|
get {
|
|
|
|
return AutoReverse;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
[System.Obsolete("Use AutomaticGear instead of automaticGear")]
|
|
public bool automaticGear {
|
|
|
|
get {
|
|
|
|
return AutomaticGear;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
[System.Obsolete("Use UseAutomaticClutch instead of useAutomaticClutch")]
|
|
public bool useAutomaticClutch {
|
|
|
|
get {
|
|
|
|
return UseAutomaticClutch;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endregion
|
|
|
|
public bool canControl = true; // Enables / Disables controlling the vehicle. If enabled, vehicle can receive all inputs from the InputManager.
|
|
public bool isGrounded = false; // Is vehicle grounded completely now?
|
|
|
|
public bool overrideBehavior = false; // Vehicle won't be affected by selected behavior in RCC Settings if override is selected.
|
|
public bool overrideInputs = false; // Override internal inputs with given inputs. Vehicle won't receive player inputs from the RCC_InputManager if this option is enabled.
|
|
|
|
#region Wheels
|
|
// Wheel models of the vehicle.
|
|
public Transform FrontLeftWheelTransform;
|
|
public Transform FrontRightWheelTransform;
|
|
public Transform RearLeftWheelTransform;
|
|
public Transform RearRightWheelTransform;
|
|
public Transform[] ExtraRearWheelsTransform; // Extra wheel models in case your vehicle has extra wheels.
|
|
|
|
// Wheel colliders of the vehicle.
|
|
public RCC_WheelCollider FrontLeftWheelCollider;
|
|
public RCC_WheelCollider FrontRightWheelCollider;
|
|
public RCC_WheelCollider RearLeftWheelCollider;
|
|
public RCC_WheelCollider RearRightWheelCollider;
|
|
public RCC_WheelCollider[] ExtraRearWheelsCollider; // Extra wheelcolliders in case your vehicle has extra wheels.
|
|
|
|
// All wheel colliders.
|
|
public RCC_WheelCollider[] AllWheelColliders {
|
|
|
|
get {
|
|
|
|
if (_allWheelColliders == null || _allWheelColliders.Length <= 0)
|
|
_allWheelColliders = GetComponentsInChildren<RCC_WheelCollider>(true);
|
|
|
|
return _allWheelColliders;
|
|
|
|
}
|
|
|
|
}
|
|
private RCC_WheelCollider[] _allWheelColliders;
|
|
|
|
// All lights.
|
|
public RCC_Light[] AllLights {
|
|
|
|
get {
|
|
|
|
if (_allLights == null || _allLights.Length <= 0)
|
|
_allLights = GetComponentsInChildren<RCC_Light>(true);
|
|
|
|
return _allLights;
|
|
|
|
}
|
|
|
|
}
|
|
private RCC_Light[] _allLights;
|
|
|
|
public bool hasExtraWheels = false; // Vehicle has extra wheels?
|
|
|
|
public bool overrideAllWheels = false; // Overriding individual wheel settings such as steer, power, brake, handbrake.
|
|
public int poweredWheels = 0; // Total count of powered wheels. Used for dividing total power per each wheel.
|
|
#endregion
|
|
|
|
#region SteeringWheel
|
|
// Steering wheel model.
|
|
public Transform SteeringWheel; // Driver steering wheel model. In case of if your vehicle has individual steering wheel model in interior.
|
|
private Quaternion orgSteeringWheelRot = Quaternion.identity; // Original rotation of steering wheel.
|
|
public SteeringWheelRotateAround steeringWheelRotateAround = SteeringWheelRotateAround.ZAxis; // Current rotation of steering wheel.
|
|
public enum SteeringWheelRotateAround { XAxis, YAxis, ZAxis } // Rotation axis of steering wheel.
|
|
public float steeringWheelAngleMultiplier = 11f; // Angle multiplier of steering wheel.
|
|
#endregion
|
|
|
|
#region Drivetrain Type
|
|
// Drivetrain type of the vehicle.
|
|
public WheelType wheelTypeChoise = WheelType.RWD;
|
|
public enum WheelType { FWD, RWD, AWD, BIASED }
|
|
#endregion
|
|
|
|
#region AI
|
|
public bool externalController = false; // AI Controller.
|
|
#endregion
|
|
|
|
#region Steering
|
|
public enum SteeringType { Curve, Simple, Constant }
|
|
public SteeringType steeringType = SteeringType.Curve;
|
|
public AnimationCurve steerAngleCurve = new AnimationCurve(); // Steering angle limiter curve based on speed.
|
|
public float steerAngle = 40f; // Maximum Steer Angle Of Your Vehicle.
|
|
public float highspeedsteerAngle = 5f; // Maximum Steer Angle At Highest Speed.
|
|
public float highspeedsteerAngleAtspeed = 120f; // Highest Speed For Maximum Steer Angle.
|
|
public float antiRollFrontHorizontal = 1000f; // Anti Roll Horizontal Force For Preventing Flip Overs And Stability.
|
|
public float antiRollRearHorizontal = 1000f; // Anti Roll Horizontal Force For Preventing Flip Overs And Stability.
|
|
public float antiRollVertical = 0f; // Anti Roll Vertical Force For Preventing Flip Overs And Stability. I know it doesn't exist, but it can improve gameplay if you have high COM vehicles like monster trucks.
|
|
#endregion
|
|
|
|
#region Configurations
|
|
// Rigidbody.
|
|
public Rigidbody Rigid {
|
|
|
|
get {
|
|
|
|
if (!_rigid)
|
|
_rigid = GetComponent<Rigidbody>();
|
|
|
|
return _rigid;
|
|
|
|
}
|
|
|
|
}
|
|
private Rigidbody _rigid;
|
|
|
|
public Transform COM; // Center of mass.
|
|
|
|
public enum COMAssisterTypes { Off, Slight, Medium, Opposite }
|
|
public COMAssisterTypes COMAssister = COMAssisterTypes.Off;
|
|
|
|
public float brakeTorque = 2000f; // Maximum brake torque.,
|
|
public float downForce = 25f; // Applies downforce related with vehicle speed.
|
|
public float speed = 0f; // Vehicle speed in km/h or mp/h.
|
|
public float maxspeed = 240f; // Top speed.
|
|
private float resetTime = 0f; // Used for resetting the vehicle if upside down.
|
|
#endregion
|
|
|
|
#region Engine
|
|
public AnimationCurve engineTorqueCurve = new AnimationCurve(); // Engine torque curve based on RPM.
|
|
public bool autoGenerateEngineRPMCurve = true; // Auto create engine torque curve. If min/max engine rpm, engine torque, max engine torque at rpm, or top speed has been changed at runtime, it will generate new curve with them.
|
|
public float maxEngineTorque = 300f; // Maximum engine torque at target RPM.
|
|
public float maxEngineTorqueAtRPM = 5500f; // Maximum peek of the engine at this RPM.
|
|
public float minEngineRPM = 800f; // Minimum engine RPM.
|
|
public float maxEngineRPM = 7000f; // Maximum engine RPM.
|
|
public float engineRPM = 0f; // Current engine RPM.
|
|
public float engineRPMRaw = 0f; // Current raw engine RPM.
|
|
[Range(.02f, .4f)] public float engineInertia = .15f; // Engine inertia. Engine reacts faster on lower values.
|
|
public bool useRevLimiter = true; // Rev limiter above maximum engine RPM. Cuts gas when RPM exceeds maximum engine RPM.
|
|
public bool useExhaustFlame = true; // Exhaust blows flame when driver cuts gas at certain RPMs.
|
|
public bool RunEngineAtAwake = true; // Engine running at Awake?
|
|
public bool engineRunning = false; // Engine running now?
|
|
|
|
// Comparing old and new values to recreate engine torque curve.
|
|
private float oldEngineTorque = 0f; // Old engine torque used for recreating the engine curve.
|
|
private float oldMaxTorqueAtRPM = 0f; // Old max torque used for recreating the engine curve.
|
|
private float oldMinEngineRPM = 0f; // Old min RPM used for recreating the engine curve.
|
|
private float oldMaxEngineRPM = 0f; // Old max RPM used for recreating the engine curve.
|
|
#endregion
|
|
|
|
#region Steering Assistance
|
|
public bool useSteeringLimiter = true; // Limits maximum steering angle when vehicle is sliding. It helps to keep the vehicle in control.
|
|
public bool useCounterSteering = true; // Applies counter steering when vehicle is drifting. It helps to keep the vehicle in control.
|
|
public bool useSteeringSensitivity = true; // Steering sensitivity.
|
|
[Range(0f, 1f)] public float counterSteeringFactor = .5f; // Counter steering multiplier.
|
|
[Range(.05f, 1f)] public float steeringSensitivityFactor = 1f; // Steering sensitivity multiplier.
|
|
private float orgSteerAngle = 0f; // Original steer angle.
|
|
public float oldSteeringInput = 0f; // Old steering input.
|
|
public float steeringDifference = 0f; // Steering input difference.
|
|
#endregion
|
|
|
|
#region Fuel
|
|
// Fuel.
|
|
public bool useFuelConsumption = false; // Enable / Disable Fuel Consumption.
|
|
public float fuelTankCapacity = 62f; // Fuel Tank Capacity.
|
|
public float fuelTank = 62f; // Fuel Amount.
|
|
public float fuelConsumptionRate = .1f; // Fuel Consumption Rate.
|
|
#endregion
|
|
|
|
#region Heat
|
|
// Engine heat.
|
|
public bool useEngineHeat = false; // Enable / Disable engine heat.
|
|
public float engineHeat = 15f; // Engine heat.
|
|
public float engineCoolingWaterThreshold = 90f; // Engine cooling water engage point.
|
|
public float engineHeatRate = 1f; // Engine heat multiplier.
|
|
public float engineCoolRate = 1f; // Engine cool multiplier.
|
|
#endregion
|
|
|
|
#region Gears
|
|
// Gears.
|
|
[System.Serializable]
|
|
public class Gear {
|
|
|
|
public float maxRatio;
|
|
public int maxSpeed;
|
|
public int targetSpeedForNextGear;
|
|
|
|
public void SetGear(float ratio, int speed, int targetSpeed) {
|
|
|
|
maxRatio = ratio;
|
|
maxSpeed = speed;
|
|
targetSpeedForNextGear = targetSpeed;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
public Gear[] gears = null; // Gear class.
|
|
public int totalGears = 6; // Total count of gears.
|
|
public int currentGear = 0; // Current gear of the vehicle.
|
|
public bool NGear = false; // N gear.
|
|
|
|
public float finalRatio = 3.23f; // Final drive gear ratio.
|
|
[Range(0f, .5f)] public float gearShiftingDelay = .35f; // Gear shifting delay with time.
|
|
[Range(.25f, 1)] public float gearShiftingThreshold = .75f; // Shifting gears at lower RPMs at higher values.
|
|
[Range(.1f, .9f)] public float clutchInertia = .25f; // Adjusting clutch faster at lower values. Higher values for smooth clutch.
|
|
|
|
public float gearShiftUpRPM = 6500f; // Shifting up when engine RPM is high enough.
|
|
public float gearShiftDownRPM = 3500f; // Shifting down when engine RPM is low enough.
|
|
public bool changingGear = false; // Changing gear currently?
|
|
|
|
public int direction = 1; // Reverse gear currently?
|
|
internal bool canGoReverseNow = false; // If speed is low enough and player pushes the brake button, enable this bool to go reverse.
|
|
public float launched = 0f;
|
|
public bool AutoReverse = true; // Enables / Disables auto reversing when player press brake button. Useful for if you are making parking style game.
|
|
public bool AutomaticGear = true; // Enables / Disables automatic gear shifting.
|
|
internal bool semiAutomaticGear = false; // Enables / Disables semi-automatic gear shifting.
|
|
public bool UseAutomaticClutch = true;
|
|
#endregion
|
|
|
|
#region Audio
|
|
// How many audio sources we will use for simulating engine sounds?. Usually, all modern driving games have around six audio sources per vehicle.
|
|
// Low RPM, Medium RPM, and High RPM. And their off versions.
|
|
public AudioType audioType;
|
|
public enum AudioType { OneSource, TwoSource, ThreeSource, Off }
|
|
|
|
// If you don't have their off versions, generate them.
|
|
public bool autoCreateEngineOffSounds = true;
|
|
|
|
// AudioSources and AudioClips.
|
|
private AudioSource engineStartSound;
|
|
public AudioClip engineStartClip;
|
|
private AudioSource engineSoundHigh;
|
|
public AudioClip engineClipHigh;
|
|
private AudioSource engineSoundMed;
|
|
public AudioClip engineClipMed;
|
|
private AudioSource engineSoundLow;
|
|
public AudioClip engineClipLow;
|
|
private AudioSource engineSoundIdle;
|
|
public AudioClip engineClipIdle;
|
|
private AudioSource gearShiftingSound;
|
|
|
|
private AudioSource engineSoundHighOff;
|
|
public AudioClip engineClipHighOff;
|
|
private AudioSource engineSoundMedOff;
|
|
public AudioClip engineClipMedOff;
|
|
private AudioSource engineSoundLowOff;
|
|
public AudioClip engineClipLowOff;
|
|
|
|
// Shared AudioSources and AudioClips.
|
|
private AudioClip[] GearShiftingClips { get { return RCC_Settings.Instance.gearShiftingClips; } }
|
|
private AudioSource crashSound;
|
|
private AudioClip[] CrashClips { get { return RCC_Settings.Instance.crashClips; } }
|
|
private AudioSource reversingSound;
|
|
private AudioClip ReversingClip { get { return RCC_Settings.Instance.reversingClip; } }
|
|
private AudioSource windSound;
|
|
private AudioClip WindClip { get { return RCC_Settings.Instance.windClip; } }
|
|
private AudioSource brakeSound;
|
|
private AudioClip BrakeClip { get { return RCC_Settings.Instance.brakeClip; } }
|
|
private AudioSource NOSSound;
|
|
private AudioClip NOSClip { get { return RCC_Settings.Instance.NOSClip; } }
|
|
private AudioSource turboSound;
|
|
private AudioClip TurboClip { get { return RCC_Settings.Instance.turboClip; } }
|
|
private AudioSource blowSound;
|
|
private AudioClip[] BlowClip { get { return RCC_Settings.Instance.blowoutClip; } }
|
|
|
|
// Min / Max sound pitches and volumes.
|
|
[Range(0f, 1f)] public float minEngineSoundPitch = .75f;
|
|
[Range(1f, 2f)] public float maxEngineSoundPitch = 1.75f;
|
|
[Range(0f, 1f)] public float minEngineSoundVolume = .05f;
|
|
[Range(0f, 1f)] public float maxEngineSoundVolume = .85f;
|
|
[Range(0f, 1f)] public float idleEngineSoundVolume = .85f;
|
|
|
|
// Positions of the created audio sources.
|
|
public Vector3 engineSoundPosition = new Vector3(0f, 0f, 1.5f);
|
|
public Vector3 gearSoundPosition = new Vector3(0f, -.5f, .5f);
|
|
public Vector3 turboSoundPosition = new Vector3(0f, 0f, 1.5f);
|
|
public Vector3 exhaustSoundPosition = new Vector3(0f, -.5f, -2f);
|
|
public Vector3 windSoundPosition = new Vector3(0f, 0f, 2f);
|
|
#endregion
|
|
|
|
#region Inputs
|
|
// Inputs. All values are clamped 0f - 1f. They will receive proper input values from the RCC_InputManager class.
|
|
public RCC_Inputs inputs = new RCC_Inputs();
|
|
|
|
// Please don't override below variables. If you want to feed inputs, use OverrideInputs method with your own inputs.
|
|
[HideInInspector] public float throttleInput = 0f;
|
|
[HideInInspector] public float brakeInput = 0f;
|
|
[HideInInspector] public float steerInput = 0f;
|
|
[HideInInspector] public float counterSteerInput = 0f;
|
|
[HideInInspector] public float clutchInput = 0f;
|
|
[HideInInspector] public float handbrakeInput = 0f;
|
|
[HideInInspector] public float boostInput = 0f;
|
|
[HideInInspector] public float fuelInput = 0f;
|
|
[HideInInspector] public bool cutGas = false;
|
|
[HideInInspector] public bool permanentGas = false;
|
|
#endregion
|
|
|
|
#region Head Lights
|
|
// Lights.
|
|
public bool lowBeamHeadLightsOn = false; // Low beam head lights.
|
|
public bool highBeamHeadLightsOn = false; // High beam head lights.
|
|
#endregion
|
|
|
|
#region Indicator Lights
|
|
// For Indicators.
|
|
public IndicatorsOn indicatorsOn = IndicatorsOn.Off; // Indicator system.
|
|
public enum IndicatorsOn { Off, Right, Left, All } // Current indicator mode.
|
|
public float indicatorTimer = 0f; // Used timer for indicator on / off sequence.
|
|
#endregion
|
|
|
|
#region Damage
|
|
// Damage.
|
|
public RCC_Damage damage = new RCC_Damage();
|
|
public bool useDamage = true; // Use deformation on collisions.
|
|
public bool useCollisionParticles = true; // Use particles on coliisions.
|
|
public bool useCollisionAudio = true; // Play crash audio clips on collisions
|
|
|
|
public GameObject contactSparkle { get { return RCC_Settings.Instance.contactParticles; } } // Contact Particles for collisions. It must be Particle System.
|
|
public GameObject scratchSparkle { get { return RCC_Settings.Instance.scratchParticles; } } // Scratch Particles for collisions. It must be Particle System.
|
|
|
|
private List<ParticleSystem> contactSparkeList = new List<ParticleSystem>(); // Array for Contact Particles.
|
|
private List<ParticleSystem> scratchSparkeList = new List<ParticleSystem>(); // Array for Contact Particles.
|
|
|
|
public int maximumContactSparkle = 5; // Contact Particles will be ready to use for collisions in pool.
|
|
private GameObject allContactParticles; // Main particle gameobject for keep the hierarchy clean and organized.
|
|
#endregion
|
|
|
|
#region Helpers
|
|
// Used for Angular and Linear Steering Helper.
|
|
private float oldRotation = 0f;
|
|
private Transform velocityDirection;
|
|
private Transform steeringDirection;
|
|
private float velocityAngle = 0f;
|
|
private float angle = 0f;
|
|
private float angularVelo = 0f;
|
|
#endregion
|
|
|
|
#region Driving Assistances
|
|
// Driving Assistances.
|
|
public bool ABS = true;
|
|
public bool TCS = true;
|
|
public bool ESP = true;
|
|
public bool steeringHelper = true;
|
|
public bool tractionHelper = true;
|
|
public bool angularDragHelper = false;
|
|
|
|
// Driving Assistance thresholds.
|
|
[Range(.05f, .5f)] public float ABSThreshold = .35f; // ABS will be engaged at this threshold.
|
|
[Range(.05f, 1f)] public float TCSStrength = .5f;
|
|
[Range(.05f, .5f)] public float ESPThreshold = .5f; // ESP will be engaged at this threshold.
|
|
[Range(.05f, 1f)] public float ESPStrength = .25f;
|
|
[Range(0f, 1f)] public float steerHelperLinearVelStrength = .1f;
|
|
[Range(0f, 1f)] public float steerHelperAngularVelStrength = .1f;
|
|
[Range(0f, 1f)] public float tractionHelperStrength = .1f;
|
|
[Range(0f, 1f)] public float angularDragHelperStrength = .1f;
|
|
|
|
// Is Driving Assistance is in action now?
|
|
public bool ABSAct = false;
|
|
public bool TCSAct = false;
|
|
public bool ESPAct = false;
|
|
|
|
// ESP malfunction.
|
|
public bool ESPBroken = false;
|
|
|
|
// Used For ESP.
|
|
public float frontSlip = 0f;
|
|
public float rearSlip = 0f;
|
|
|
|
// ESP Bools.
|
|
public bool underSteering = false;
|
|
public bool overSteering = false;
|
|
#endregion
|
|
|
|
#region Drift
|
|
// Drift Variables.
|
|
internal bool driftingNow = false; // Currently drifting?
|
|
internal float driftAngle = 0f; // If we do, what's the drift angle?
|
|
#endregion
|
|
|
|
#region Turbo / NOS / Boost
|
|
// Turbo and NOS.
|
|
public float turboBoost = 0f;
|
|
public float NoS = 100f;
|
|
private float NoSConsumption = 25f;
|
|
private float NoSRegenerateTime = 10f;
|
|
|
|
public bool useNOS = false;
|
|
public bool useTurbo = false;
|
|
#endregion
|
|
|
|
#region Events
|
|
/// <summary>
|
|
/// On RCC player vehicle spawned.
|
|
/// </summary>
|
|
public delegate void onRCCPlayerSpawned(RCC_CarControllerV3 RCC);
|
|
public static event onRCCPlayerSpawned OnRCCPlayerSpawned;
|
|
|
|
/// <summary>
|
|
/// On RCC player vehicle destroyed.
|
|
/// </summary>
|
|
public delegate void onRCCPlayerDestroyed(RCC_CarControllerV3 RCC);
|
|
public static event onRCCPlayerDestroyed OnRCCPlayerDestroyed;
|
|
|
|
/// <summary>
|
|
/// On RCC player vehicle collision.
|
|
/// </summary>
|
|
public delegate void onRCCPlayerCollision(RCC_CarControllerV3 RCC, Collision collision);
|
|
public static event onRCCPlayerCollision OnRCCPlayerCollision;
|
|
#endregion
|
|
|
|
public RCC_TruckTrailer attachedTrailer;
|
|
|
|
private void Awake() {
|
|
|
|
// Setting max angular velocity of the rigid.
|
|
Rigid.maxAngularVelocity = RCC_Settings.Instance.maxAngularVelocity;
|
|
|
|
// Checks the important parameters. Normally, editor script limits them, but your old prefabs may still use out of range.
|
|
gearShiftingThreshold = Mathf.Clamp(gearShiftingThreshold, .25f, 1f);
|
|
|
|
// Checks the important parameters. Normally, editor script limits them, but your old prefabs may still use out of range.
|
|
if (engineInertia > .4f)
|
|
engineInertia = .15f;
|
|
|
|
engineInertia = Mathf.Clamp(engineInertia, .02f, .4f);
|
|
|
|
oldEngineTorque = maxEngineTorque;
|
|
oldMaxTorqueAtRPM = maxEngineTorqueAtRPM;
|
|
oldMinEngineRPM = minEngineRPM;
|
|
oldMaxEngineRPM = maxEngineRPM;
|
|
|
|
// Assigning wheel models of the wheelcolliders.
|
|
FrontLeftWheelCollider.wheelModel = FrontLeftWheelTransform;
|
|
FrontRightWheelCollider.wheelModel = FrontRightWheelTransform;
|
|
RearLeftWheelCollider.wheelModel = RearLeftWheelTransform;
|
|
RearRightWheelCollider.wheelModel = RearRightWheelTransform;
|
|
|
|
// If vehicle has extra rear wheels, assign them too.
|
|
if (ExtraRearWheelsCollider != null) {
|
|
|
|
for (int i = 0; i < ExtraRearWheelsCollider.Length; i++)
|
|
ExtraRearWheelsCollider[i].wheelModel = ExtraRearWheelsTransform[i];
|
|
|
|
}
|
|
|
|
// Default Steer Angle. Using it for lerping current steer angle between default steer angle and high speed steer angle.
|
|
orgSteerAngle = steerAngle;
|
|
|
|
// Collecting all contact particles in same parent gameobject for clean hierarchy.
|
|
allContactParticles = new GameObject("All Contact Particles");
|
|
allContactParticles.transform.SetParent(transform, false);
|
|
|
|
// Creating and initializing all audio sources.
|
|
CreateAudios();
|
|
|
|
// Checks the current selected behavior in RCC Settings. If any behavior selected, apply changes to the vehicle.
|
|
if (!overrideBehavior)
|
|
CheckBehavior();
|
|
|
|
// And lastly, starting the engine.
|
|
if (RunEngineAtAwake || externalController) {
|
|
|
|
engineRunning = true;
|
|
fuelInput = 1f;
|
|
|
|
}
|
|
|
|
// If steer angle curve is not initialized or has low keyframes, recreate it.
|
|
if (steerAngleCurve == null)
|
|
steerAngleCurve = new AnimationCurve(new Keyframe(0f, 40f, 0f, -.3f), new Keyframe(120f, 10f, -.115f, -.1f), new Keyframe(200f, 7f)); // Steering angle limiter curve based on speed.
|
|
else if (steerAngleCurve.length < 1)
|
|
steerAngleCurve = new AnimationCurve(new Keyframe(0f, 40f, 0f, -.3f), new Keyframe(120f, 10f, -.115f, -.1f), new Keyframe(200f, 7f)); // Steering angle limiter curve based on speed.
|
|
|
|
}
|
|
|
|
private void OnEnable() {
|
|
|
|
// Make sure changing gear is set to false, because we're setting it in coroutine.
|
|
changingGear = false;
|
|
currentGear = 0;
|
|
driftingNow = false;
|
|
driftAngle = 0f;
|
|
ABSAct = false;
|
|
TCSAct = false;
|
|
ESPAct = false;
|
|
frontSlip = 0f;
|
|
rearSlip = 0f;
|
|
underSteering = false;
|
|
overSteering = false;
|
|
oldRotation = 0f;
|
|
velocityAngle = 0f;
|
|
angle = 0f;
|
|
angularVelo = 0f;
|
|
throttleInput = 0f;
|
|
brakeInput = 0f;
|
|
steerInput = 0f;
|
|
counterSteerInput = 0f;
|
|
clutchInput = 0f;
|
|
handbrakeInput = 0f;
|
|
boostInput = 0f;
|
|
cutGas = false;
|
|
permanentGas = false;
|
|
NGear = false;
|
|
direction = 1;
|
|
launched = 0f;
|
|
resetTime = 0f;
|
|
|
|
if (engineRunning) {
|
|
|
|
engineRPMRaw = minEngineRPM;
|
|
engineRPM = engineRPMRaw;
|
|
|
|
}
|
|
|
|
// Firing an event when each RCC car spawned / enabled. This event has been listening by RCC_MobileButtons.cs, RCC_DashboardInputs.cs.
|
|
StartCoroutine(RCCPlayerSpawned());
|
|
|
|
// Listening an event when main behavior changed.
|
|
RCC_SceneManager.OnBehaviorChanged += CheckBehavior;
|
|
|
|
// Listening input events on RCC_InputManager.
|
|
RCC_InputManager.OnLowBeamHeadlights += RCC_InputManager_OnLowBeamHeadlights;
|
|
RCC_InputManager.OnHighBeamHeadlights += RCC_InputManager_OnHighBeamHeadlights;
|
|
RCC_InputManager.OnIndicatorLeft += RCC_InputManager_OnIndicatorLeft;
|
|
RCC_InputManager.OnIndicatorRight += RCC_InputManager_OnIndicatorRight;
|
|
RCC_InputManager.OnIndicatorHazard += RCC_InputManager_OnIndicatorHazard;
|
|
RCC_InputManager.OnGearShiftUp += RCC_InputManager_OnGearShiftUp;
|
|
RCC_InputManager.OnGearShiftDown += RCC_InputManager_OnGearShiftDown;
|
|
RCC_InputManager.OnNGear += RCC_InputManager_OnNGear;
|
|
RCC_InputManager.OnTrailerDetach += RCC_InputManager_OnTrailerDetach;
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Firing an event when each RCC car spawned / enabled. This event has been listening by RCC_MobileButtons.cs, RCC_DashboardInputs.cs.
|
|
/// </summary>
|
|
/// <returns>The player spawned.</returns>
|
|
private IEnumerator RCCPlayerSpawned() {
|
|
|
|
yield return new WaitForEndOfFrame();
|
|
|
|
// Firing an event when each RCC car spawned / enabled. This event has been listening by RCC_SceneManager.
|
|
if (!externalController) {
|
|
|
|
if (OnRCCPlayerSpawned != null)
|
|
OnRCCPlayerSpawned(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates all wheelcolliders. Only editor script calls this when you click "Create WheelColliders" button.
|
|
/// </summary>
|
|
public void CreateWheelColliders() {
|
|
|
|
CreateWheelColliders(this);
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates all audio sources and assigns corresponding audio clips with proper names and keeping hierarchy more clean.
|
|
/// </summary>
|
|
private void CreateAudios() {
|
|
|
|
switch (audioType) {
|
|
|
|
case AudioType.OneSource:
|
|
|
|
engineSoundHigh = NewAudioSource(RCC_Settings.Instance.audioMixer, gameObject, engineSoundPosition, "Engine Sound High AudioSource", 5, 50, 0, engineClipHigh, true, true, false);
|
|
|
|
if (autoCreateEngineOffSounds) {
|
|
|
|
engineSoundHighOff = NewAudioSource(RCC_Settings.Instance.audioMixer, gameObject, engineSoundPosition, "Engine Sound High Off AudioSource", 5, 50, 0, engineClipHigh, true, true, false);
|
|
|
|
NewLowPassFilter(engineSoundHighOff, 3000f);
|
|
|
|
} else {
|
|
|
|
engineSoundHighOff = NewAudioSource(RCC_Settings.Instance.audioMixer, gameObject, engineSoundPosition, "Engine Sound High Off AudioSource", 5, 50, 0, engineClipHighOff, true, true, false);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case AudioType.TwoSource:
|
|
|
|
engineSoundHigh = NewAudioSource(RCC_Settings.Instance.audioMixer, gameObject, engineSoundPosition, "Engine Sound High AudioSource", 5, 50, 0, engineClipHigh, true, true, false);
|
|
engineSoundLow = NewAudioSource(RCC_Settings.Instance.audioMixer, gameObject, engineSoundPosition, "Engine Sound Low AudioSource", 5, 25, 0, engineClipLow, true, true, false);
|
|
|
|
if (autoCreateEngineOffSounds) {
|
|
|
|
engineSoundHighOff = NewAudioSource(RCC_Settings.Instance.audioMixer, gameObject, engineSoundPosition, "Engine Sound High Off AudioSource", 5, 50, 0, engineClipHigh, true, true, false);
|
|
engineSoundLowOff = NewAudioSource(RCC_Settings.Instance.audioMixer, gameObject, engineSoundPosition, "Engine Sound Low Off AudioSource", 5, 25, 0, engineClipLow, true, true, false);
|
|
|
|
NewLowPassFilter(engineSoundHighOff, 3000f);
|
|
NewLowPassFilter(engineSoundLowOff, 3000f);
|
|
|
|
} else {
|
|
|
|
engineSoundHighOff = NewAudioSource(RCC_Settings.Instance.audioMixer, gameObject, engineSoundPosition, "Engine Sound High Off AudioSource", 5, 50, 0, engineClipHighOff, true, true, false);
|
|
engineSoundLowOff = NewAudioSource(RCC_Settings.Instance.audioMixer, gameObject, engineSoundPosition, "Engine Sound Low Off AudioSource", 5, 25, 0, engineClipLowOff, true, true, false);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case AudioType.ThreeSource:
|
|
|
|
engineSoundHigh = NewAudioSource(RCC_Settings.Instance.audioMixer, gameObject, engineSoundPosition, "Engine Sound High AudioSource", 5, 50, 0, engineClipHigh, true, true, false);
|
|
engineSoundMed = NewAudioSource(RCC_Settings.Instance.audioMixer, gameObject, engineSoundPosition, "Engine Sound Medium AudioSource", 5, 50, 0, engineClipMed, true, true, false);
|
|
engineSoundLow = NewAudioSource(RCC_Settings.Instance.audioMixer, gameObject, engineSoundPosition, "Engine Sound Low AudioSource", 5, 25, 0, engineClipLow, true, true, false);
|
|
|
|
if (autoCreateEngineOffSounds) {
|
|
|
|
engineSoundHighOff = NewAudioSource(RCC_Settings.Instance.audioMixer, gameObject, engineSoundPosition, "Engine Sound High Off AudioSource", 5, 50, 0, engineClipHigh, true, true, false);
|
|
engineSoundMedOff = NewAudioSource(RCC_Settings.Instance.audioMixer, gameObject, engineSoundPosition, "Engine Sound Medium Off AudioSource", 5, 50, 0, engineClipMed, true, true, false);
|
|
engineSoundLowOff = NewAudioSource(RCC_Settings.Instance.audioMixer, gameObject, engineSoundPosition, "Engine Sound Low Off AudioSource", 5, 25, 0, engineClipLow, true, true, false);
|
|
|
|
if (engineSoundHighOff)
|
|
NewLowPassFilter(engineSoundHighOff, 3000f);
|
|
if (engineSoundMedOff)
|
|
NewLowPassFilter(engineSoundMedOff, 3000f);
|
|
if (engineSoundLowOff)
|
|
NewLowPassFilter(engineSoundLowOff, 3000f);
|
|
|
|
} else {
|
|
|
|
engineSoundHighOff = NewAudioSource(RCC_Settings.Instance.audioMixer, gameObject, engineSoundPosition, "Engine Sound High Off AudioSource", 5, 50, 0, engineClipHighOff, true, true, false);
|
|
engineSoundMedOff = NewAudioSource(RCC_Settings.Instance.audioMixer, gameObject, engineSoundPosition, "Engine Sound Medium Off AudioSource", 5, 50, 0, engineClipMedOff, true, true, false);
|
|
engineSoundLowOff = NewAudioSource(RCC_Settings.Instance.audioMixer, gameObject, engineSoundPosition, "Engine Sound Low Off AudioSource", 5, 25, 0, engineClipLowOff, true, true, false);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
engineSoundIdle = NewAudioSource(RCC_Settings.Instance.audioMixer, gameObject, engineSoundPosition, "Engine Sound Idle AudioSource", 5, 25, 0, engineClipIdle, true, true, false);
|
|
reversingSound = NewAudioSource(RCC_Settings.Instance.audioMixer, gameObject, gearSoundPosition, "Reverse Sound AudioSource", 10, 50, 0, ReversingClip, true, false, false);
|
|
windSound = NewAudioSource(RCC_Settings.Instance.audioMixer, gameObject, windSoundPosition, "Wind Sound AudioSource", 1, 10, 0, WindClip, true, true, false);
|
|
brakeSound = NewAudioSource(RCC_Settings.Instance.audioMixer, gameObject, "Brake Sound AudioSource", 1, 10, 0, BrakeClip, true, true, false);
|
|
|
|
if (useNOS)
|
|
NOSSound = NewAudioSource(RCC_Settings.Instance.audioMixer, gameObject, exhaustSoundPosition, "NOS Sound AudioSource", 5, 10, .5f, NOSClip, true, false, false);
|
|
|
|
if (useNOS || useTurbo)
|
|
blowSound = NewAudioSource(RCC_Settings.Instance.audioMixer, gameObject, exhaustSoundPosition, "NOS Blow", 1f, 10f, .5f, null, false, false, false);
|
|
|
|
if (useTurbo) {
|
|
|
|
turboSound = NewAudioSource(RCC_Settings.Instance.audioMixer, gameObject, turboSoundPosition, "Turbo Sound AudioSource", .1f, .5f, 0f, TurboClip, true, true, false);
|
|
NewHighPassFilter(turboSound, 10000f, 10);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Overrides the behavior.
|
|
/// </summary>
|
|
private void CheckBehavior() {
|
|
|
|
// If override is enabled, return.
|
|
if (overrideBehavior)
|
|
return;
|
|
|
|
// If selected behavior is none, return.
|
|
if (RCC_Settings.Instance.selectedBehaviorType == null)
|
|
return;
|
|
|
|
// If any behavior is selected in RCC Settings, override changes.
|
|
SetBehavior(this);
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates the engine torque curve.
|
|
/// </summary>
|
|
public void ReCreateEngineTorqueCurve() {
|
|
|
|
engineTorqueCurve = new AnimationCurve();
|
|
engineTorqueCurve.AddKey(minEngineRPM, maxEngineTorque / 2f); // First index of the curve.
|
|
engineTorqueCurve.AddKey(maxEngineTorqueAtRPM, maxEngineTorque); // Second index of the curve at max.
|
|
engineTorqueCurve.AddKey(maxEngineRPM, maxEngineTorque / 1.5f); // Last index of the curve at maximum RPM.
|
|
|
|
oldEngineTorque = maxEngineTorque;
|
|
oldMaxTorqueAtRPM = maxEngineTorqueAtRPM;
|
|
oldMinEngineRPM = minEngineRPM;
|
|
oldMaxEngineRPM = maxEngineRPM;
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Inits the gears.
|
|
/// </summary>
|
|
public void InitGears() {
|
|
|
|
gears = new Gear[totalGears];
|
|
|
|
float[] gearRatio = new float[gears.Length];
|
|
int[] maxSpeedForGear = new int[gears.Length];
|
|
int[] targetSpeedForGear = new int[gears.Length];
|
|
|
|
if (gears.Length == 1)
|
|
gearRatio = new float[] { 1.0f };
|
|
|
|
if (gears.Length == 2)
|
|
gearRatio = new float[] { 2.0f, 1.0f };
|
|
|
|
if (gears.Length == 3)
|
|
gearRatio = new float[] { 2.0f, 1.5f, 1.0f };
|
|
|
|
if (gears.Length == 4)
|
|
gearRatio = new float[] { 2.86f, 1.62f, 1.0f, .72f };
|
|
|
|
if (gears.Length == 5)
|
|
gearRatio = new float[] { 4.23f, 2.52f, 1.66f, 1.22f, 1.0f, };
|
|
|
|
if (gears.Length == 6)
|
|
gearRatio = new float[] { 4.35f, 2.5f, 1.66f, 1.23f, 1.0f, .85f };
|
|
|
|
if (gears.Length == 7)
|
|
gearRatio = new float[] { 4.5f, 2.5f, 1.66f, 1.23f, 1.0f, .9f, .8f };
|
|
|
|
if (gears.Length == 8)
|
|
gearRatio = new float[] { 4.6f, 2.5f, 1.86f, 1.43f, 1.23f, 1.05f, .9f, .72f };
|
|
|
|
for (int i = 0; i < gears.Length; i++) {
|
|
|
|
maxSpeedForGear[i] = (int)((maxspeed / gears.Length) * (i + 1));
|
|
targetSpeedForGear[i] = (int)(Mathf.Lerp(0, maxspeed * Mathf.Lerp(0f, 1f, gearShiftingThreshold), ((float)(i + 1) / (float)(gears.Length))));
|
|
|
|
}
|
|
|
|
for (int i = 0; i < gears.Length; i++) {
|
|
|
|
gears[i] = new Gear();
|
|
gears[i].SetGear(gearRatio[i], maxSpeedForGear[i], targetSpeedForGear[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Kills or start engine.
|
|
/// </summary>
|
|
public void KillOrStartEngine() {
|
|
|
|
if (engineRunning)
|
|
KillEngine();
|
|
else
|
|
StartEngine();
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Starts the engine.
|
|
/// </summary>
|
|
public void StartEngine() {
|
|
|
|
if (!engineRunning)
|
|
StartCoroutine(StartEngineDelayed());
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Starts the engine.
|
|
/// </summary>
|
|
/// <param name="instantStart">If set to <c>true</c> instant start.</param>
|
|
public void StartEngine(bool instantStart) {
|
|
|
|
if (instantStart) {
|
|
|
|
fuelInput = 1f;
|
|
engineRunning = true;
|
|
|
|
} else {
|
|
|
|
StartCoroutine(StartEngineDelayed());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Starts the engine delayed.
|
|
/// </summary>
|
|
/// <returns>The engine delayed.</returns>
|
|
public IEnumerator StartEngineDelayed() {
|
|
|
|
if (!engineRunning) {
|
|
|
|
engineStartSound = NewAudioSource(RCC_Settings.Instance.audioMixer, gameObject, engineSoundPosition, "Engine Start AudioSource", 1, 10, 1, engineStartClip, false, true, true);
|
|
|
|
yield return new WaitForSeconds(1f);
|
|
|
|
engineRunning = true;
|
|
fuelInput = 1f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Kills the engine.
|
|
/// </summary>
|
|
public void KillEngine() {
|
|
|
|
fuelInput = 0f;
|
|
engineRunning = false;
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Other visuals.
|
|
/// </summary>
|
|
private void OtherVisuals() {
|
|
|
|
//Driver SteeringWheel Transform.
|
|
if (SteeringWheel) {
|
|
|
|
if (orgSteeringWheelRot.eulerAngles == Vector3.zero)
|
|
orgSteeringWheelRot = SteeringWheel.transform.localRotation;
|
|
|
|
switch (steeringWheelRotateAround) {
|
|
|
|
case SteeringWheelRotateAround.XAxis:
|
|
SteeringWheel.transform.localRotation = Quaternion.Lerp(SteeringWheel.transform.localRotation, orgSteeringWheelRot * Quaternion.AngleAxis(((steerInput * steerAngle) * -steeringWheelAngleMultiplier), Vector3.right), Time.deltaTime * 5f);
|
|
break;
|
|
|
|
case SteeringWheelRotateAround.YAxis:
|
|
SteeringWheel.transform.localRotation = Quaternion.Lerp(SteeringWheel.transform.localRotation, orgSteeringWheelRot * Quaternion.AngleAxis(((steerInput * steerAngle) * -steeringWheelAngleMultiplier), Vector3.up), Time.deltaTime * 5f);
|
|
break;
|
|
|
|
case SteeringWheelRotateAround.ZAxis:
|
|
SteeringWheel.transform.localRotation = Quaternion.Lerp(SteeringWheel.transform.localRotation, orgSteeringWheelRot * Quaternion.AngleAxis(((steerInput * steerAngle) * -steeringWheelAngleMultiplier), Vector3.forward), Time.deltaTime * 5f);
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
private void Update() {
|
|
|
|
Inputs();
|
|
Audio();
|
|
CheckReset();
|
|
|
|
if (useDamage) {
|
|
|
|
damage.UpdateRepair();
|
|
damage.UpdateDamage();
|
|
|
|
}
|
|
|
|
OtherVisuals();
|
|
|
|
indicatorTimer += Time.deltaTime;
|
|
|
|
if (throttleInput >= .1f)
|
|
launched += throttleInput * Time.deltaTime;
|
|
else
|
|
launched -= Time.deltaTime;
|
|
|
|
launched = Mathf.Clamp01(launched);
|
|
|
|
float rearSidewaysSlip = RearLeftWheelCollider.wheelSlipAmountSideways + RearRightWheelCollider.wheelSlipAmountSideways;
|
|
rearSidewaysSlip /= 2f;
|
|
|
|
if (Mathf.Abs(rearSidewaysSlip) > .25f)
|
|
driftingNow = true;
|
|
else
|
|
driftingNow = false;
|
|
|
|
driftAngle = rearSidewaysSlip * 1f;
|
|
|
|
}
|
|
|
|
private void FixedUpdate() {
|
|
|
|
Vector3 locVel = transform.InverseTransformDirection(Rigid.angularVelocity);
|
|
|
|
switch (COMAssister) {
|
|
|
|
case COMAssisterTypes.Off:
|
|
locVel *= 0f;
|
|
break;
|
|
|
|
case COMAssisterTypes.Slight:
|
|
locVel /= 10f;
|
|
break;
|
|
|
|
case COMAssisterTypes.Medium:
|
|
locVel /= 5f;
|
|
break;
|
|
|
|
case COMAssisterTypes.Opposite:
|
|
locVel /= -5f;
|
|
break;
|
|
|
|
}
|
|
|
|
// Setting centre of mass.
|
|
Rigid.centerOfMass = new Vector3(COM.localPosition.x + locVel.y, COM.localPosition.y, COM.localPosition.z);
|
|
|
|
//Speed.
|
|
speed = Rigid.velocity.magnitude * 3.6f;
|
|
|
|
if ((autoGenerateEngineRPMCurve) && oldEngineTorque != maxEngineTorque || oldMaxTorqueAtRPM != maxEngineTorqueAtRPM || minEngineRPM != oldMinEngineRPM || maxEngineRPM != oldMaxEngineRPM)
|
|
ReCreateEngineTorqueCurve();
|
|
|
|
if (gears == null || gears.Length == 0) {
|
|
|
|
print("Gear can not be 0! Recreating gears...");
|
|
InitGears();
|
|
|
|
}
|
|
|
|
int currentPoweredWheels = 0;
|
|
|
|
for (int i = 0; i < AllWheelColliders.Length; i++) {
|
|
|
|
if (AllWheelColliders[i].canPower)
|
|
currentPoweredWheels++;
|
|
|
|
}
|
|
|
|
poweredWheels = currentPoweredWheels;
|
|
|
|
Engine();
|
|
Steering();
|
|
Wheels();
|
|
|
|
if (canControl) {
|
|
|
|
if (UseAutomaticClutch)
|
|
AutomaticClutch();
|
|
|
|
if (AutomaticGear)
|
|
AutomaticGearbox();
|
|
|
|
}
|
|
|
|
AntiRollBars();
|
|
CheckGrounded();
|
|
|
|
if (useRevLimiter)
|
|
RevLimiter();
|
|
|
|
if (useTurbo)
|
|
Turbo();
|
|
|
|
if (useNOS)
|
|
NOS();
|
|
|
|
if (useFuelConsumption)
|
|
Fuel();
|
|
|
|
if (useEngineHeat)
|
|
EngineHeat();
|
|
|
|
if (steeringHelper)
|
|
SteerHelper();
|
|
|
|
if (tractionHelper)
|
|
TractionHelper();
|
|
|
|
if (angularDragHelper)
|
|
AngularDragHelper();
|
|
|
|
if (ESP) {
|
|
|
|
ESPCheck();
|
|
|
|
} else {
|
|
|
|
frontSlip = 0f;
|
|
rearSlip = 0f;
|
|
underSteering = false;
|
|
overSteering = false;
|
|
ESPAct = false;
|
|
|
|
}
|
|
|
|
if (!overrideBehavior && RCC_Settings.Instance.selectedBehaviorType != null && RCC_Settings.Instance.selectedBehaviorType.applyRelativeTorque) {
|
|
|
|
// If current selected behavior has apply relative torque enabled, and wheel is grounded, apply it.
|
|
if (isGrounded)
|
|
Rigid.AddRelativeTorque(Vector3.up * (((inputs.steerInput) * direction)) * Mathf.Lerp(2.5f, 2.5f, speed / 200f), ForceMode.Acceleration);
|
|
|
|
}
|
|
|
|
// Applying downforce.
|
|
Rigid.AddForceAtPosition(-transform.up * (Mathf.Clamp(transform.InverseTransformDirection(Rigid.velocity).z, 0f, 300f) * downForce), COM.transform.position, ForceMode.Force);
|
|
|
|
}
|
|
|
|
private void Inputs() {
|
|
|
|
if (canControl) {
|
|
|
|
if (!externalController) {
|
|
|
|
if (!overrideInputs)
|
|
inputs = RCC_InputManager.Instance.inputs;
|
|
|
|
if (!AutomaticGear || semiAutomaticGear) {
|
|
if (!changingGear && !cutGas)
|
|
throttleInput = inputs.throttleInput;
|
|
else
|
|
throttleInput = 0f;
|
|
} else {
|
|
if (!changingGear && !cutGas)
|
|
throttleInput = (direction == 1 ? Mathf.Clamp01(inputs.throttleInput) : Mathf.Clamp01(inputs.brakeInput));
|
|
else
|
|
throttleInput = 0f;
|
|
}
|
|
|
|
if (!AutomaticGear || semiAutomaticGear) {
|
|
brakeInput = Mathf.Clamp01(inputs.brakeInput);
|
|
} else {
|
|
if (!cutGas)
|
|
brakeInput = (direction == 1 ? Mathf.Clamp01(inputs.brakeInput) : Mathf.Clamp01(inputs.throttleInput));
|
|
else
|
|
brakeInput = 0f;
|
|
}
|
|
|
|
if (useSteeringSensitivity) {
|
|
|
|
bool oppositeDirection = Mathf.Sign(inputs.steerInput) != Mathf.Sign(steerInput) ? true : false;
|
|
steerInput = Mathf.MoveTowards(steerInput, inputs.steerInput + counterSteerInput, (Time.deltaTime * steeringSensitivityFactor * Mathf.Lerp(10f, 5f, steerAngle / orgSteerAngle)) * (oppositeDirection ? 1f : 1f));
|
|
|
|
} else {
|
|
steerInput = inputs.steerInput + counterSteerInput;
|
|
}
|
|
|
|
SteeringAssistance();
|
|
|
|
boostInput = inputs.boostInput;
|
|
handbrakeInput = inputs.handbrakeInput;
|
|
|
|
if (RCC_InputManager.Instance.logitechHShifterUsed) {
|
|
|
|
currentGear = inputs.gearInput;
|
|
|
|
if (currentGear == -1) {
|
|
|
|
currentGear = 0;
|
|
direction = -1;
|
|
|
|
} else {
|
|
|
|
direction = 1;
|
|
|
|
}
|
|
|
|
if (currentGear == -2) {
|
|
|
|
currentGear = 0;
|
|
NGear = true;
|
|
|
|
} else {
|
|
|
|
NGear = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!UseAutomaticClutch) {
|
|
|
|
if (!NGear)
|
|
clutchInput = inputs.clutchInput;
|
|
else
|
|
clutchInput = 1f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (!externalController) {
|
|
|
|
throttleInput = 0f;
|
|
brakeInput = 0f;
|
|
steerInput = 0f;
|
|
boostInput = 0f;
|
|
handbrakeInput = 1f;
|
|
|
|
}
|
|
|
|
if (fuelInput <= 0f) {
|
|
|
|
throttleInput = 0f;
|
|
engineRunning = false;
|
|
|
|
}
|
|
|
|
if (changingGear || cutGas)
|
|
throttleInput = 0f;
|
|
|
|
if (!useNOS || NoS < 5 || throttleInput < .75f)
|
|
boostInput = 0f;
|
|
|
|
throttleInput = Mathf.Clamp01(throttleInput);
|
|
brakeInput = Mathf.Clamp01(brakeInput);
|
|
steerInput = Mathf.Clamp(steerInput, -1f, 1f);
|
|
boostInput = Mathf.Clamp01(boostInput);
|
|
handbrakeInput = Mathf.Clamp01(handbrakeInput);
|
|
|
|
if (RCC_InputManager.Instance.logitechSteeringUsed) {
|
|
|
|
steeringType = SteeringType.Constant;
|
|
useSteeringLimiter = false;
|
|
useSteeringSensitivity = false;
|
|
useCounterSteering = false;
|
|
|
|
}
|
|
|
|
//Auto Reverse Bool.
|
|
if (AutoReverse) {
|
|
|
|
canGoReverseNow = true;
|
|
|
|
} else {
|
|
|
|
if (brakeInput < .5f && speed < 5)
|
|
canGoReverseNow = true;
|
|
else if (brakeInput > 0 && transform.InverseTransformDirection(Rigid.velocity).z > 1f)
|
|
canGoReverseNow = false;
|
|
|
|
}
|
|
|
|
if (AutomaticGear && !semiAutomaticGear && !changingGear && !RCC_InputManager.Instance.logitechHShifterUsed) {
|
|
|
|
//Reversing Bool.
|
|
if (brakeInput > .9f && transform.InverseTransformDirection(Rigid.velocity).z < 1f && canGoReverseNow && direction != -1)
|
|
StartCoroutine(ChangeGear(-1));
|
|
else if (throttleInput < .1f && transform.InverseTransformDirection(Rigid.velocity).z > -1f && direction == -1)
|
|
StartCoroutine(ChangeGear(0));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
private void SteeringAssistance() {
|
|
|
|
float sidewaysSlip = 0f; // Total sideways slip of all wheels.
|
|
|
|
foreach (RCC_WheelCollider w in AllWheelColliders)
|
|
sidewaysSlip += w.wheelSlipAmountSideways;
|
|
|
|
sidewaysSlip /= AllWheelColliders.Length;
|
|
|
|
if (useSteeringLimiter) {
|
|
|
|
float maxSteerInput = Mathf.Clamp(1f - Mathf.Abs(sidewaysSlip), -1f, 1f); // Subtract total average sideways slip from max steer input (1f).;
|
|
float sign = -Mathf.Sign(sidewaysSlip); // Is sideways slip is left or right?
|
|
|
|
// If slip is high enough, apply counter input.
|
|
if (maxSteerInput > 0f)
|
|
steerInput = Mathf.Clamp(steerInput, -maxSteerInput, maxSteerInput);
|
|
else
|
|
steerInput = Mathf.Clamp(steerInput, sign * maxSteerInput, sign * maxSteerInput);
|
|
|
|
}
|
|
|
|
if (useCounterSteering)
|
|
counterSteerInput = counterSteeringFactor * driftAngle;
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Engine.
|
|
/// </summary>
|
|
private void Engine() {
|
|
|
|
float tractionRPM = 0;
|
|
|
|
for (int i = 0; i < AllWheelColliders.Length; i++) {
|
|
|
|
if (AllWheelColliders[i].canPower)
|
|
tractionRPM += Mathf.Abs(AllWheelColliders[i].WheelCollider.rpm);
|
|
|
|
}
|
|
|
|
float velocity = 0f;
|
|
float newEngineInertia = engineInertia + (clutchInput / 5f * engineInertia);
|
|
newEngineInertia *= Mathf.Lerp(1f, Mathf.Clamp(clutchInput, .75f, 1f), engineRPM / maxEngineRPM);
|
|
|
|
engineRPMRaw = Mathf.SmoothDamp(engineRPMRaw, (Mathf.Lerp(minEngineRPM, maxEngineRPM + 500f, (clutchInput * throttleInput)) +
|
|
((tractionRPM / Mathf.Clamp(poweredWheels, 1, Mathf.Infinity)) *
|
|
finalRatio * (gears[currentGear].maxRatio)) * (1f - clutchInput)) *
|
|
fuelInput, ref velocity, newEngineInertia * .75f);
|
|
|
|
engineRPMRaw = Mathf.Clamp(engineRPMRaw, 0f, maxEngineRPM + 500f);
|
|
|
|
engineRPM = Mathf.Lerp(engineRPM, engineRPMRaw, Time.fixedDeltaTime * Mathf.Clamp(1f - clutchInput, .25f, 1f) * 25f);
|
|
|
|
}
|
|
|
|
private void Steering() {
|
|
|
|
switch (steeringType) {
|
|
|
|
case SteeringType.Curve:
|
|
steerAngle = steerAngleCurve.Evaluate(speed);
|
|
break;
|
|
|
|
case SteeringType.Simple:
|
|
steerAngle = Mathf.Lerp(orgSteerAngle, highspeedsteerAngle, (speed / highspeedsteerAngleAtspeed));
|
|
break;
|
|
|
|
case SteeringType.Constant:
|
|
steerAngle = orgSteerAngle;
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Audio.
|
|
/// </summary>
|
|
private void Audio() {
|
|
|
|
EngineSounds();
|
|
|
|
windSound.volume = Mathf.Lerp(0f, RCC_Settings.Instance.maxWindSoundVolume, speed / 300f);
|
|
windSound.pitch = UnityEngine.Random.Range(.9f, 1f);
|
|
|
|
if (direction == 1)
|
|
brakeSound.volume = Mathf.Lerp(0f, RCC_Settings.Instance.maxBrakeSoundVolume, Mathf.Clamp01((FrontLeftWheelCollider.WheelCollider.brakeTorque + FrontRightWheelCollider.WheelCollider.brakeTorque) / (brakeTorque * 2f)) * Mathf.Lerp(0f, 1f, FrontLeftWheelCollider.WheelCollider.rpm / 50f));
|
|
else
|
|
brakeSound.volume = 0f;
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks the ESP.
|
|
/// </summary>
|
|
private void ESPCheck() {
|
|
|
|
if (ESPBroken) {
|
|
|
|
frontSlip = 0f;
|
|
rearSlip = 0f;
|
|
underSteering = false;
|
|
overSteering = false;
|
|
ESPAct = false;
|
|
return;
|
|
|
|
}
|
|
|
|
frontSlip = FrontLeftWheelCollider.wheelSlipAmountSideways + FrontRightWheelCollider.wheelSlipAmountSideways;
|
|
rearSlip = RearLeftWheelCollider.wheelSlipAmountSideways + RearRightWheelCollider.wheelSlipAmountSideways;
|
|
|
|
if (Mathf.Abs(frontSlip) >= ESPThreshold)
|
|
underSteering = true;
|
|
else
|
|
underSteering = false;
|
|
|
|
if (Mathf.Abs(rearSlip) >= ESPThreshold)
|
|
overSteering = true;
|
|
else
|
|
overSteering = false;
|
|
|
|
if (overSteering || underSteering)
|
|
ESPAct = true;
|
|
else
|
|
ESPAct = false;
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Engine sounds.
|
|
/// </summary>
|
|
private void EngineSounds() {
|
|
|
|
float lowRPM, medRPM, highRPM;
|
|
|
|
if (engineRPM < ((maxEngineRPM) / 2f))
|
|
lowRPM = Mathf.Lerp(0f, 1f, engineRPM / ((maxEngineRPM) / 2f));
|
|
else
|
|
lowRPM = Mathf.Lerp(1f, .25f, engineRPM / maxEngineRPM);
|
|
|
|
if (engineRPM < ((maxEngineRPM) / 2f))
|
|
medRPM = Mathf.Lerp(-.5f, 1f, engineRPM / ((maxEngineRPM) / 2f));
|
|
else
|
|
medRPM = Mathf.Lerp(1f, .5f, engineRPM / maxEngineRPM);
|
|
|
|
highRPM = Mathf.Lerp(-1f, 1f, engineRPM / maxEngineRPM);
|
|
|
|
lowRPM = Mathf.Clamp01(lowRPM) * maxEngineSoundVolume;
|
|
medRPM = Mathf.Clamp01(medRPM) * maxEngineSoundVolume;
|
|
highRPM = Mathf.Clamp01(highRPM) * maxEngineSoundVolume;
|
|
|
|
float volumeLevel = Mathf.Clamp(throttleInput, 0f, 1f);
|
|
float pitchLevel = Mathf.Lerp(minEngineSoundPitch, maxEngineSoundPitch, engineRPM / maxEngineRPM) * (engineRunning ? 1f : 0f);
|
|
|
|
switch (audioType) {
|
|
|
|
case AudioType.OneSource:
|
|
|
|
engineSoundHigh.volume = volumeLevel * maxEngineSoundVolume;
|
|
engineSoundHigh.pitch = pitchLevel;
|
|
|
|
engineSoundHighOff.volume = (1f - volumeLevel) * maxEngineSoundVolume;
|
|
engineSoundHighOff.pitch = pitchLevel;
|
|
|
|
if (engineSoundIdle) {
|
|
|
|
engineSoundIdle.volume = Mathf.Lerp(engineRunning ? idleEngineSoundVolume : 0f, 0f, engineRPM / maxEngineRPM);
|
|
engineSoundIdle.pitch = pitchLevel;
|
|
|
|
}
|
|
|
|
if (!engineSoundHigh.isPlaying)
|
|
engineSoundHigh.Play();
|
|
if (!engineSoundIdle.isPlaying)
|
|
engineSoundIdle.Play();
|
|
|
|
break;
|
|
|
|
case AudioType.TwoSource:
|
|
|
|
engineSoundHigh.volume = highRPM * volumeLevel;
|
|
engineSoundHigh.pitch = pitchLevel;
|
|
engineSoundLow.volume = lowRPM * volumeLevel;
|
|
engineSoundLow.pitch = pitchLevel;
|
|
|
|
engineSoundHighOff.volume = highRPM * (1f - volumeLevel);
|
|
engineSoundHighOff.pitch = pitchLevel;
|
|
engineSoundLowOff.volume = lowRPM * (1f - volumeLevel);
|
|
engineSoundLowOff.pitch = pitchLevel;
|
|
|
|
if (engineSoundIdle) {
|
|
|
|
engineSoundIdle.volume = Mathf.Lerp(engineRunning ? idleEngineSoundVolume : 0f, 0f, engineRPM / maxEngineRPM);
|
|
engineSoundIdle.pitch = pitchLevel;
|
|
|
|
}
|
|
|
|
if (!engineSoundLow.isPlaying)
|
|
engineSoundLow.Play();
|
|
if (!engineSoundHigh.isPlaying)
|
|
engineSoundHigh.Play();
|
|
if (!engineSoundIdle.isPlaying)
|
|
engineSoundIdle.Play();
|
|
|
|
break;
|
|
|
|
case AudioType.ThreeSource:
|
|
|
|
engineSoundHigh.volume = highRPM * volumeLevel;
|
|
engineSoundHigh.pitch = pitchLevel;
|
|
engineSoundMed.volume = medRPM * volumeLevel;
|
|
engineSoundMed.pitch = pitchLevel;
|
|
engineSoundLow.volume = lowRPM * volumeLevel;
|
|
engineSoundLow.pitch = pitchLevel;
|
|
|
|
engineSoundHighOff.volume = highRPM * (1f - volumeLevel);
|
|
engineSoundHighOff.pitch = pitchLevel;
|
|
engineSoundMedOff.volume = medRPM * (1f - volumeLevel);
|
|
engineSoundMedOff.pitch = pitchLevel;
|
|
engineSoundLowOff.volume = lowRPM * (1f - volumeLevel);
|
|
engineSoundLowOff.pitch = pitchLevel;
|
|
|
|
if (engineSoundIdle) {
|
|
|
|
engineSoundIdle.volume = Mathf.Lerp(engineRunning ? idleEngineSoundVolume : 0f, 0f, engineRPM / maxEngineRPM);
|
|
engineSoundIdle.pitch = pitchLevel;
|
|
|
|
}
|
|
|
|
if (!engineSoundLow.isPlaying)
|
|
engineSoundLow.Play();
|
|
if (!engineSoundMed.isPlaying)
|
|
engineSoundMed.Play();
|
|
if (!engineSoundHigh.isPlaying)
|
|
engineSoundHigh.Play();
|
|
if (!engineSoundIdle.isPlaying)
|
|
engineSoundIdle.Play();
|
|
|
|
break;
|
|
|
|
case AudioType.Off:
|
|
|
|
if (engineSoundHigh) {
|
|
|
|
engineSoundHigh.volume = 0f;
|
|
engineSoundHigh.pitch = 1f;
|
|
|
|
}
|
|
|
|
if (engineSoundMed) {
|
|
|
|
engineSoundMed.volume = 0f;
|
|
engineSoundMed.pitch = 1f;
|
|
|
|
}
|
|
|
|
if (engineSoundLow) {
|
|
|
|
engineSoundLow.volume = 0f;
|
|
engineSoundLow.pitch = 1f;
|
|
|
|
}
|
|
|
|
if (engineSoundHighOff) {
|
|
|
|
engineSoundHighOff.volume = 0f;
|
|
engineSoundHighOff.pitch = 1f;
|
|
|
|
}
|
|
|
|
if (engineSoundMedOff) {
|
|
|
|
engineSoundMedOff.volume = 0f;
|
|
engineSoundMedOff.pitch = 1f;
|
|
|
|
}
|
|
|
|
if (engineSoundLowOff) {
|
|
|
|
engineSoundLowOff.volume = 0f;
|
|
engineSoundLowOff.pitch = 1f;
|
|
|
|
}
|
|
|
|
if (engineSoundIdle) {
|
|
|
|
engineSoundIdle.volume = 0f;
|
|
engineSoundIdle.pitch = 1f;
|
|
|
|
}
|
|
|
|
if (engineSoundLow && engineSoundLow.isPlaying)
|
|
engineSoundLow.Stop();
|
|
if (engineSoundMed && engineSoundMed.isPlaying)
|
|
engineSoundMed.Stop();
|
|
if (engineSoundHigh && engineSoundHigh.isPlaying)
|
|
engineSoundHigh.Stop();
|
|
if (engineSoundIdle && engineSoundIdle.isPlaying)
|
|
engineSoundIdle.Stop();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
private void Wheels() {
|
|
|
|
for (int i = 0; i < AllWheelColliders.Length; i++) {
|
|
|
|
if (AllWheelColliders[i].canPower)
|
|
AllWheelColliders[i].ApplyMotorTorque((direction * AllWheelColliders[i].powerMultiplier * (1f - clutchInput) * throttleInput * (1f + boostInput) * (engineTorqueCurve.Evaluate(engineRPM) * gears[currentGear].maxRatio * finalRatio)) / Mathf.Clamp(poweredWheels, 1, Mathf.Infinity));
|
|
|
|
if (AllWheelColliders[i].canSteer)
|
|
AllWheelColliders[i].ApplySteering(steerInput * AllWheelColliders[i].steeringMultiplier, steerAngle);
|
|
|
|
bool appliedBrake = false;
|
|
|
|
if (!appliedBrake && handbrakeInput > .5f) {
|
|
|
|
appliedBrake = true;
|
|
|
|
if (AllWheelColliders[i].canHandbrake)
|
|
AllWheelColliders[i].ApplyBrakeTorque((brakeTorque * handbrakeInput) * AllWheelColliders[i].handbrakeMultiplier);
|
|
|
|
}
|
|
|
|
if (!appliedBrake && brakeInput >= .05f) {
|
|
|
|
appliedBrake = true;
|
|
|
|
if (AllWheelColliders[i].canBrake)
|
|
AllWheelColliders[i].ApplyBrakeTorque((brakeInput * brakeTorque) * AllWheelColliders[i].brakingMultiplier);
|
|
|
|
}
|
|
|
|
if (ESPAct)
|
|
appliedBrake = true;
|
|
|
|
if (!appliedBrake)
|
|
AllWheelColliders[i].ApplyBrakeTorque(0f);
|
|
|
|
// Checking all wheels. If one of them is not powered, reset.
|
|
if (!AllWheelColliders[i].canPower)
|
|
AllWheelColliders[i].ApplyMotorTorque(0f);
|
|
if (!AllWheelColliders[i].canBrake)
|
|
AllWheelColliders[i].ApplyBrakeTorque(0f);
|
|
if (!AllWheelColliders[i].canSteer)
|
|
AllWheelColliders[i].ApplySteering(0f, 0f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Antiroll bars.
|
|
/// </summary>
|
|
private void AntiRollBars() {
|
|
|
|
#region Horizontal
|
|
|
|
float travelFL = 1f;
|
|
float travelFR = 1f;
|
|
|
|
bool groundedFL = FrontLeftWheelCollider.isGrounded;
|
|
|
|
if (groundedFL)
|
|
travelFL = (-FrontLeftWheelCollider.transform.InverseTransformPoint(FrontLeftWheelCollider.wheelHit.point).y - FrontLeftWheelCollider.WheelCollider.radius) / FrontLeftWheelCollider.WheelCollider.suspensionDistance;
|
|
|
|
bool groundedFR = FrontRightWheelCollider.isGrounded;
|
|
|
|
if (groundedFR)
|
|
travelFR = (-FrontRightWheelCollider.transform.InverseTransformPoint(FrontRightWheelCollider.wheelHit.point).y - FrontRightWheelCollider.WheelCollider.radius) / FrontRightWheelCollider.WheelCollider.suspensionDistance;
|
|
|
|
float antiRollForceFrontHorizontal = (travelFL - travelFR) * antiRollFrontHorizontal;
|
|
|
|
if (FrontLeftWheelCollider.isActiveAndEnabled && FrontRightWheelCollider.isActiveAndEnabled) {
|
|
|
|
if (groundedFL)
|
|
Rigid.AddForceAtPosition(FrontLeftWheelCollider.transform.up * -antiRollForceFrontHorizontal, FrontLeftWheelCollider.transform.position);
|
|
if (groundedFR)
|
|
Rigid.AddForceAtPosition(FrontRightWheelCollider.transform.up * antiRollForceFrontHorizontal, FrontRightWheelCollider.transform.position);
|
|
|
|
}
|
|
|
|
float travelRL = 1f;
|
|
float travelRR = 1f;
|
|
|
|
bool groundedRL = RearLeftWheelCollider.isGrounded;
|
|
|
|
if (groundedRL)
|
|
travelRL = (-RearLeftWheelCollider.transform.InverseTransformPoint(RearLeftWheelCollider.wheelHit.point).y - RearLeftWheelCollider.WheelCollider.radius) / RearLeftWheelCollider.WheelCollider.suspensionDistance;
|
|
|
|
bool groundedRR = RearRightWheelCollider.isGrounded;
|
|
|
|
if (groundedRR)
|
|
travelRR = (-RearRightWheelCollider.transform.InverseTransformPoint(RearRightWheelCollider.wheelHit.point).y - RearRightWheelCollider.WheelCollider.radius) / RearRightWheelCollider.WheelCollider.suspensionDistance;
|
|
|
|
float antiRollForceRearHorizontal = (travelRL - travelRR) * antiRollRearHorizontal;
|
|
|
|
if (RearLeftWheelCollider.isActiveAndEnabled && RearRightWheelCollider.isActiveAndEnabled) {
|
|
|
|
if (groundedRL)
|
|
Rigid.AddForceAtPosition(RearLeftWheelCollider.transform.up * -antiRollForceRearHorizontal, RearLeftWheelCollider.transform.position);
|
|
if (groundedRR)
|
|
Rigid.AddForceAtPosition(RearRightWheelCollider.transform.up * antiRollForceRearHorizontal, RearRightWheelCollider.transform.position);
|
|
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Vertical
|
|
|
|
float antiRollForceFrontVertical = (travelFL - travelRL) * antiRollVertical;
|
|
|
|
if (FrontLeftWheelCollider.isActiveAndEnabled && RearLeftWheelCollider.isActiveAndEnabled) {
|
|
|
|
if (groundedFL)
|
|
Rigid.AddForceAtPosition(FrontLeftWheelCollider.transform.up * -antiRollForceFrontVertical, FrontLeftWheelCollider.transform.position);
|
|
if (groundedRL)
|
|
Rigid.AddForceAtPosition(RearLeftWheelCollider.transform.up * antiRollForceFrontVertical, RearLeftWheelCollider.transform.position);
|
|
|
|
}
|
|
|
|
float antiRollForceRearVertical = (travelFR - travelRR) * antiRollVertical;
|
|
|
|
if (FrontRightWheelCollider.isActiveAndEnabled && RearRightWheelCollider.isActiveAndEnabled) {
|
|
|
|
if (groundedFR)
|
|
Rigid.AddForceAtPosition(FrontRightWheelCollider.transform.up * -antiRollForceRearVertical, FrontRightWheelCollider.transform.position);
|
|
if (groundedRR)
|
|
Rigid.AddForceAtPosition(RearRightWheelCollider.transform.up * antiRollForceRearVertical, RearRightWheelCollider.transform.position);
|
|
|
|
}
|
|
|
|
#endregion
|
|
|
|
}
|
|
|
|
private void CheckGrounded() {
|
|
|
|
bool grounded = false;
|
|
|
|
for (int i = 0; i < AllWheelColliders.Length; i++) {
|
|
|
|
if (AllWheelColliders[i].WheelCollider.isGrounded)
|
|
grounded = true;
|
|
|
|
}
|
|
|
|
isGrounded = grounded;
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Steering helper.
|
|
/// </summary>
|
|
private void SteerHelper() {
|
|
|
|
if (!isGrounded)
|
|
return;
|
|
|
|
if (!steeringDirection || !velocityDirection) {
|
|
|
|
if (!steeringDirection) {
|
|
|
|
GameObject steeringDirectionGO = new GameObject("Steering Direction");
|
|
steeringDirectionGO.transform.SetParent(transform, false);
|
|
steeringDirection = steeringDirectionGO.transform;
|
|
steeringDirectionGO.transform.localPosition = new Vector3(1f, 2f, 0f);
|
|
steeringDirectionGO.transform.localScale = new Vector3(.1f, .1f, 3f);
|
|
|
|
}
|
|
|
|
if (!velocityDirection) {
|
|
|
|
GameObject velocityDirectionGO = new GameObject("Velocity Direction");
|
|
velocityDirectionGO.transform.SetParent(transform, false);
|
|
velocityDirection = velocityDirectionGO.transform;
|
|
velocityDirectionGO.transform.localPosition = new Vector3(-1f, 2f, 0f);
|
|
velocityDirectionGO.transform.localScale = new Vector3(.1f, .1f, 3f);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (int i = 0; i < AllWheelColliders.Length; i++) {
|
|
|
|
if (AllWheelColliders[i].wheelHit.point == Vector3.zero)
|
|
return;
|
|
|
|
}
|
|
|
|
Vector3 v = Rigid.angularVelocity;
|
|
velocityAngle = (v.y * Mathf.Clamp(transform.InverseTransformDirection(Rigid.velocity).z, -1f, 1f)) * Mathf.Rad2Deg;
|
|
velocityDirection.localRotation = Quaternion.Lerp(velocityDirection.localRotation, Quaternion.AngleAxis(Mathf.Clamp(velocityAngle / 3f, -45f, 45f), Vector3.up), Time.fixedDeltaTime * 20f);
|
|
steeringDirection.localRotation = Quaternion.Euler(0f, FrontLeftWheelCollider.WheelCollider.steerAngle, 0f);
|
|
|
|
int normalizer;
|
|
|
|
if (steeringDirection.localRotation.y > velocityDirection.localRotation.y)
|
|
normalizer = 1;
|
|
else
|
|
normalizer = -1;
|
|
|
|
float angle2 = Quaternion.Angle(velocityDirection.localRotation, steeringDirection.localRotation) * (normalizer);
|
|
|
|
Rigid.AddRelativeTorque(Vector3.up * ((angle2 * (Mathf.Clamp(transform.InverseTransformDirection(Rigid.velocity).z, -10f, 10f) / 1000f)) * steerHelperAngularVelStrength), ForceMode.VelocityChange);
|
|
|
|
if (Mathf.Abs(oldRotation - transform.eulerAngles.y) < 10f) {
|
|
|
|
float turnadjust = (transform.eulerAngles.y - oldRotation) * (steerHelperLinearVelStrength / 2f);
|
|
Quaternion velRotation = Quaternion.AngleAxis(turnadjust, Vector3.up);
|
|
Rigid.velocity = (velRotation * Rigid.velocity);
|
|
|
|
}
|
|
|
|
oldRotation = transform.eulerAngles.y;
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Traction helper.
|
|
/// </summary>
|
|
private void TractionHelper() {
|
|
|
|
if (!isGrounded)
|
|
return;
|
|
|
|
Vector3 velocity = Rigid.velocity;
|
|
velocity -= transform.up * Vector3.Dot(velocity, transform.up);
|
|
velocity.Normalize();
|
|
|
|
angle = -Mathf.Asin(Vector3.Dot(Vector3.Cross(transform.forward, velocity), transform.up));
|
|
|
|
angularVelo = Rigid.angularVelocity.y;
|
|
|
|
if (angle * FrontLeftWheelCollider.WheelCollider.steerAngle < 0)
|
|
FrontLeftWheelCollider.tractionHelpedSidewaysStiffness = (1f - Mathf.Clamp01(tractionHelperStrength * Mathf.Abs(angularVelo)));
|
|
else
|
|
FrontLeftWheelCollider.tractionHelpedSidewaysStiffness = 1f;
|
|
|
|
if (angle * FrontRightWheelCollider.WheelCollider.steerAngle < 0)
|
|
FrontRightWheelCollider.tractionHelpedSidewaysStiffness = (1f - Mathf.Clamp01(tractionHelperStrength * Mathf.Abs(angularVelo)));
|
|
else
|
|
FrontRightWheelCollider.tractionHelpedSidewaysStiffness = 1f;
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Angular drag helper.
|
|
/// </summary>
|
|
private void AngularDragHelper() {
|
|
|
|
Rigid.angularDrag = Mathf.Lerp(0f, 10f, (speed * angularDragHelperStrength) / 1000f);
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clutch.
|
|
/// </summary>
|
|
private void AutomaticClutch() {
|
|
|
|
if (!UseAutomaticClutch)
|
|
return;
|
|
|
|
float tractionRPM = 0;
|
|
|
|
for (int i = 0; i < AllWheelColliders.Length; i++) {
|
|
|
|
if (AllWheelColliders[i].canPower)
|
|
tractionRPM += Mathf.Abs(AllWheelColliders[i].WheelCollider.rpm);
|
|
|
|
}
|
|
|
|
if (currentGear == 0) {
|
|
|
|
if (launched >= .25f)
|
|
clutchInput = Mathf.Lerp(clutchInput, (Mathf.Lerp(1f, (Mathf.Lerp(clutchInertia, 0f, (tractionRPM / Mathf.Clamp(poweredWheels, 1, Mathf.Infinity)) / gears[0].targetSpeedForNextGear)), Mathf.Abs(throttleInput))), Time.fixedDeltaTime * 20f);
|
|
else
|
|
clutchInput = Mathf.Lerp(clutchInput, 1f / speed, Time.fixedDeltaTime * 20f);
|
|
|
|
} else {
|
|
|
|
if (changingGear)
|
|
clutchInput = Mathf.Lerp(clutchInput, 1, Time.fixedDeltaTime * 20f);
|
|
else
|
|
clutchInput = Mathf.Lerp(clutchInput, 0, Time.fixedDeltaTime * 20f);
|
|
|
|
}
|
|
|
|
if (cutGas || handbrakeInput >= .1f)
|
|
clutchInput = 1f;
|
|
|
|
if (NGear)
|
|
clutchInput = 1f;
|
|
|
|
clutchInput = Mathf.Clamp01(clutchInput);
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gearbox.
|
|
/// </summary>
|
|
private void AutomaticGearbox() {
|
|
|
|
if (!RCC_InputManager.Instance.logitechHShifterUsed) {
|
|
|
|
if (currentGear < gears.Length - 1 && !changingGear) {
|
|
|
|
if (direction == 1 && speed >= gears[currentGear].targetSpeedForNextGear && engineRPM >= gearShiftUpRPM) {
|
|
|
|
if (!semiAutomaticGear)
|
|
StartCoroutine(ChangeGear(currentGear + 1));
|
|
else if (semiAutomaticGear && direction != -1)
|
|
StartCoroutine(ChangeGear(currentGear + 1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (currentGear > 0) {
|
|
|
|
if (!changingGear) {
|
|
|
|
if (direction != -1 && speed < gears[currentGear - 1].targetSpeedForNextGear && engineRPM <= gearShiftDownRPM)
|
|
StartCoroutine(ChangeGear(currentGear - 1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (direction == -1) {
|
|
|
|
if (!reversingSound.isPlaying)
|
|
reversingSound.Play();
|
|
|
|
reversingSound.volume = Mathf.Lerp(0f, 1f, speed / gears[0].maxSpeed);
|
|
reversingSound.pitch = reversingSound.volume;
|
|
|
|
} else {
|
|
|
|
if (reversingSound.isPlaying)
|
|
reversingSound.Stop();
|
|
|
|
reversingSound.volume = 0f;
|
|
reversingSound.pitch = 0f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Changes the gear.
|
|
/// </summary>
|
|
/// <returns>The gear.</returns>
|
|
/// <param name="gear">Gear.</param>
|
|
public IEnumerator ChangeGear(int gear) {
|
|
|
|
changingGear = true;
|
|
|
|
if (RCC_Settings.Instance.useTelemetry)
|
|
print("Shifted to: " + (gear).ToString());
|
|
|
|
if (GearShiftingClips.Length > 0) {
|
|
|
|
gearShiftingSound = NewAudioSource(RCC_Settings.Instance.audioMixer, gameObject, gearSoundPosition, "Gear Shifting AudioSource", 1f, 5f, RCC_Settings.Instance.maxGearShiftingSoundVolume, GearShiftingClips[UnityEngine.Random.Range(0, GearShiftingClips.Length)], false, true, true);
|
|
|
|
if (!gearShiftingSound.isPlaying)
|
|
gearShiftingSound.Play();
|
|
|
|
}
|
|
|
|
yield return new WaitForSeconds(gearShiftingDelay);
|
|
|
|
if (gear == -1) {
|
|
|
|
currentGear = 0;
|
|
|
|
if (!NGear)
|
|
direction = -1;
|
|
else
|
|
direction = 0;
|
|
|
|
} else {
|
|
|
|
currentGear = gear;
|
|
|
|
if (!NGear)
|
|
direction = 1;
|
|
else
|
|
direction = 0;
|
|
|
|
}
|
|
|
|
changingGear = false;
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gears the shift up.
|
|
/// </summary>
|
|
public void GearShiftUp() {
|
|
|
|
if (currentGear < gears.Length - 1 && !changingGear) {
|
|
|
|
if (direction != -1)
|
|
StartCoroutine(ChangeGear(currentGear + 1));
|
|
else
|
|
StartCoroutine(ChangeGear(0));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gears the shift to.
|
|
/// </summary>
|
|
public void GearShiftTo(int gear) {
|
|
|
|
if (gear < -1 || gear >= gears.Length)
|
|
return;
|
|
|
|
if (gear == currentGear)
|
|
return;
|
|
|
|
StartCoroutine(ChangeGear(gear));
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gears the shift down.
|
|
/// </summary>
|
|
public void GearShiftDown() {
|
|
|
|
if (currentGear >= 0)
|
|
StartCoroutine(ChangeGear(currentGear - 1));
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rev limiter.
|
|
/// </summary>
|
|
private void RevLimiter() {
|
|
|
|
if ((engineRPM >= maxEngineRPM))
|
|
cutGas = true;
|
|
else if (engineRPM < (maxEngineRPM * .975f))
|
|
cutGas = false;
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// NOS.
|
|
/// </summary>
|
|
private void NOS() {
|
|
|
|
if (!NOSSound)
|
|
NOSSound = NewAudioSource(RCC_Settings.Instance.audioMixer, gameObject, exhaustSoundPosition, "NOS Sound AudioSource", 5f, 10f, .5f, NOSClip, true, false, false);
|
|
|
|
if (!blowSound)
|
|
blowSound = NewAudioSource(RCC_Settings.Instance.audioMixer, gameObject, exhaustSoundPosition, "NOS Blow", 1f, 10f, .5f, null, false, false, false);
|
|
|
|
if (boostInput >= .8f && throttleInput >= .8f && NoS > 5) {
|
|
|
|
NoS -= NoSConsumption * Time.fixedDeltaTime;
|
|
NoSRegenerateTime = 0f;
|
|
|
|
if (!NOSSound.isPlaying)
|
|
NOSSound.Play();
|
|
|
|
} else {
|
|
|
|
if (NoS < 100 && NoSRegenerateTime >= 3)
|
|
NoS += (NoSConsumption / 1.5f) * Time.fixedDeltaTime;
|
|
|
|
NoSRegenerateTime += Time.fixedDeltaTime;
|
|
|
|
if (NOSSound.isPlaying) {
|
|
|
|
NOSSound.Stop();
|
|
blowSound.clip = BlowClip[UnityEngine.Random.Range(0, BlowClip.Length)];
|
|
blowSound.Play();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Turbo.
|
|
/// </summary>
|
|
private void Turbo() {
|
|
|
|
if (!turboSound) {
|
|
|
|
turboSound = NewAudioSource(RCC_Settings.Instance.audioMixer, gameObject, turboSoundPosition, "Turbo Sound AudioSource", .1f, .5f, 0, TurboClip, true, true, false);
|
|
NewHighPassFilter(turboSound, 10000f, 10);
|
|
|
|
}
|
|
|
|
turboBoost = Mathf.Lerp(turboBoost, Mathf.Clamp(Mathf.Pow(throttleInput, 10) * 30f + Mathf.Pow(engineRPM / maxEngineRPM, 10) * 30f, 0f, 30f), Time.fixedDeltaTime * 10f);
|
|
|
|
if (turboBoost >= 25f) {
|
|
|
|
if (turboBoost < (turboSound.volume * 30f)) {
|
|
|
|
if (!blowSound.isPlaying) {
|
|
|
|
blowSound.clip = RCC_Settings.Instance.blowoutClip[UnityEngine.Random.Range(0, RCC_Settings.Instance.blowoutClip.Length)];
|
|
blowSound.Play();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
turboSound.volume = Mathf.Lerp(turboSound.volume, turboBoost / 30f, Time.fixedDeltaTime * 5f);
|
|
turboSound.pitch = Mathf.Lerp(Mathf.Clamp(turboSound.pitch, 2f, 3f), (turboBoost / 30f) * 2f, Time.fixedDeltaTime * 5f);
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fuel.
|
|
/// </summary>
|
|
private void Fuel() {
|
|
|
|
fuelTank -= ((engineRPM / 10000f) * fuelConsumptionRate) * Time.fixedDeltaTime;
|
|
fuelTank = Mathf.Clamp(fuelTank, 0f, fuelTankCapacity);
|
|
|
|
if (fuelTank <= 0f)
|
|
fuelInput = 0f;
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Engine heat.
|
|
/// </summary>
|
|
private void EngineHeat() {
|
|
|
|
engineHeat += ((engineRPM / 10000f) * engineHeatRate) * Time.fixedDeltaTime;
|
|
|
|
if (engineHeat > engineCoolingWaterThreshold)
|
|
engineHeat -= engineCoolRate * Time.fixedDeltaTime;
|
|
|
|
engineHeat -= (engineCoolRate / 10f) * Time.fixedDeltaTime;
|
|
|
|
engineHeat = Mathf.Clamp(engineHeat, 15f, 120f);
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Resets the car.
|
|
/// </summary>
|
|
private void CheckReset() {
|
|
|
|
if (!RCC_Settings.Instance.autoReset)
|
|
return;
|
|
|
|
if (speed < 5 && !Rigid.isKinematic) {
|
|
|
|
if (transform.eulerAngles.z < 300 && transform.eulerAngles.z > 60) {
|
|
|
|
resetTime += Time.deltaTime;
|
|
|
|
if (resetTime > 3) {
|
|
|
|
transform.rotation = Quaternion.Euler(0f, transform.eulerAngles.y, 0f);
|
|
transform.position = new Vector3(transform.position.x, transform.position.y + 3, transform.position.z);
|
|
resetTime = 0f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Raises the collision enter event.
|
|
/// </summary>
|
|
/// <param name="collision">Collision.</param>
|
|
private void OnCollisionEnter(Collision collision) {
|
|
|
|
if (collision.contactCount < 1)
|
|
return;
|
|
|
|
if (collision.relativeVelocity.magnitude < 5)
|
|
return;
|
|
|
|
if (OnRCCPlayerCollision != null && this == RCC_SceneManager.Instance.activePlayerVehicle)
|
|
OnRCCPlayerCollision(this, collision);
|
|
|
|
if (((1 << collision.gameObject.layer) & damage.damageFilter) != 0) {
|
|
|
|
if (useDamage) {
|
|
|
|
if (!damage.carController)
|
|
damage.Initialize(this);
|
|
|
|
damage.OnCollision(collision);
|
|
|
|
}
|
|
|
|
if (useCollisionAudio) {
|
|
|
|
if (CrashClips.Length > 0) {
|
|
|
|
crashSound = NewAudioSource(RCC_Settings.Instance.audioMixer, gameObject, "Crash Sound AudioSource", 5f, 20f, RCC_Settings.Instance.maxCrashSoundVolume * (collision.impulse.magnitude / 10000f), CrashClips[UnityEngine.Random.Range(0, CrashClips.Length)], false, true, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (useCollisionParticles) {
|
|
|
|
// Particle System used for collision effects. Creating it at start. We will use this when we collide something.
|
|
if (contactSparkle && contactSparkeList.Count < 1) {
|
|
|
|
for (int i = 0; i < maximumContactSparkle; i++) {
|
|
|
|
GameObject sparks = Instantiate(contactSparkle, transform.position, Quaternion.identity);
|
|
sparks.transform.SetParent(allContactParticles.transform);
|
|
contactSparkeList.Add(sparks.GetComponent<ParticleSystem>());
|
|
ParticleSystem.EmissionModule em = sparks.GetComponent<ParticleSystem>().emission;
|
|
em.enabled = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (int i = 0; i < contactSparkeList.Count; i++) {
|
|
|
|
if (!contactSparkeList[i].isPlaying) {
|
|
|
|
contactSparkeList[i].transform.position = collision.GetContact(0).point;
|
|
ParticleSystem.EmissionModule em = contactSparkeList[i].emission;
|
|
em.rateOverTimeMultiplier = collision.impulse.magnitude / 500f;
|
|
em.enabled = true;
|
|
contactSparkeList[i].Play();
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
private void OnCollisionStay(Collision collision) {
|
|
|
|
if (collision.contactCount < 1 || collision.relativeVelocity.magnitude < 2f) {
|
|
|
|
if (scratchSparkeList != null) {
|
|
|
|
for (int i = 0; i < scratchSparkeList.Count; i++) {
|
|
|
|
ParticleSystem.EmissionModule em = scratchSparkeList[i].emission;
|
|
em.enabled = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (((1 << collision.gameObject.layer) & damage.damageFilter) != 0) {
|
|
|
|
if (useCollisionParticles) {
|
|
|
|
// Particle System used for collision effects. Creating it at start. We will use this when we collide something.
|
|
if (scratchSparkle && scratchSparkeList.Count < 1) {
|
|
|
|
for (int i = 0; i < maximumContactSparkle; i++) {
|
|
|
|
GameObject sparks = Instantiate(scratchSparkle, transform.position, Quaternion.identity);
|
|
sparks.transform.SetParent(allContactParticles.transform);
|
|
scratchSparkeList.Add(sparks.GetComponent<ParticleSystem>());
|
|
ParticleSystem.EmissionModule em = sparks.GetComponent<ParticleSystem>().emission;
|
|
em.enabled = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ContactPoint[] contacts = new ContactPoint[collision.contactCount];
|
|
collision.GetContacts(contacts);
|
|
|
|
int ind = -1;
|
|
|
|
foreach (ContactPoint cp in contacts) {
|
|
|
|
ind++;
|
|
|
|
if (ind < scratchSparkeList.Count && !scratchSparkeList[ind].isPlaying) {
|
|
|
|
scratchSparkeList[ind].transform.position = cp.point;
|
|
ParticleSystem.EmissionModule em = scratchSparkeList[ind].emission;
|
|
em.enabled = true;
|
|
em.rateOverTimeMultiplier = collision.relativeVelocity.magnitude / 1f;
|
|
scratchSparkeList[ind].Play();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
private void OnCollisionExit(Collision collision) {
|
|
|
|
for (int i = 0; i < scratchSparkeList.Count; i++) {
|
|
|
|
ParticleSystem.EmissionModule em = scratchSparkeList[i].emission;
|
|
em.enabled = false;
|
|
scratchSparkeList[i].Stop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Raises the draw gizmos event.
|
|
/// </summary>
|
|
private void OnDrawGizmos() {
|
|
#if UNITY_EDITOR
|
|
if (Application.isPlaying) {
|
|
|
|
WheelHit hit;
|
|
|
|
for (int i = 0; i < AllWheelColliders.Length; i++) {
|
|
|
|
AllWheelColliders[i].WheelCollider.GetGroundHit(out hit);
|
|
|
|
Matrix4x4 temp = Gizmos.matrix;
|
|
Gizmos.matrix = Matrix4x4.TRS(AllWheelColliders[i].transform.position, Quaternion.AngleAxis(-90, Vector3.right), Vector3.one);
|
|
Gizmos.color = new Color((hit.force / Rigid.mass) / 5f, (-hit.force / Rigid.mass) / 5f, 0f);
|
|
Gizmos.DrawFrustum(Vector3.zero, 2f, hit.force / Rigid.mass, .1f, 1f);
|
|
Gizmos.matrix = temp;
|
|
|
|
}
|
|
|
|
//Gizmos.DrawSphere(transform.TransformPoint(Rigid.centerOfMass), .15f);
|
|
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// Previews the smoke particle.
|
|
/// </summary>
|
|
/// <param name="state">If set to <c>true</c> state.</param>
|
|
public void PreviewSmokeParticle(bool state) {
|
|
|
|
canControl = state;
|
|
permanentGas = state;
|
|
Rigid.isKinematic = state;
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Detachs the trailer.
|
|
/// </summary>
|
|
public void DetachTrailer() {
|
|
|
|
if (!attachedTrailer)
|
|
return;
|
|
|
|
attachedTrailer.DetachTrailer();
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Raises the destroy event.
|
|
/// </summary>
|
|
private void OnDestroy() {
|
|
|
|
if (OnRCCPlayerDestroyed != null)
|
|
OnRCCPlayerDestroyed(this);
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the can control.
|
|
/// </summary>
|
|
/// <param name="state">If set to <c>true</c> state.</param>
|
|
public void SetCanControl(bool state) {
|
|
|
|
canControl = state;
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the external controller.
|
|
/// </summary>
|
|
/// <param name="state"></param>
|
|
public void SetExternalControl(bool state) {
|
|
|
|
externalController = state;
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the engine state.
|
|
/// </summary>
|
|
/// <param name="state">If set to <c>true</c> state.</param>
|
|
public void SetEngine(bool state) {
|
|
|
|
if (state)
|
|
StartEngine();
|
|
else
|
|
KillEngine();
|
|
|
|
}
|
|
|
|
public void Repair() {
|
|
|
|
damage.repairNow = true;
|
|
|
|
}
|
|
|
|
private void RCC_InputManager_OnTrailerDetach() {
|
|
|
|
if (!canControl || externalController)
|
|
return;
|
|
|
|
DetachTrailer();
|
|
|
|
}
|
|
|
|
private void RCC_InputManager_OnGearShiftDown() {
|
|
|
|
if (!canControl || externalController)
|
|
return;
|
|
|
|
GearShiftDown();
|
|
|
|
}
|
|
|
|
private void RCC_InputManager_OnGearShiftUp() {
|
|
|
|
if (!canControl || externalController)
|
|
return;
|
|
|
|
GearShiftUp();
|
|
|
|
}
|
|
|
|
private void RCC_InputManager_OnNGear(bool state) {
|
|
|
|
if (!canControl || externalController)
|
|
return;
|
|
|
|
NGear = state;
|
|
|
|
}
|
|
|
|
private void RCC_InputManager_OnIndicatorHazard() {
|
|
|
|
if (!canControl || externalController)
|
|
return;
|
|
|
|
if (indicatorsOn != IndicatorsOn.All)
|
|
indicatorsOn = IndicatorsOn.All;
|
|
else
|
|
indicatorsOn = IndicatorsOn.Off;
|
|
|
|
}
|
|
|
|
private void RCC_InputManager_OnIndicatorRight() {
|
|
|
|
if (!canControl || externalController)
|
|
return;
|
|
|
|
if (indicatorsOn != IndicatorsOn.Right)
|
|
indicatorsOn = IndicatorsOn.Right;
|
|
else
|
|
indicatorsOn = IndicatorsOn.Off;
|
|
|
|
}
|
|
|
|
private void RCC_InputManager_OnIndicatorLeft() {
|
|
|
|
if (!canControl || externalController)
|
|
return;
|
|
|
|
if (indicatorsOn != IndicatorsOn.Left)
|
|
indicatorsOn = IndicatorsOn.Left;
|
|
else
|
|
indicatorsOn = IndicatorsOn.Off;
|
|
|
|
}
|
|
|
|
private void RCC_InputManager_OnHighBeamHeadlights() {
|
|
|
|
if (!canControl || externalController)
|
|
return;
|
|
|
|
highBeamHeadLightsOn = !highBeamHeadLightsOn;
|
|
|
|
}
|
|
|
|
private void RCC_InputManager_OnLowBeamHeadlights() {
|
|
|
|
if (!canControl || externalController)
|
|
return;
|
|
|
|
lowBeamHeadLightsOn = !lowBeamHeadLightsOn;
|
|
|
|
}
|
|
|
|
private void OnDisable() {
|
|
|
|
RCC_SceneManager.OnBehaviorChanged -= CheckBehavior;
|
|
|
|
// Listening input events.
|
|
RCC_InputManager.OnLowBeamHeadlights -= RCC_InputManager_OnLowBeamHeadlights;
|
|
RCC_InputManager.OnHighBeamHeadlights -= RCC_InputManager_OnHighBeamHeadlights;
|
|
RCC_InputManager.OnIndicatorLeft -= RCC_InputManager_OnIndicatorLeft;
|
|
RCC_InputManager.OnIndicatorRight -= RCC_InputManager_OnIndicatorRight;
|
|
RCC_InputManager.OnIndicatorHazard -= RCC_InputManager_OnIndicatorHazard;
|
|
RCC_InputManager.OnGearShiftUp -= RCC_InputManager_OnGearShiftUp;
|
|
RCC_InputManager.OnGearShiftDown -= RCC_InputManager_OnGearShiftDown;
|
|
RCC_InputManager.OnNGear -= RCC_InputManager_OnNGear;
|
|
RCC_InputManager.OnTrailerDetach -= RCC_InputManager_OnTrailerDetach;
|
|
|
|
}
|
|
|
|
public void OverrideInputs(RCC_Inputs newInputs) {
|
|
|
|
overrideInputs = true;
|
|
inputs = newInputs;
|
|
|
|
}
|
|
|
|
public void OverrideInputs(RCC_Inputs newInputs, bool enableExternalController) {
|
|
|
|
overrideInputs = true;
|
|
inputs = newInputs;
|
|
externalController = enableExternalController;
|
|
|
|
}
|
|
|
|
public void DisableOverrideInputs() {
|
|
|
|
overrideInputs = false;
|
|
|
|
}
|
|
|
|
public void DisableOverrideInputs(bool disableExternalController) {
|
|
|
|
overrideInputs = false;
|
|
externalController = !disableExternalController;
|
|
|
|
}
|
|
|
|
private void Reset() {
|
|
|
|
Rigidbody rigid = GetComponent<Rigidbody>();
|
|
|
|
if (!rigid)
|
|
rigid = gameObject.AddComponent<Rigidbody>();
|
|
|
|
rigid.mass = RCC_InitialSettings.Instance.mass;
|
|
rigid.drag = RCC_InitialSettings.Instance.drag;
|
|
rigid.angularDrag = RCC_InitialSettings.Instance.angularDrag;
|
|
rigid.interpolation = RCC_InitialSettings.Instance.interpolation;
|
|
|
|
if (transform.Find("COM"))
|
|
DestroyImmediate(transform.Find("COM").gameObject);
|
|
|
|
if (transform.Find("Wheel Colliders"))
|
|
DestroyImmediate(transform.Find("Wheel Colliders").gameObject);
|
|
|
|
GameObject newCOM = new GameObject("COM");
|
|
newCOM.transform.parent = transform;
|
|
newCOM.transform.localPosition = Vector3.zero;
|
|
newCOM.transform.localRotation = Quaternion.identity;
|
|
newCOM.transform.localScale = Vector3.one;
|
|
COM = newCOM.transform;
|
|
|
|
ReCreateEngineTorqueCurve();
|
|
|
|
steerAngleCurve = new AnimationCurve(new Keyframe(0f, 40f, 0f, -.3f), new Keyframe(120f, 10f, -.115f, -.1f), new Keyframe(200f, 7f));
|
|
|
|
}
|
|
|
|
}
|