Unity平臺模擬自動擋駕駛汽車
阿新 • • 發佈:2020-07-21
自動擋汽車功能分析:
(1)剎車數值用連續量0-255表示,連續量根據鍵盤按鍵按下時長進行遞增,1秒後達到峰值,無論車輛處於前進擋還是倒擋,踩下剎車後車輛逐漸減速至0
(2)汽車分為四個擋位,停車擋P,倒擋R,空擋N,前進擋D
(3)汽車啟動後,鬆開剎車,車輛進入怠速模式,速度從0逐步提升至12KM/H
(4)剎車數值用連續量0-255表示。車速對應1檔0-10,2檔11-20,3檔21-40,4檔41-60,5檔61-80,6檔81-最大值,對應峰值車速150KM/H
(5)掛住P檔,拉起手剎車輛停止。
(6)掛住R檔,車輛可進行倒車操作。
(7)通過鍵盤A和D可以控制車輛左右轉向
執行結果圖:
啟動車輛,拉起手剎,掛前進擋,車輛進入怠速模式,緩慢進行加速。
速度提升到12km/h後勻速行駛,繼續加速需要踩下油門。
踩下油門後車輛快速加速,自行切換擋位:
前進時踩下剎車後車子逐漸減速至0:
切換至倒擋,踩下油門,車輛後退,踩下剎車,車子逐漸減速至0:
前進時左右轉向:
倒擋時左右轉型:
原始碼:
採用manager of manager的方式,使用了單例模式。
1.Car_Mng類負責管理車輛的物理模擬
2.Input_Mng類負責接受使用者的鍵盤輸入資訊
3.UI_Mng類負責更新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; //最大的前進力矩 public float maxSpeed; //車輛最大前進速度 public float maxReversMotorTorque; //最大的倒車力矩 public float maxBrakeToeque; //最大的剎車阻力 public float maxSteeringAngle; //主動輪最大的旋轉角度 public Rigidbody car; //車輛的剛體 public WheelCollider[] coliders; //車輪碰撞器 public GameObject[] wheelMesh; //車輪模型 public CarState carState=CarState.Off; //車輛啟動狀態 public GearState gearState = GearState.ParkingGear; //車輛的擋位 public bool isHandBrakeON; //是否拉起手剎的標誌位 public float currentSpeed=0; //計算當前車輛的速度 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(); //更新手剎狀態 } private void FixedUpdate() { if (gearState == GearState.ForwardGear || gearState == GearState.ReversGear) { BrakeCalculate(); //剎車計算 阻力 AccCalculate(); //油門計算 動力 } SteerCalculate(); UpdateCarSpeed(); //更新車子的速度 AutoChangeGear(); //自動換擋 自動擋的車子 SynchronousWheelMesh(); //將車輪的狀態同步給車的模型 } 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(); } } } //更新手剎狀態 public void StartCar() //啟動車輛 { carState = CarState.On; } public void StopCar() //停車 { carState = CarState.Off; //停止接收油門、方向盤、剎車訊號 gearState = GearState.ParkingGear; //掛上停車擋 PullupHandbrake(); //拉起手剎 } void PullupHandbrake() //拉起手剎,相當於阻力矩最大,直接Freeze車輛剛體的運動 { isHandBrakeON = true; //設定標誌位 //僅保留y軸向的運動 car.constraints = RigidbodyConstraints.FreezeRotation | RigidbodyConstraints.FreezePositionX | RigidbodyConstraints.FreezePositionZ; } void PullDownHandbrake() //放下手剎,解鎖運動 { isHandBrakeON = false; //解鎖所有運動 car.constraints = RigidbodyConstraints.None; } void BrakeCalculate() //計算剎車的阻力 { var value = Input_Mng.Instance.GetBrakeValue(); //讀取剎車阻力 var brakeToequePerWheel = maxBrakeToeque / 2 * value / 255; //計算一個車輪的阻力 coliders[0].motorTorque = 0; coliders[1].motorTorque = 0; for (int i = 0; i < 6; i++) { coliders[i].brakeTorque = brakeToequePerWheel; } // Debug.Log("剎車阻力:"+ brakeToequePerWheel); } void AccCalculate() //油門動力計算 { if (gearState == GearState.ForwardGear) //前進 { var value = Input_Mng.Instance.GetAcceleratorValue(); if (value != 0) //加速行駛 { if(MeterPerSeconds2KmPerHour(currentSpeed) <= 150) { var accToequePerWheel = maxMotorTorque * value / 255; //計算一個車輪的動力 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("無動力"); for (int i = 0; i < 6; i++) { coliders[i].motorTorque = 0; } } } } else //倒車 { var value = Input_Mng.Instance.GetAcceleratorValue(); var accToequePerWheel = maxReversMotorTorque / 2 * value / 255; //計算一個車輪的動力 coliders[0].motorTorque = -accToequePerWheel; coliders[1].motorTorque = -accToequePerWheel; } } void SteerCalculate() //計算轉向 { var value= Input_Mng.Instance.GetSteerValue(); var steerAngle = (value - 128) / 128 * maxSteeringAngle; //計算旋轉角度 coliders[0].steerAngle = steerAngle; coliders[1].steerAngle = steerAngle; } void AutoChangeGear() //自動擋,前進時根據車輛的速度自動切換擋位 { 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,//關機狀態 On = 1,//執行狀態 } public enum GearState { ParkingGear = 1,//停車擋 ReversGear = 2,//倒擋 NeutralGear = 3,//空擋 ForwardGear = 4,//前進擋 } 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; //剎車對應的鍵盤按鍵 public float brakeValue = 0; //剎車值 public bool isBra = false; private KeyCode accKeyCode=KeyCode.W; //油門對應的鍵盤按鍵 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; //停車對應的按鍵 private KeyCode reversKeyCode = KeyCode.Alpha2; //倒車對應的按鍵 private KeyCode neutralKeyCode = KeyCode.Alpha3; //空擋對應的按鍵 private KeyCode forwardKeyCode = KeyCode.Alpha4; //前進擋對應的按鍵 private KeyCode handBrakeKeyCode = KeyCode.H; //手剎對應的按鍵 public float GetBrakeValue() //獲取剎車值 { return brakeValue; } public float GetAcceleratorValue() //獲取油門值 { return acceleratorValue; } public float GetSteerValue() { return steerValue; } //獲取轉彎值 private void Awake() { Instance = this; } private void Update() { if (Car_Mng.Instance.carState == CarState.On) //當車輛啟動後,檢測油門剎車和擋位變換 { 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,255); isAcc = true; } else { acceleratorValue = 0; isAcc = false; } } //更新油門狀態 void UpdateBrakeValue(KeyCode BraCode) //更新剎車狀態 { if (Input.GetKey(BraCode)) { brakeValue += 255 * Time.deltaTime; brakeValue = Mathf.Clamp(brakeValue,255); isBra = true; } else { brakeValue = 0; isBra = false; } } void UpdateSteerValue() //更新方向盤狀態 { if (Input.GetKey(leftSteerKeyCode)) { steerValue -= 255 * Time.deltaTime; //0.5秒左側打死 steerValue = Mathf.Clamp(steerValue,255); }else if(Input.GetKey(rightSteerKeyCode)) { steerValue += 255 * Time.deltaTime; //0.5秒右側打死 steerValue = Mathf.Clamp(steerValue,255); } else { steerValue = 128; } } void UpdateGeerState() //更新擋位狀態 { if (Input.GetKeyDown(parkingKeyCode)) //設定為停車檔 { 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)) //前進擋 { 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; //前進擋 public Image NeutralBg; //空擋 public Image ReversBg; //倒車檔 public Image HandBrakeBg; //手剎 public Text speedText; //速度顯示 public Text speedGearText; //擋位顯示 public Image SwitchBg; //開關背景 public Text Switchtext; //開關顯示文字 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 = "自動擋"; 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(); //關閉車輛 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) //如果處於開機狀態,則停機 { Car_Mng.Instance.StopCar(); //關閉車輛 OnCarShutDown();//更新UI }else { Car_Mng.Instance.StartCar(); //啟動車子 OnCarStart();//更新UI } } private void OnCarStart() //車輛啟動時更新ui { SwitchBg.color = UnityEngine.Color.red; Switchtext.text = "關閉車輛"; } private void OnCarShutDown() //車輛關閉時執行的邏輯 { SwitchBg.color = UnityEngine.Color.green; Switchtext.text = "啟動車輛"; } }
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。