【unity工程日誌】寫給自己看的CarControl.c#註釋
阿新 • • 發佈:2018-12-31
【寫給自己看的工作日誌7.22】
雖然還是偷了一下懶,沒有去105工作,但是鑑於暑假都過了一半了,而我的VR駕考專案工作還沒有絲毫進展,所以,哪怕呆在宿舍也要努力學習啊!
之前的賽車手遊也要找時間把工作日誌補上了~主要研究了一下WheelCollider,一個很難搞的小傢伙……這兩天就要動手寫啊!千萬不要拖延症啊!!!!
這一篇部落格就拿來炫耀今天工作的進展了~讓一個對車沒有啥印象的人來摸清楚汽車的原理……簡直沒話說……好難啊!!!具體的分析及涉及的知識點之後會進行補充,希望明天的進展能快一點吧……明天主要是CCar.c#以及相機相關的程式碼理解,加上之前紅華給的的羅技盤的一些知識點。
如果可以的話,希望也能空出時間取跑個步……感覺自己越來越胖了……
【PS:下面的內容是根據某個博主的思路來進行理解的……原諒我忘了到底是哪個了,所以這裡就先不轉載了,但還是要感謝他~】
using System;
using UnityEngine;namespace myCar
{
//汽車驅動型別
internal enum CarDriveType
{
FrontWheelDrive,
RearWheelDrive,
FourWheelDrive
}
enum InputType
{
//鍵盤 羅技輪
Keyboard,LogiWheel
}
internal enum SpeedType
{
MPH,//速度單位 英里
KPH//速度單位 千米/小時
}
public class myCarController : MonoBehaviour
{
//車子為四輪驅動
[SerializeField] private CarDriveType m_CarDriveType = CarDriveType.FourWheelDrive;
//存放wheelcollider的陣列
[SerializeField] private WheelCollider[] m_WheelColliders = new WheelCollider[4];
//存放車輪模型的陣列
[SerializeField] private GameObject[] m_WheelMeshes = new GameObject[4];
//存放車輪聲音、煙霧、劃痕的陣列
[SerializeField] private myWheelEffects[] m_myWheelEffects = new myWheelEffects[4];
//存放前剎的陣列
[SerializeField] private GameObject[] m_frontBrake = new GameObject[2];
//車子的重心
[SerializeField] private Vector3 m_CentreOfMassOffset;
//最大可轉角度
[SerializeField] private float m_MaxSteerWheelAngle=360;
[SerializeField] private float m_MaximumSteerAngle;//最大控制角
[SerializeField] private float m_MinimumSteerAngle;//最小控制角
[Range(0, 1)] [SerializeField] private float m_SteerHelper; //初始化為0,1是車被控制面對的方向 0 is raw physics , 1 the car will grip in the direction it is facing
[Range(0, 1)] [SerializeField] private float m_TractionControl; //0沒有牽引力控制系統,1是完整的干擾0 is no traction control, 1 is full interference
//所有車輪的扭矩 扭矩越大,加速效能越好;扭矩越小,加速效能越差
//如某車的1擋齒比(齒輪的齒數比,本質就是齒輪的半徑比)是3,尾牙為4,輪胎半徑為0.3米,原扭矩是200Nm的話,最後在輪軸的扭矩就變成200×3×4=2400Nm,再除以輪胎半徑0.3米後,輪胎與地面摩擦的部分就有2400Nm/0.3m=8000N,即800公斤力的驅動力,這就足以驅動汽車了
[SerializeField] private float m_FullTorqueOverAllWheels;
//沒用到???反向扭矩
[SerializeField] private float m_ReverseTorque;
//最大手剎扭矩
[SerializeField] private float m_MaxHandbrakeTorque;
//最大下壓力:在中高速行駛時可以產生作用在車上向下的壓力,隨著速度的增加下壓力可以幾何級增長。下壓力的提升可以增大車輛的抓地力,由此可以具有更好的操縱性
[SerializeField] private float m_Downforce = 100f;
//速度型別
[SerializeField] private SpeedType m_SpeedType;
//最大速度
[SerializeField] private float m_Topspeed = 200;
//??最大倒車速度??
[SerializeField] private float m_TopBackspeed = 10;
//??轉速範圍邊界??
[SerializeField] private float m_RevRangeBoundary = 1f;
//滑動極限
[SerializeField] private float m_SlipLimit;
//制動力矩/剎車扭矩
[SerializeField] private float m_BrakeTorque;
//鍵盤控制
[SerializeField] private InputType inputType = InputType.Keyboard;
//??????有待考證
public bool shifter = false;//移動裝置
public bool needClutch = false;//是否需要離合器
public bool autoGear= false;//自動換擋
public string shiftUpButton="ShiftUp";//升檔按鈕
public string shiftDownButton="ShiftDown";//降檔按鈕
private float old_wheelangle;//之前的輪角
public GameObject wheel;//方向盤
public int wheelz = 57;
public int wheely = 23;
public int GearsNum = 7;//檔數
public int positiveGearsNum = 5;//檔位因子
public int m_GearNum;//當前檔數
public bool pressHandbrake;
private bool autoClutchUp = false;//離合器上去
private bool autoClutchDown = false;//離合器下來
private int tickTime = 0;
private bool ispress = false;
private Quaternion[] m_WheelMeshLocalRotations;
private Vector3 m_Prevpos, m_Pos;
private float m_SteerAngle;
private float m_GearFactor;
private float m_OldRotation;
private float m_CurrentTorque;
private Rigidbody m_Rigidbody;
private const float k_ReversingThreshold = 0.01f;
private float[] angle=new float[2];
private float[] old_steerAngle=new float[2];
public GameObject[] panelShowArray;//面板顯示陣列
public TextMesh[] panelNumArray;//儀盤表檔位顯示
private float oldSpeedPanelAngle=0; //角度329~575
private float oldSpeedFactorPanelAngle = 0;
private float CurrentTorque;
float hshow;
float handbrakeshow;
float vshow;
float brakeshow;
public float AccelInput { get; private set; }
public float BrakeInput { get; private set; }
public bool Skidding { get; private set; }
public float CurrentSteerAngle{ get { return m_SteerAngle; }}
public float CurrentSpeed{ get { return m_Rigidbody.velocity.magnitude*2.23693629f; }}//返回了剛體的速度
public float MaxSpeed{get { return m_Topspeed; }}//返回最大速度
public float Revs { get; private set; }
public float everyGearlimit_factor;
public float PlusTorque;
[Range(0f, 1f)]
public float factor;
[Range(0f, 1f)]
public float speedfactor;
public float[] myGearFactor;
[Range(-1f, 1f)]
public float[] myAccelSpeedFactor;
//float testtoque = 500;
//float oldrpm = 0;
//float time = 0;
// Use this for initialization
private void Start()
{
m_WheelMeshLocalRotations = new Quaternion[4];//四個輪胎的自轉方向:四元數來表示車輪方向,http://blog.csdn.net/soilwork/article/details/1447346
for (int i = 0; i < 4; i++)
{
m_WheelMeshLocalRotations[i] = m_WheelMeshes[i].transform.localRotation;//當前車輪的角度
}
m_WheelColliders[0].attachedRigidbody.centerOfMass = m_CentreOfMassOffset;//車子的質心放在wheelcollider[0]的質心位置
//手剎初始值為最大
m_MaxHandbrakeTorque = float.MaxValue;
//獲取剛體元件
m_Rigidbody = GetComponent<Rigidbody>();
//當前扭矩=全部扭矩-(牽引係數【0-1】*全部扭矩)
//設定當前扭矩,初始化的扭矩值跟m_TractionControl大小有關,m_TractionControl決定是否有牽引力,如果m_TractionControl
//值為0,則當前扭矩直接就是最大值,如果該值為1,則初始扭矩為0,然後汽車啟動慢慢增加扭矩力。建議m_TractionControl數值為0.5
m_CurrentTorque = m_FullTorqueOverAllWheels - (m_TractionControl*m_FullTorqueOverAllWheels);
}
// 一個簡單的函式來新增一個偏向1的曲線 【0 - 1的值的範圍內】simple function to add a curved bias towards 1 for a value in the 0-1 range
private static float CurveFactor(float factor)
{
return 1 - (1 - factor)*(1 - factor);
}
// 鬆開插值的版本,允許值超出範圍unclamped version of Lerp, to allow value to exceed the from-to range
//非限制版本的插值函式,“非限制”怎麼體現?
private static float ULerp(float from, float to, float value)
{
return (1.0f - value)*from + value*to;
}
//計算齒輪因素/檔位因子
private void CalculateGearFactor()
{
float f = (1/(float) GearsNum);
// gear factor is a normalised representation of the current speed within the current gear's range of speeds.
// We smooth towards the 'target' gear factor, so that revs don't instantly snap up or down when changing gear.
//齒輪因素是在當前齒輪的速度範圍的正常表示。我們順利走向“目標”裝備因素,所以轉速時不要立即調節或向下改變齒輪。
//目標齒輪數=(當前速度/最大速度)*最大齒輪數-當前齒輪數
//我們要讓值平滑地想著目標移動,以保證轉速不會在變換檔位時突然地上高或者降低
//反向差值,通過當前速度的比例值,找當前速度在當前檔位的比例位置,得到的值將是一個0~1範圍內的值。
var targetGearFactor = Mathf.InverseLerp(f*m_GearNum, f*(m_GearNum + 1), Mathf.Abs(CurrentSpeed/MaxSpeed));//反插值,計算比例值(5,10,8)=(8-5)/(10-5)=3/5 mathf.abs絕對值
//從當前檔位因子向目標檔位因子做平滑差值
m_GearFactor = Mathf.Lerp(m_GearFactor, targetGearFactor, Time.deltaTime*5f);
}
//計算引擎轉速(顯示/聲音)
private void CalculateRevs()
{ //計算引擎轉速(顯示/聲音)
//(這樣做是回想起來-轉速不習慣在力/功率計算)
//(我的個人理解:)這個計算是回溯的轉速,不能用於力的計算。
//計算在當前檔位上的轉速因子(決定在當前檔位上的轉速)
// calculate engine revs (for display / sound)
// (this is done in retrospect - revs are not used in force/power calculations)
CalculateGearFactor();
var gearNumFactor = m_GearNum/(float) GearsNum;
//計算當前檔位最小速度
var revsRangeMin = ULerp(0f, m_RevRangeBoundary, CurveFactor(gearNumFactor));
//計算當前檔位最大速度
var revsRangeMax = ULerp(m_RevRangeBoundary, 1f, gearNumFactor);
//根據當前的轉速因子,計算當前的轉速
Revs = ULerp(revsRangeMin, revsRangeMax, m_GearFactor);
}
public void Move(float steering, float accel, float footbrake, float clutch, float handbrake)
{
for (int i = 0; i < 4; i++)
{
Quaternion quat;
Vector3 position;
m_WheelColliders[i].GetWorldPose(out position, out quat);
m_WheelMeshes[i].transform.position = position;
m_WheelMeshes[i].transform.rotation = quat;
}
//steering wheel 控制方向盤的旋轉
wheel.transform.Rotate(new Vector3(0, -wheelz, wheely), steering * m_MaxSteerWheelAngle - old_wheelangle * m_MaxSteerWheelAngle);
old_wheelangle = steering;
//panelShowArray面板顯示陣列 CurrentSpeed返回了剛體的速度
panelShowArray[0].transform.Rotate(new Vector3(0, 1, 0), (CurrentSpeed - oldSpeedPanelAngle) * 242.0f / 150.0f, Space.Self);//Space.Self指區域性座標,即繞Y軸轉動
oldSpeedPanelAngle = CurrentSpeed;
float factor = CurrentTorque / m_CurrentTorque;
if(speedfactor>0)
{
panelShowArray[1].transform.Rotate(new Vector3(0, 1, 0), (Mathf.Clamp(speedfactor,0f,1f) - oldSpeedFactorPanelAngle) * 240f, Space.Self);
oldSpeedFactorPanelAngle = Mathf.Clamp(speedfactor, 0f, 1f);
}
float showSpeed = (int)CurrentSpeed;
if (CurrentSpeed % ((int)CurrentSpeed) > 0.5f)
showSpeed++;
//面板上顯示當前檔位
panelNumArray[0].text = ""+showSpeed;
if (m_GearNum == -1)
panelNumArray[1].text = "" + "R";
else if (m_GearNum == 0)
panelNumArray[1].text = "" + "H";
else
{
panelNumArray[1].text = "" + m_GearNum;
}
//限定輸入值範圍clamp input values
steering = Mathf.Clamp(steering, -1, 1);
AccelInput= accel = Mathf.Clamp(accel, 0, 1);
if (autoGear)
needClutch = true;
if(inputType==InputType.Keyboard)
{
BrakeInput = footbrake = -1 * Mathf.Clamp(footbrake, -1, 0);
if (needClutch)
clutch = -1 * Mathf.Clamp(clutch, -1, 0);
else
clutch = 0;
}
else
{
BrakeInput = footbrake = (footbrake + 1) * 0.5f;
if (needClutch)
clutch = (clutch + 1) * 0.5f;
else
clutch = 0;
}
//設定前輪轉角
//wheels下標為0、1的就是前輪
//Set the steer on the front wheels.
//Assuming that wheels 0 and 1 are the front wheels.
m_SteerAngle = steering *m_MaximumSteerAngle;
m_WheelColliders[0].steerAngle = m_SteerAngle;
m_WheelColliders[1].steerAngle = m_SteerAngle;
//換擋
GearChange(clutch);
//角度輔助助手,旋轉更平滑
SteerHelper();
//設定加速/剎車資訊到WheelCollider
ApplyDrive(accel, footbrake,clutch,(int)handbrake);
//檢查速度範圍
CapSpeed();
//Set the handbrake.
//Assuming that wheels 2 and 3 are the rear wheels.
//計算轉速
CalculateRevs();
//施加下壓力
AddDownForce();
//檢查輪胎
CheckForWheelSpin();
//牽引力控制系統
TractionControl();
//show
hshow = m_SteerAngle;
vshow =footbrake ;
brakeshow = accel;
handbrakeshow =handbrake;
}
//控制車速
private void CapSpeed()
{
float speed = m_Rigidbody.velocity.magnitude;
switch (m_SpeedType)
{
case SpeedType.MPH:
//轉換單位便於比較,將速度m/s轉換為mile/h
speed *= 2.23693629f;
if (speed > m_Topspeed)
m_Rigidbody.velocity = (m_Topspeed/2.23693629f) * m_Rigidbody.velocity.normalized;
break;
//將速度m/s轉換為km/h,以便比較
case SpeedType.KPH:
speed *= 3.6f;
if (speed > m_Topspeed)
m_Rigidbody.velocity = (m_Topspeed/3.6f) * m_Rigidbody.velocity.normalized;
break;
}
}
//設定加速/剎車資訊到WheelCollider
private void ApplyDrive(float accel, float footbrake,float clutch,int handbrake)
{
if (handbrake == 1&&!ispress)
{
pressHandbrake = !pressHandbrake;
ispress = true;
}
if (handbrake == 0)
ispress = false;
float thrustTorque;
switch (m_CarDriveType)
{
case CarDriveType.FourWheelDrive:
thrustTorque =accel * (m_CurrentTorque / 4f);
for (int i = 0; i < 4; i++)
myApplyDrive(i,thrustTorque,clutch);
break;
case CarDriveType.FrontWheelDrive:
thrustTorque = accel * (m_CurrentTorque / 2f);
myApplyDrive(0, thrustTorque, clutch);
myApplyDrive(1, thrustTorque, clutch);
break;
case CarDriveType.RearWheelDrive:
thrustTorque = accel * (m_CurrentTorque / 2f);
// thrustTorque = testtoque;
// if(testtoque>=164.4948)
// testtoque-=0.1f;
// Debug.Log(CurrentSpeed+"eee"+testtoque);
//oldrpm = CurrentSpeed;
myApplyDrive(2, thrustTorque, clutch);
myApplyDrive(3, thrustTorque, clutch);
break;
}
for (int i = 0; i < 4; i++)
{
if (!pressHandbrake)
{
if (Vector3.Angle(transform.forward, m_Rigidbody.velocity) < 50f && CurrentSpeed > m_TopBackspeed)
m_WheelColliders[i].brakeTorque = m_BrakeTorque * accel;
else if (footbrake > 0)
{
//m_WheelColliders[i].brakeTorque = m_ReverseTorque * footbrake;
if(CurrentSpeed>10)
m_WheelColliders[i].brakeTorque = m_BrakeTorque * footbrake;
else
m_WheelColliders[i].motorTorque = 100 * footbrake;
}
else
{
m_WheelColliders[i].brakeTorque = 0;
WheelHit wh;
m_WheelColliders[i].GetGroundHit(out wh);
float groundangle = Vector3.Angle(Vector3.up, wh.normal);
if (groundangle > 5 && accel == 0 && CurrentSpeed < 1)
m_WheelColliders[i].motorTorque = 1;
}
}
else
m_WheelColliders[i].brakeTorque = m_MaxHandbrakeTorque;//剎車的力矩。這個值必須為正。
}
}
//掛擋【檔位更新】
void GearChange(float clutch)
{//不是自動擋
if(!autoGear)
{
if(needClutch)
{//踩離合換擋
if(clutch>0.5f)
Gear();
}
else
{//不需要離合直接換擋
Gear();
}
}
//自動換擋
else
{
//後退檔
if (Input.GetButton("reverse")||Input.GetButtonDown(shiftDownButton))
m_GearNum = -1;
//空擋
else if (Input.GetButton("neutral"))
m_GearNum = 0;
//1檔
else if (Input.GetButtonDown("first") || Input.GetButtonDown(shiftUpButton))
m_GearNum = 1;
//執行時汽車自動換擋
//這裡其實相當於將所有速度進行了劃分,f就是指的目前速度處於最大速度的幾分之幾
//如果NoOfGears是5,那麼就把速度分成5段
//1檔就是0/5 ~ 1/5,
//2檔就是1/5 ~ 2/5,
//3檔就是2/5 ~ 3/5,
//4檔就是3/5 ~ 4/5,
//5檔就是4/5 ~ 5/5,
//每次先看當前檔位是幾檔,然後看當前速度是否匹配當前檔位,如果匹配當前檔位沒啥事,如果不匹配則看當前速度如果小於當前檔位
//最小速度則減檔,如果大於當前檔位最大速度則,加檔;
else if(m_GearNum>0&&m_GearNum<=positiveGearsNum)
{
float f = Mathf.Abs(CurrentSpeed / MaxSpeed);
//計算當前檔位速度下限
float downgearlimit = (1 / (float)positiveGearsNum) * (m_GearNum-1) ;
//計算當前檔位速度上限
float upgearlimit = (1 / (float)positiveGearsNum) * (m_GearNum);
factor = 1.2f - (float)m_GearNum / positiveGearsNum;
speedfactor = f / upgearlimit;
if(!autoClutchDown&&tickTime==0)
{
if (f > upgearlimit && m_GearNum < positiveGearsNum)
autoClutchUp = true;
}
if(!autoClutchUp&&tickTime==0)
{
if (m_GearNum > 1 && f < downgearlimit)
autoClutchDown = true;
}
if (autoClutchUp && tickTime == 0)
{
m_GearNum++;
tickTime++;
}
if (autoClutchDown && tickTime == 0)
{
m_GearNum--;
tickTime++;
}
if(tickTime!=0)
{
tickTime++;
if (tickTime > 10)
{
tickTime = 0;
autoClutchDown = false;
autoClutchUp = false;
}
}
}
else
speedfactor = CurrentSpeed / m_TopBackspeed;
}
}
//手動切換當前檔位
void Gear()
{ //根據鍵盤來更換當前檔位
if (shifter == true && inputType != InputType.Keyboard)
{
if (Input.GetButton("reverse"))
m_GearNum = -1;
else if (Input.GetButton("neutral"))
m_GearNum = 0;
else if (Input.GetButton("first"))
m_GearNum = 1;
else if (Input.GetButton("second"))
m_GearNum = 2;
else if (Input.GetButton("third"))
m_GearNum = 3;
else if (Input.GetButton("fourth"))
m_GearNum = 4;
else if (Input.GetButton("fifth"))
m_GearNum = 5;
else if (Input.GetButton("sixth"))
m_GearNum = -1;
else
m_GearNum = 0;
}
else
{//方向鍵控制
if (Input.GetButtonDown(shiftUpButton))
{
if (m_GearNum < positiveGearsNum)
m_GearNum++;
}
if (Input.GetButtonDown(shiftDownButton))
{
if (m_GearNum > -1)
--m_GearNum;
}
}
}
void myApplyDrive(int i,float oneTorque,float clutch)
{
CurrentTorque = oneTorque;
if(!pressHandbrake)
{
if (!autoGear)
{
if (m_GearNum > 0)
{
float f = Mathf.Abs(CurrentSpeed / MaxSpeed);
float upgearlimit = (1 / (float)positiveGearsNum) * m_GearNum * GetFactor(myGearFactor);
float downgearlimit = (1 / (float)positiveGearsNum) * m_GearNum;
float IForNOT;
if (f >= downgearlimit)
IForNOT = 1;
else
IForNOT = 0;
float calTorque;
factor = 1.2f - (float)m_GearNum / positiveGearsNum;
speedfactor = f / upgearlimit;
calTorque = factor * oneTorque + (1.2f - factor) * oneTorque * (CurrentSpeed / MaxSpeed) + PlusTorque * GetFactor(myAccelSpeedFactor) * IForNOT;
if (f > upgearlimit)
calTorque = everyGearlimit_factor * calTorque;
m_WheelColliders[i].motorTorque = -calTorque * (1 - clutch);
CurrentTorque = calTorque;
}
else if (m_GearNum < 0 && CurrentSpeed < m_TopBackspeed)
{
m_WheelColliders[i].motorTorque = oneTorque * (1 - clutch);
speedfactor = CurrentSpeed / m_TopBackspeed;
}
else
speedfactor = CurrentSpeed / m_TopBackspeed;
}
else
{
if(m_GearNum>0)
m_WheelColliders[i].motorTorque = -oneTorque;
else
m_WheelColliders[i].motorTorque = oneTorque;
}
}
}
float GetFactor(float[] fact)
{
if (myGearFactor.Length != positiveGearsNum)
{
Debug.LogError("GearFactor Error!");
return -1;
}
else
return fact[m_GearNum-1];
}
private void SteerHelper()
{
for (int i = 0; i < 4; i++)
{
WheelHit wheelhit;
m_WheelColliders[i].GetGroundHit(out wheelhit);
if (wheelhit.normal == Vector3.zero)
return; // wheels arent on the ground so dont realign the rigidbody velocity
//假如輪子離地,就不用調整汽車角度了
}
// this if is needed to avoid gimbal lock problems that will make the car suddenly shift direction
//這個是為了避免萬向鎖問題的,萬向鎖問題會導致汽車突然變換方向(我直到萬向鎖問題,但不理解下面是怎麼避免問題的,我只知道四元數的使用
//就是為了避免萬向鎖問題)
//下面這個If函式的效果就是,假如上一次車體Y方向角度比這次小於十度,就根據相差的度數乘以係數m_SteerHelper
//計算出這個偏移角度的四元數,然後將剛體速度直接旋轉這個偏倚度數,
//根據程式碼開頭m_SteerHelper的定義,這個做法相當於做了一個角度輔助,不完全憑藉WheelCollider物理效果
//而直接操控速度方向,對車角度進行調整。
if (Mathf.Abs(m_OldRotation - transform.eulerAngles.y) < 10f)
{
var turnadjust = (transform.eulerAngles.y - m_OldRotation) * m_SteerHelper;
Quaternion velRotation = Quaternion.AngleAxis(turnadjust, Vector3.up);
m_Rigidbody.velocity = velRotation * m_Rigidbody.velocity;
}
m_OldRotation = transform.eulerAngles.y;
for(int i=0;i<m_frontBrake.Length;i++)
{
angle[i] = m_SteerAngle - old_steerAngle[i];
old_steerAngle[i] = m_SteerAngle;
m_frontBrake[i].transform.RotateAround(m_WheelMeshes[i].transform.position, Vector3.up, angle[i]);
}
}
// 新增下壓力:這是用來新增更多的速度控制this is used to add more grip in relation to speed
private void AddDownForce()
{
m_WheelColliders[0].attachedRigidbody.AddForce(-transform.up*m_Downforce*
m_WheelColliders[0].attachedRigidbody.velocity.magnitude);
}
// checks if the wheels are spinning and is so does three things
//檢查輪胎是否旋轉
// 1) emits particles
//檢查是否發射尾氣粒子
// 2) plays tiure skidding sounds
//播放滑行音
// 3) leaves skidmarks on the ground
//去掉剎車印
// these effects are controlled through the WheelEffects class
//這些特效都是通過WheelEffects類控制的
//檢查輪胎
private void CheckForWheelSpin()
{
// loop through all wheels
for (int i = 0; i < 4; i++)
{
WheelHit wheelHit;
m_WheelColliders[i].GetGroundHit(out wheelHit);
// 輪胎下滑超過給定的閾值嗎 is the tire slipping above the given threshhold
if (Mathf.Abs(wheelHit.forwardSlip) >= m_SlipLimit || Mathf.Abs(wheelHit.sidewaysSlip) >= m_SlipLimit)
{
m_myWheelEffects[i].EmitTyreSmoke();
//超出則發射煙霧粒子
// avoiding all four tires screeching at the same time
// if they do it can lead to some strange audio artefacts
//避免四個輪胎都同時播放滑行聲音
//如果那樣的話會導致某些奇怪的音效
if (!AnySkidSoundPlaying())
{
m_myWheelEffects[i].PlayAudio();
}
continue;
}
// if it wasnt slipping stop all the audio
//假如沒有超出閾值,還沒有停止音效,則停止音效
if (m_myWheelEffects[i].PlayingAudio)
{
m_myWheelEffects[i].StopAudio();
}
// end the trail generation
//停止煙霧生成
m_myWheelEffects[i].EndSkidTrail();
}
}
// crude traction control that reduces the power to wheel if the car is wheel spinning too much
//如果汽車輪胎過度滑轉,牽引力系統可以控制減少輪胎動力
//牽引力控制系統
private void TractionControl()
{
WheelHit wheelHit;
switch (m_CarDriveType)
{
case CarDriveType.FourWheelDrive:
// loop through all wheels
for (int i = 0; i < 4; i++)
{
m_WheelColliders[i].GetGroundHit(out wheelHit);
AdjustTorque(wheelHit.forwardSlip);
}
break;
case CarDriveType.RearWheelDrive:
m_WheelColliders[2].GetGroundHit(out wheelHit);
AdjustTorque(wheelHit.forwardSlip);
m_WheelColliders[3].GetGroundHit(out wheelHit);
AdjustTorque(wheelHit.forwardSlip);
break;
case CarDriveType.FrontWheelDrive:
m_WheelColliders[0].GetGroundHit(out wheelHit);
AdjustTorque(wheelHit.forwardSlip);
m_WheelColliders[1].GetGroundHit(out wheelHit);
AdjustTorque(wheelHit.forwardSlip);
break;
}
}
private void AdjustTorque(float forwardSlip)
{//當向前滑動距離超過閾值後,就說明輪胎過度滑轉,則減少牽引力,以降低轉速。
//調整m_CurrentTorque值的大小來控制牽引力
if (forwardSlip >= m_SlipLimit && m_CurrentTorque >= 0)
{
m_CurrentTorque -= 10 * m_TractionControl;
}
else
{
m_CurrentTorque += 10 * m_TractionControl;
if (m_CurrentTorque > m_FullTorqueOverAllWheels)
{
m_CurrentTorque = m_FullTorqueOverAllWheels;
}
}
}
void OnGUI()
{
GUIStyle size=new GUIStyle();
size.fontSize=30;
GUI.Label(new Rect(500, 20, 100, 20), "Throttle:" + vshow);
GUI.Label(new Rect(500, 50, 100, 20), "Wheel:" + hshow);
GUI.Label(new Rect(500, 70, 100, 20), "Brake:" + brakeshow);
GUI.Label(new Rect(500, 90, 100, 20), "handBrake:" + handbrakeshow);
GUI.Label(new Rect(500, 120, 100, 20), "geer:" + m_GearNum, size);
GUI.Label(new Rect(500, 160, 100, 20), "speed:" + (int)CurrentSpeed, size);
}
private bool AnySkidSoundPlaying()
{
for (int i = 0; i < 4; i++)
{
if (m_myWheelEffects[i].PlayingAudio)
{
return true;
}
}
return false;
}
}
}