Unity平臺(tái)模擬自動(dòng)擋駕駛汽車
自動(dòng)擋汽車功能分析:
(1)剎車數(shù)值用連續(xù)量0-255表示,連續(xù)量根據(jù)鍵盤按鍵按下時(shí)長(zhǎng)進(jìn)行遞增,1秒后達(dá)到峰值,無論車輛處于前進(jìn)擋還是倒擋,踩下剎車后車輛逐漸減速至0
(2)汽車分為四個(gè)擋位,停車擋P,倒擋R,空擋N,前進(jìn)擋D
(3)汽車啟動(dòng)后,松開剎車,車輛進(jìn)入怠速模式,速度從0逐步提升至12KM/H
(4)剎車數(shù)值用連續(xù)量0-255表示。車速對(duì)應(yīng)1檔0-10,2檔11-20,3檔21-40,4檔41-60,5檔61-80,6檔81-最大值,對(duì)應(yīng)峰值車速150KM/H
(5)掛住P檔,拉起手剎車輛停止。
(6)掛住R檔,車輛可進(jìn)行倒車操作。
(7)通過鍵盤A和D可以控制車輛左右轉(zhuǎn)向
運(yùn)行結(jié)果圖:
啟動(dòng)車輛,拉起手剎,掛前進(jìn)擋,車輛進(jìn)入怠速模式,緩慢進(jìn)行加速。

速度提升到12km/h后勻速行駛,繼續(xù)加速需要踩下油門。

踩下油門后車輛快速加速,自行切換擋位:

前進(jìn)時(shí)踩下剎車后車子逐漸減速至0:

切換至倒擋,踩下油門,車輛后退,踩下剎車,車子逐漸減速至0:

前進(jìn)時(shí)左右轉(zhuǎn)向:

倒擋時(shí)左右轉(zhuǎn)型:

源代碼:
采用manager of manager的方式,使用了單例模式。
1.Car_Mng類負(fù)責(zé)管理車輛的物理仿真
2.Input_Mng類負(fù)責(zé)接受用戶的鍵盤輸入信息
3.UI_Mng類負(fù)責(zé)更新UI界面的顯示
Car_Mng
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.Tracing;
using UnityEngine;
public class Car_Mng : MonoBehaviour
{
static public Car_Mng Instance;
public SpeedGear speedGear;
public float maxMotorTorque; //最大的前進(jìn)力矩
public float maxSpeed; //車輛最大前進(jìn)速度
public float maxReversMotorTorque; //最大的倒車力矩
public float maxBrakeToeque; //最大的剎車阻力
public float maxSteeringAngle; //主動(dòng)輪最大的旋轉(zhuǎn)角度
public Rigidbody car; //車輛的剛體
public WheelCollider[] coliders; //車輪碰撞器
public GameObject[] wheelMesh; //車輪模型
public CarState carState=CarState.Off; //車輛啟動(dòng)狀態(tài)
public GearState gearState = GearState.ParkingGear; //車輛的擋位
public bool isHandBrakeON; //是否拉起手剎的標(biāo)志位
public float currentSpeed=0; //計(jì)算當(dāng)前車輛的速度
private bool currentHandBrakeState=true;
private void Awake()
{
Instance = this;
}
void Start()
{
/* coliders[0].steerAngle = 30;
coliders[1].steerAngle = 30;
for (int i = 0; i < 4; i++)
{
Quaternion quat;
Vector3 position;
coliders[i].GetWorldPose(out position, out quat);
Debug.Log(position);
Debug.Log(quat.eulerAngles);
wheelMesh[i].transform.position = position;
wheelMesh[i].transform.rotation =
coliders[i].transform.rotation * Quaternion.Euler(0, coliders[i].steerAngle, 0);
}*/
}
private void Update()
{
UpdateHandBrokeState(); //更新手剎狀態(tài)
}
private void FixedUpdate()
{
if (gearState == GearState.ForwardGear || gearState == GearState.ReversGear)
{
BrakeCalculate(); //剎車計(jì)算 阻力
AccCalculate(); //油門計(jì)算 動(dòng)力
}
SteerCalculate();
UpdateCarSpeed(); //更新車子的速度
AutoChangeGear(); //自動(dòng)換擋 自動(dòng)擋的車子
SynchronousWheelMesh(); //將車輪的狀態(tài)同步給車的模型
}
void SynchronousWheelMesh()
{
for (int i = 0; i < 6; i++)
{
Quaternion quat;
Vector3 position;
coliders[i].GetWorldPose(out position, out quat);
wheelMesh[i].transform.position = position;
wheelMesh[i].transform.rotation = quat;
}
}
void UpdateHandBrokeState()
{
if (currentHandBrakeState != isHandBrakeON)
{
currentHandBrakeState = isHandBrakeON;
if (currentHandBrakeState)
{
PullupHandbrake();
}
else
{
PullDownHandbrake();
}
}
} //更新手剎狀態(tài)
public void StartCar() //啟動(dòng)車輛
{
carState = CarState.On;
}
public void StopCar() //停車
{
carState = CarState.Off; //停止接收油門、方向盤、剎車信號(hào)
gearState = GearState.ParkingGear; //掛上停車擋
PullupHandbrake(); //拉起手剎
}
void PullupHandbrake() //拉起手剎,相當(dāng)于阻力矩最大,直接Freeze車輛剛體的運(yùn)動(dòng)
{
isHandBrakeON = true; //設(shè)置標(biāo)志位
//僅保留y軸向的運(yùn)動(dòng)
car.constraints = RigidbodyConstraints.FreezeRotation
| RigidbodyConstraints.FreezePositionX | RigidbodyConstraints.FreezePositionZ;
}
void PullDownHandbrake() //放下手剎,解鎖運(yùn)動(dòng)
{
isHandBrakeON = false;
//解鎖所有運(yùn)動(dòng)
car.constraints = RigidbodyConstraints.None;
}
void BrakeCalculate() //計(jì)算剎車的阻力
{
var value = Input_Mng.Instance.GetBrakeValue(); //讀取剎車阻力
var brakeToequePerWheel = maxBrakeToeque / 2 * value / 255; //計(jì)算一個(gè)車輪的阻力
coliders[0].motorTorque = 0;
coliders[1].motorTorque = 0;
for (int i = 0; i < 6; i++)
{
coliders[i].brakeTorque = brakeToequePerWheel;
}
// Debug.Log("剎車阻力:"+ brakeToequePerWheel);
}
void AccCalculate() //油門動(dòng)力計(jì)算
{
if (gearState == GearState.ForwardGear) //前進(jìn)
{
var value = Input_Mng.Instance.GetAcceleratorValue();
if (value != 0) //加速行駛
{
if(MeterPerSeconds2KmPerHour(currentSpeed) <= 150)
{
var accToequePerWheel = maxMotorTorque * value / 255; //計(jì)算一個(gè)車輪的動(dòng)力
coliders[0].motorTorque = accToequePerWheel;
coliders[1].motorTorque = accToequePerWheel;
}
else //不能超過速度上限
{
coliders[0].motorTorque = 0;
coliders[1].motorTorque = 0;
}
}
else //怠速駕駛
{
if (MeterPerSeconds2KmPerHour(currentSpeed) < 12)
{
coliders[0].motorTorque = 100;
coliders[1].motorTorque = 100;
}
else
{
Debug.Log("無動(dòng)力");
for (int i = 0; i < 6; i++)
{
coliders[i].motorTorque = 0;
}
}
}
}
else //倒車
{
var value = Input_Mng.Instance.GetAcceleratorValue();
var accToequePerWheel = maxReversMotorTorque / 2 * value / 255; //計(jì)算一個(gè)車輪的動(dòng)力
coliders[0].motorTorque = -accToequePerWheel;
coliders[1].motorTorque = -accToequePerWheel;
}
}
void SteerCalculate() //計(jì)算轉(zhuǎn)向
{
var value= Input_Mng.Instance.GetSteerValue();
var steerAngle = (value - 128) / 128 * maxSteeringAngle; //計(jì)算旋轉(zhuǎn)角度
coliders[0].steerAngle = steerAngle;
coliders[1].steerAngle = steerAngle;
}
void AutoChangeGear() //自動(dòng)擋,前進(jìn)時(shí)根據(jù)車輛的速度自動(dòng)切換擋位
{
if (gearState == GearState.ForwardGear)
{
var speed = MeterPerSeconds2KmPerHour(currentSpeed);
if (speed <= 10 && speed > 0)
{
speedGear = SpeedGear.Speed01;
}
if (speed <= 20 && speed > 10)
{
speedGear = SpeedGear.Speed02;
}
if (speed <= 40 && speed > 20)
{
speedGear = SpeedGear.Speed03;
}
if (speed <= 60 && speed > 40)
{
speedGear = SpeedGear.Speed04;
}
if (speed <= 80 && speed > 60)
{
speedGear = SpeedGear.Speed05;
}
if (speed <= 155 && speed > 80)
{
speedGear = SpeedGear.Speed06;
}
}
else
{
speedGear = SpeedGear.none;
}
}
void UpdateCarSpeed()
{
currentSpeed = car.velocity.magnitude;
}
static public float MeterPerSeconds2KmPerHour(float speed) //切換單位 m/s換算成 km/h
{
return speed*3.6f;
}
static float KmPerHour2MeterPerSeconds(float speed) //切換單位 km/h換算成m/s
{
return speed/3.6f;
}
}
public enum CarState
{
Off = 0, //關(guān)機(jī)狀態(tài)
On = 1, //運(yùn)行狀態(tài)
}
public enum GearState
{
ParkingGear = 1, //停車擋
ReversGear = 2, //倒擋
NeutralGear = 3, //空擋
ForwardGear = 4, //前進(jìn)擋
}
public enum SpeedGear
{
none,
Speed01,
Speed02,
Speed03,
Speed04,
Speed05,
Speed06
}
Input_Mng
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Input_Mng : MonoBehaviour
{
static public Input_Mng Instance; //單例模式
private KeyCode braKeyCode=KeyCode.M; //剎車對(duì)應(yīng)的鍵盤按鍵
public float brakeValue = 0; //剎車值
public bool isBra = false;
private KeyCode accKeyCode=KeyCode.W; //油門對(duì)應(yīng)的鍵盤按鍵
public float acceleratorValue = 0; //油門值
public bool isAcc = false;
private KeyCode leftSteerKeyCode = KeyCode.A;
private KeyCode rightSteerKeyCode = KeyCode.D;
public float steerValue = 128;
private KeyCode parkingKeyCode = KeyCode.Alpha1; //停車對(duì)應(yīng)的按鍵
private KeyCode reversKeyCode = KeyCode.Alpha2; //倒車對(duì)應(yīng)的按鍵
private KeyCode neutralKeyCode = KeyCode.Alpha3; //空擋對(duì)應(yīng)的按鍵
private KeyCode forwardKeyCode = KeyCode.Alpha4; //前進(jìn)擋對(duì)應(yīng)的按鍵
private KeyCode handBrakeKeyCode = KeyCode.H; //手剎對(duì)應(yīng)的按鍵
public float GetBrakeValue() //獲取剎車值
{
return brakeValue;
}
public float GetAcceleratorValue() //獲取油門值
{
return acceleratorValue;
}
public float GetSteerValue()
{
return steerValue;
} //獲取轉(zhuǎn)彎值
private void Awake()
{
Instance = this;
}
private void Update()
{
if (Car_Mng.Instance.carState == CarState.On) //當(dāng)車輛啟動(dòng)后,檢測(cè)油門剎車和擋位變換
{
UpdateGeerState();
}
UpdateSteerValue();
UpdateHandBrakeState();
UpdateAcceleratorValue(accKeyCode);
UpdateBrakeValue(braKeyCode);
}
void UpdateHandBrakeState()
{
if (Input.GetKeyDown(handBrakeKeyCode))
{
if (Car_Mng.Instance.isHandBrakeON)
{
Car_Mng.Instance.isHandBrakeON = false;
}
else
{
Car_Mng.Instance.isHandBrakeON = true;
}
}
}
void UpdateAcceleratorValue(KeyCode AccCode)
{
if (Input.GetKey(AccCode))
{
acceleratorValue += 255 * Time.deltaTime;
acceleratorValue = Mathf.Clamp(acceleratorValue, 0, 255);
isAcc = true;
}
else
{
acceleratorValue = 0;
isAcc = false;
}
} //更新油門狀態(tài)
void UpdateBrakeValue(KeyCode BraCode) //更新剎車狀態(tài)
{
if (Input.GetKey(BraCode))
{
brakeValue += 255 * Time.deltaTime;
brakeValue = Mathf.Clamp(brakeValue, 0, 255);
isBra = true;
}
else
{
brakeValue = 0;
isBra = false;
}
}
void UpdateSteerValue() //更新方向盤狀態(tài)
{
if (Input.GetKey(leftSteerKeyCode))
{
steerValue -= 255 * Time.deltaTime; //0.5秒左側(cè)打死
steerValue = Mathf.Clamp(steerValue, 0, 255);
}else if(Input.GetKey(rightSteerKeyCode))
{
steerValue += 255 * Time.deltaTime; //0.5秒右側(cè)打死
steerValue = Mathf.Clamp(steerValue, 0, 255);
}
else
{
steerValue = 128;
}
}
void UpdateGeerState() //更新?lián)跷粻顟B(tài)
{
if (Input.GetKeyDown(parkingKeyCode)) //設(shè)置為停車檔
{
Car_Mng.Instance.gearState = GearState.ParkingGear;
}
if (Input.GetKeyDown(reversKeyCode)) //倒車檔
{
Car_Mng.Instance.gearState = GearState.ReversGear;
}
if (Input.GetKeyDown(neutralKeyCode)) //空擋
{
Car_Mng.Instance.gearState = GearState.NeutralGear;
}
if (Input.GetKeyDown(forwardKeyCode)) //前進(jìn)擋
{
Car_Mng.Instance.gearState = GearState.ForwardGear;
}
}
}
UI_Mng
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using UnityEngine;
using UnityEngine.UI;
public class UI_Mng : MonoBehaviour
{
static public UI_Mng Instance;
public Image ParkingBg; //停車檔
public Image ForwardBg; //前進(jìn)擋
public Image NeutralBg; //空擋
public Image ReversBg; //倒車檔
public Image HandBrakeBg; //手剎
public Text speedText; //速度顯示
public Text speedGearText; //擋位顯示
public Image SwitchBg; //開關(guān)背景
public Text Switchtext; //開關(guān)顯示文字
public Image AccBg; //油門
public Image BraBg; //剎車
private GearState currentGearState;
private bool currentBrakeState;
private void Awake()
{
Instance = this;
}
private void Update()
{
UpdateGearUI();
UpdateHandBrakeUI();
UpdateAccBra();
UpdateSpeed();
}
void UpdateSpeed()
{
speedText.text = Car_Mng.MeterPerSeconds2KmPerHour(Car_Mng.Instance.currentSpeed).ToString("F2")
+ " Km/h";
SpeedGear speedGear = Car_Mng.Instance.speedGear;
switch (speedGear)
{
case SpeedGear.none:
speedGearText.text = "自動(dòng)擋";
break;
case SpeedGear.Speed01:
speedGearText.text = "1擋";
break;
case SpeedGear.Speed02:
speedGearText.text = "2擋";
break;
case SpeedGear.Speed03:
speedGearText.text = "3擋";
break;
case SpeedGear.Speed04:
speedGearText.text = "4擋";
break;
case SpeedGear.Speed05:
speedGearText.text = "5擋";
break;
case SpeedGear.Speed06:
speedGearText.text = "6擋";
break;
default:
break;
}
}
void UpdateAccBra()
{
if (Input_Mng.Instance.isAcc)
{
AccBg.color = UnityEngine.Color.green;
}
else
{
AccBg.color = UnityEngine.Color.white;
}
if (Input_Mng.Instance.isBra)
{
BraBg.color = UnityEngine.Color.green;
}
else
{
BraBg.color = UnityEngine.Color.white;
}
}
void UpdateHandBrakeUI()
{
if (currentBrakeState != Car_Mng.Instance.isHandBrakeON)
{
currentBrakeState = Car_Mng.Instance.isHandBrakeON;
if (currentBrakeState)
{
HandBrakeBg.color = UnityEngine.Color.red;
}
else
{
HandBrakeBg.color = UnityEngine.Color.white;
}
}
}
private void Start()
{
Car_Mng.Instance.StopCar(); //關(guān)閉車輛
OnCarShutDown();//更新UI
}
void UpdateGearUI()
{
if (currentGearState != Car_Mng.Instance.gearState)
{
currentGearState = Car_Mng.Instance.gearState;
ClearGearUI();
SetGearUI(currentGearState);
}
}
void ClearGearUI()
{
ParkingBg.color = UnityEngine.Color.white;
ForwardBg.color = UnityEngine.Color.white;
NeutralBg.color = UnityEngine.Color.white;
ReversBg.color = UnityEngine.Color.white;
}
void SetGearUI(GearState state)
{
switch (state)
{
case GearState.ForwardGear:
ForwardBg.color = UnityEngine.Color.red;
break;
case GearState.ReversGear:
ReversBg.color = UnityEngine.Color.red;
break;
case GearState.NeutralGear:
NeutralBg.color = UnityEngine.Color.red;
break;
case GearState.ParkingGear:
ParkingBg.color = UnityEngine.Color.red;
break;
}
}
public void ChangeCarState()
{
if (Car_Mng.Instance.carState == CarState.On) //如果處于開機(jī)狀態(tài),則停機(jī)
{
Car_Mng.Instance.StopCar(); //關(guān)閉車輛
OnCarShutDown();//更新UI
}else
{
Car_Mng.Instance.StartCar(); //啟動(dòng)車子
OnCarStart();//更新UI
}
}
private void OnCarStart() //車輛啟動(dòng)時(shí)更新ui
{
SwitchBg.color = UnityEngine.Color.red;
Switchtext.text = "關(guān)閉車輛";
}
private void OnCarShutDown() //車輛關(guān)閉時(shí)執(zhí)行的邏輯
{
SwitchBg.color = UnityEngine.Color.green;
Switchtext.text = "啟動(dòng)車輛";
}
}
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Expression操作運(yùn)算符、表達(dá)式和操作方法總結(jié)
這篇文章詳細(xì)介紹了Expression操作運(yùn)算符、表達(dá)式和操作方法總結(jié),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-01-01
C#自定義導(dǎo)出數(shù)據(jù)到Excel的類實(shí)例
這篇文章主要介紹了C#自定義導(dǎo)出數(shù)據(jù)到Excel的類,實(shí)例分析了C#操作Excel的技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-03-03
C#實(shí)現(xiàn)ArrayList動(dòng)態(tài)數(shù)組的示例
ArrayList是一個(gè)動(dòng)態(tài)數(shù)組,可以用來存儲(chǔ)任意類型的元素,本文就來介紹一下C#實(shí)現(xiàn)ArrayList動(dòng)態(tài)數(shù)組的示例,具有一定的參考價(jià)值,感興趣的可以了解一下2023-12-12
C/C++與Java各數(shù)據(jù)類型所占字節(jié)數(shù)的詳細(xì)比較
本篇文章主要是對(duì)C/C++與Java各數(shù)據(jù)類型所占字節(jié)數(shù)進(jìn)行了詳細(xì)的對(duì)比。需要的朋友可以過來參考下,希望對(duì)大家有所幫助2014-01-01
C#開發(fā)Android百度地圖手機(jī)應(yīng)用程序(多地圖展示)
這篇文章主要介紹了C#開發(fā)Android百度地圖手機(jī)應(yīng)用程序(多地圖展示)的相關(guān)資料,需要的朋友可以參考下2016-02-02

