1. 程式人生 > 程式設計 >Unity平臺模擬自動擋駕駛汽車

Unity平臺模擬自動擋駕駛汽車

自動擋汽車功能分析:

(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可以控制車輛左右轉向

執行結果圖:

啟動車輛,拉起手剎,掛前進擋,車輛進入怠速模式,緩慢進行加速。

Unity平臺模擬自動擋駕駛汽車

速度提升到12km/h後勻速行駛,繼續加速需要踩下油門。

Unity平臺模擬自動擋駕駛汽車

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

Unity平臺模擬自動擋駕駛汽車

前進時踩下剎車後車子逐漸減速至0:

Unity平臺模擬自動擋駕駛汽車

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

Unity平臺模擬自動擋駕駛汽車

前進時左右轉向:

Unity平臺模擬自動擋駕駛汽車

倒擋時左右轉型:

Unity平臺模擬自動擋駕駛汽車

原始碼:

採用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 = "啟動車輛";
 }
 

}

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。