自动挡汽车功能分析:
(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 = "启动车辆"; } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。
岗位:全栈开发工程师 薪资福利:30-55k转正 实习250-300/天 六险一金(12%) 餐补 股票期权 965 base:上海 一面: 1、vue3和vue2的区别 2、vue2是响应式的吗?介绍一下原理 3、介绍一下双向绑定的原理 4、为什么使用框架会比使用Html、Css、Javascript开发速度快 5、介绍一下浏览器重绘 6、什么是回流 7、vue computed和data 双向
9.17 自动驾驶 感知算法实习 一面 自我介绍 ResNet数学原理 one two stage网络代表和区别 SSD yolo Faster RCNN roi pooling和roi algin torch动态图 python装饰器 CaDDN流程 DETR流程 DETR3D deformable attention mmcv中的hook runner机制 反向传播 mAP计算 9.21 二面
7.17 一面 1 先写个算法,无重复的最长字串 写完讲解思路 2 自我介绍 3 数据库事务 4 索引 底层结构 5 linux常用命令 统计行数(应该是wc 没答上来 6 进程线程区别 7 二叉树求最大深度,口述 8 算法找出重复数组元素 9 反问 2h后通知二面 7.18 二面 1 讲一下你的实习 2 深挖项目 做了哪些事 3 现场对登录框进行功能测试 4 自身的不足有哪些 5 反问 整体难度
聊天机器人:嘿,你介意回答几个问题吗? 顾客:如果是,继续提问/如果不是,向顾客致谢并停止对话。 我在Twilio Autopilot上使用了示例调查机器人,但它实际上没有“if/else”场景。如果Twilio没有它,那么还有其他适合于此的聊天机器人吗?
1. 自我介绍 2. 简单聊了一下项目 召回率 指标 具体实现方案 检测错误的情况 3. C++ 相关 继承封装多态的特点 多态是怎么实现的 有什么好处 虚函数是什么 纯虚函数是什么 析构函数和构造函数 子类实例化的时候 析构和构造的顺序是什么 构造可以使用纯虚函数吗 4. 计算机网络: TCP UDP的区别和应用场景 5.操作系统 进程和线