这篇文章主要讲解了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可以控制车辆左右转向
运行结果图:
启动车辆,拉起手刹,挂前进挡,车辆进入怠速模式,缓慢进行加速。
速度提升到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, 0, 255); isAcc = true; } else { acceleratorValue = 0; isAcc = false; } } //更新油门状态 void UpdateBrakeValue(KeyCode BraCode) //更新刹车状态 { if (Input.GetKey(BraCode)) { brakeValue += 255 * Time.deltaTime; brakeValue = Mathf.Clamp(brakeValue, 0, 255); isBra = true; } else { brakeValue = 0; isBra = false; } } void UpdateSteerValue() //更新方向盘状态 { if (Input.GetKey(leftSteerKeyCode)) { steerValue -= 255 * Time.deltaTime; //0.5秒左侧打死 steerValue = Mathf.Clamp(steerValue, 0, 255); }else if(Input.GetKey(rightSteerKeyCode)) { steerValue += 255 * Time.deltaTime; //0.5秒右侧打死 steerValue = Mathf.Clamp(steerValue, 0, 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 = "启动车辆"; } }
看完上述内容,是不是对Unity平台模拟自动挡驾驶汽车的详细解析有进一步的了解,如果还想学习更多内容,欢迎关注亿速云行业资讯频道。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。