阅读量:0
👨💻个人主页:@元宇宙-秩沅
👨💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅!
👨💻 本文由 秩沅 原创
👨💻 专栏交流 | 🧧 |
---|---|
🟥✨Unity100个实战基础✨🟥 | 🎁 |
🟦✨ Unity100个精华一记✨🟦 | 🎁 |
🟩✨ Unity50个demo案例教程✨🟩 | 🎁 |
🟨✨ Unity100个精华细节BUG✨🟨 | 🎁 |
⭐🅰️Unity3D赛车游戏⭐
文章目录
⭐前言⭐
–
😶🌫️版本: Unity2021
😶🌫️适合人群:Unity初学者
😶🌫️学习目标:3D赛车游戏的基础制作
😶🌫️技能掌握:
🎶(A)车辆优化——阿克曼转向添加
😶🌫️认识阿克曼转向
引用:阿克曼转向是一种现代汽车的转向方式,也是移动机器人的一种运动模式,在汽车转弯的时候,内外轮转过的角度不一样,内侧轮胎转弯半径小于外侧轮胎
原理图:
_____________
简单理解:一个杆子把左轮和右轮连接起来一起转。
左轮的旋转的半径小于右轮
优点:大大减小了车轮转向需要的空间,转向更加稳定
- 阿克曼公式:
β为汽车前外轮转角,α为汽车前内轮转角,K为两主销中心距,L为轴距。
😶🌫️区别:
未添加阿克曼转向之前的原理:
通过控制轮子的最大转向范围来转向
添加之后
更稳定,机动性更强
😶🌫️关键代码
- 后轮距尺寸设置为1.5f ,轴距设置为2.55f ,radius 默认为6,radius 越大旋转的角度看起来越小
if (horizontal > 0 ) { //后轮距尺寸设置为1.5f ,轴距设置为2.55f ,radius 默认为6,radius 越大旋转的角度看起来越小 wheels[0].steerAngle = Mathf.Rad2Deg * Mathf.Atan(2.55f / (radius + (1.5f / 2))) * horizontal; wheels[1].steerAngle = Mathf.Rad2Deg * Mathf.Atan(2.55f / (radius - (1.5f / 2))) * horizontal; } else if (horizontal < 0 ) { wheels[0].steerAngle = Mathf.Rad2Deg * Mathf.Atan(2.55f / (radius - (1.5f / 2))) * horizontal; wheels[1].steerAngle = Mathf.Rad2Deg * Mathf.Atan(2.55f / (radius + (1.5f / 2))) * horizontal; } else { wheels[0].steerAngle =0; wheels[1].steerAngle =0; }
😶🌫️完整代码
using System.Collections; using System.Collections.Generic; using UnityEngine; //------------------------------------- //————————————————————————————————————— //___________项目: ______________ //___________功能: 车轮的运动 //___________创建者:_______秩沅________ //_____________________________________ //------------------------------------- //驱动模式的选择 public enum EDriveType { frontDrive, //前轮驱动 backDrive, //后轮驱动 allDrive //四驱 } public class WheelMove : MonoBehaviour { //------------------------------------------- //四个轮子的碰撞器 public WheelCollider[] wheels ; //网格的获取 public GameObject[] wheelMesh; //扭矩力度 public float motorflaot = 200f; //初始化三维向量和四元数 private Vector3 wheelPosition = Vector3.zero; private Quaternion wheelRotation = Quaternion.identity; //------------------------------------------- //驱动模式选择 _默认前驱 public EDriveType DriveType = EDriveType.frontDrive; //轮半径 public float radius = 0.25f; private void FixedUpdate() { WheelsAnimation(); //车轮动画 VerticalContorl(); //驱动管理 HorizontalContolr(); //转向管理 } //垂直轴方向管理(驱动管理) public void VerticalContorl() { switch (DriveType) { case EDriveType.frontDrive: //选择前驱 if (InputManager.InputManagerment.vertical != 0) //当按下WS键时生效 { for (int i = 0; i < wheels.Length - 2; i++) { //扭矩力度 wheels[i].motorTorque = InputManager.InputManagerment.vertical *(motorflaot / 2); //扭矩马力归半 } } break; case EDriveType.backDrive: //选择后驱 if (InputManager.InputManagerment.vertical != 0) //当按下WS键时生效 { for (int i = 2; i < wheels.Length; i++) { //扭矩力度 wheels[i].motorTorque = InputManager.InputManagerment.vertical * (motorflaot / 2); //扭矩马力归半 } } break; case EDriveType.allDrive: //选择四驱 if (InputManager.InputManagerment.vertical != 0) //当按下WS键时生效 { for (int i = 0; i < wheels.Length; i++) { //扭矩力度 wheels[i].motorTorque = InputManager.InputManagerment.vertical * ( motorflaot / 4 ); //扭矩马力/4 } } break; default: break; } } //水平轴方向管理(转向管理) public void HorizontalContolr() { if (InputManager.InputManagerment.horizontal > 0) { //后轮距尺寸设置为1.5f ,轴距设置为2.55f ,radius 默认为6,radius 越大旋转的角度看起来越小 wheels[0].steerAngle = Mathf.Rad2Deg * Mathf.Atan(2.55f / (radius + (1.5f / 2))) * InputManager.InputManagerment.horizontal; wheels[1].steerAngle = Mathf.Rad2Deg * Mathf.Atan(2.55f / (radius - (1.5f / 2))) * InputManager.InputManagerment.horizontal; } else if (InputManager.InputManagerment.horizontal < 0) { wheels[0].steerAngle = Mathf.Rad2Deg * Mathf.Atan(2.55f / (radius - (1.5f / 2))) * InputManager.InputManagerment.horizontal; wheels[1].steerAngle = Mathf.Rad2Deg * Mathf.Atan(2.55f / (radius + (1.5f / 2))) * InputManager.InputManagerment.horizontal; } else { wheels[0].steerAngle = 0; wheels[1].steerAngle = 0; } } //车轮动画相关 public void WheelsAnimation() { for (int i = 0; i < wheels.Length ; i++) { //获取当前空间的车轮位置 和 角度 wheels[i].GetWorldPose(out wheelPosition, out wheelRotation); //赋值给 wheelMesh[i].transform.position = wheelPosition; print(wheelRotation); wheelMesh[i].transform.rotation = wheelRotation * Quaternion .AngleAxis (90,Vector3 .forward ); } } } } } }
🎶(B)车辆优化——车身持续稳定的优化
WheelMove脚本 ——> CarMoveControl脚本 更改脚本名
😶🌫️速度属性实时转换
- 每小时多少公里 和 每秒多少米的对应关系 ——1m/s = 3.6km/h
速度属性建议改成Int类型 ,float类型会上下浮动不准确
//1m/s = 3.6km/h Km_H =(int)(rigidbody.velocity.magnitude * 3.6) ; Km_H = Mathf.Clamp( Km_H,0, 200 ); //油门速度为 0 到 200 Km/H之间
- 相机测速 m/s
//相机监测实时速度 Control = target.GetComponent<CarMoveControl>(); speed = (int )Control.Km_H / 4; speed = Mathf.Clamp(0, 55,speed ); //对应最大200公里每小时
- 添加四个轮子的实时速度,对应虚度属性,可以明显的观察四驱和二驱的汽车动力
//车辆物理属性相关 public void VerticalAttribute() { //1m/s = 3.6km/h Km_H =(int)(rigidbody.velocity.magnitude * 3.6) ; Km_H = Mathf.Clamp( Km_H,0, 200 ); //油门速度为 0 到 200 Km/H之间 //显示每个轮胎的扭矩 f_right = wheels[0].motorTorque; f_left = wheels[1].motorTorque; b_right = wheels[2].motorTorque; b_left = wheels[3].motorTorque; }
😶🌫️为车子添加下压力
知识百科: 什么是下压力
下压力是车在行进中空气在车体上下流速不一产生的,使空气的总压力指向地面从而增加车的抓地力.
速度越大,下压力越大,抓地更强,越不易翻车
- 关键代码
//-------------下压力添加----------------- //速度越大,下压力越大,抓地更强 rigidbody.AddForce(-transform.up * downForceValue * rigidbody.velocity .magnitude );
😶🌫️质心的添加centerMess
知识百科:什么是质心?——质量中心
汽车制造商在设计汽车时会考虑质心的位置和重心高度,以尽可能减小质心侧偏角。 一些高性能汽车甚至会采用主动悬挂系统来控制车身侧倾,从而减小质心侧偏角,提高车辆的稳定性和操控性。
质量中心越贴下,越不容易翻
//-------------质量中心同步---------------- //质量中心越贴下,越不容易翻 rigidbody.centerOfMass = CenterMass;
- 手刹的添加
//手刹管理 public void HandbrakControl() { if(InputManager.InputManagerment .handbanl ) { //后轮刹车 wheels[2].brakeTorque = brakVualue; wheels[3].brakeTorque = brakVualue; } else { wheels[2].brakeTorque = 0; wheels[3].brakeTorque = 0; } }
😶🌫️轮胎的平滑度的显示
wheelhit.forwardSlip;用来观看刹车轮胎在滚动方向上打滑。加速滑移为负,制动滑为正
_______
for (int i = 0; i < slip.Length; i++) { WheelHit wheelhit; wheels[i].GetGroundHit(out wheelhit); slip[i] = wheelhit.forwardSlip; //轮胎在滚动方向上打滑。加速滑移为负,制动滑为正 }
🎶(C)脚本记录
CarMoveContorl
using System.Collections; using System.Collections.Generic; using UnityEngine; //------------------------------------- //————————————————————————————————————— //___________项目: ______________ //___________功能: 车轮的运动 //___________创建者:_______秩沅________ //_____________________________________ //------------------------------------- //驱动模式的选择 public enum EDriveType { frontDrive, //前轮驱动 backDrive, //后轮驱动 allDrive //四驱 } public class CarMoveControl : MonoBehaviour { //------------------------------------------- //四个轮子的碰撞器 public WheelCollider[] wheels ; //网格的获取 public GameObject[] wheelMesh; //初始化三维向量和四元数 private Vector3 wheelPosition = Vector3.zero; private Quaternion wheelRotation = Quaternion.identity; //------------------------------------------- //驱动模式选择 _默认前驱 public EDriveType DriveType = EDriveType.frontDrive; //----------车辆属性特征----------------------- //车刚体 public Rigidbody rigidbody; //轮半径 public float radius = 0.25f; //扭矩力度 public float motorflaot = 8000f; //刹车力 public float brakVualue = 800000f; //速度:每小时多少公里 public int Km_H; //下压力 public float downForceValue = 1000f; //四个轮胎扭矩力的大小 public float f_right; public float f_left; public float b_right; public float b_left; //车轮打滑参数识别 public float[] slip ; //质心 public Vector3 CenterMass; //一些属性的初始化 private void Start() { rigidbody = GetComponent<Rigidbody>(); slip = new float[4]; } private void FixedUpdate() { VerticalAttribute();//车辆物理属性管理 WheelsAnimation(); //车轮动画 VerticalContorl(); //驱动管理 HorizontalContolr(); //转向管理 HandbrakControl(); //手刹管理 } //车辆物理属性相关 public void VerticalAttribute() { //---------------速度实时--------------- //1m/s = 3.6km/h Km_H =(int)(rigidbody.velocity.magnitude * 3.6) ; Km_H = Mathf.Clamp( Km_H,0, 200 ); //油门速度为 0 到 200 Km/H之间 //--------------扭矩力实时--------------- //显示每个轮胎的扭矩 f_right = wheels[0].motorTorque; f_left = wheels[1].motorTorque; b_right = wheels[2].motorTorque; b_left = wheels[3].motorTorque; //-------------下压力添加----------------- //速度越大,下压力越大,抓地更强 rigidbody.AddForce(-transform.up * downForceValue * rigidbody.velocity .magnitude ); //-------------质量中心同步---------------- //质量中心越贴下,越不容易翻 rigidbody.centerOfMass = CenterMass; } //垂直轴方向运动管理(驱动管理) public void VerticalContorl() { switch (DriveType) { case EDriveType.frontDrive: //选择前驱 if (InputManager.InputManagerment.vertical != 0) //当按下WS键时生效 { for (int i = 0; i < wheels.Length - 2; i++) { //扭矩力度 wheels[i].motorTorque = InputManager.InputManagerment.vertical *(motorflaot / 2); //扭矩马力归半 } } else { for (int i = 0; i < wheels.Length - 2; i++) { //扭矩力度 wheels[i].motorTorque = 0; } } break; case EDriveType.backDrive: //选择后驱 if (InputManager.InputManagerment.vertical != 0) //当按下WS键时生效 { for (int i = 2; i < wheels.Length; i++) { //扭矩力度 wheels[i].motorTorque = InputManager.InputManagerment.vertical * (motorflaot / 2); //扭矩马力归半 } } else { for (int i = 2; i < wheels.Length ; i++) { //扭矩力度 wheels[i].motorTorque = 0; } } break; case EDriveType.allDrive: //选择四驱 if (InputManager.InputManagerment.vertical != 0) //当按下WS键时生效 { for (int i = 0; i < wheels.Length; i++) { //扭矩力度 wheels[i].motorTorque = InputManager.InputManagerment.vertical * ( motorflaot / 4 ); //扭矩马力/4 } } else { for (int i = 0; i < wheels.Length; i++) { //扭矩力度 wheels[i].motorTorque = 0; } } break; default: break; } } //水平轴方向运动管理(转向管理) public void HorizontalContolr() { if (InputManager.InputManagerment.horizontal != 0) { //后轮距尺寸设置为1.5f ,轴距设置为2.55f ,radius 默认为6,radius 越大旋转的角度看起来越小 wheels[0].steerAngle = Mathf.Rad2Deg * Mathf.Atan(2.55f / (radius + (1.5f / 2))) * InputManager.InputManagerment.horizontal; wheels[1].steerAngle = Mathf.Rad2Deg * Mathf.Atan(2.55f / (radius + (1.5f / 2))) * InputManager.InputManagerment.horizontal; } else { wheels[0].steerAngle = 0; wheels[1].steerAngle = 0; } } //手刹管理 public void HandbrakControl() { if(InputManager.InputManagerment .handbanl ) { //后轮刹车 wheels[2].brakeTorque = brakVualue; wheels[3].brakeTorque = brakVualue; } else { wheels[2].brakeTorque = 0; wheels[3].brakeTorque = 0; } //------------刹车效果平滑度显示------------ for (int i = 0; i < slip.Length; i++) { WheelHit wheelhit; wheels[i].GetGroundHit(out wheelhit); slip[i] = wheelhit.forwardSlip; //轮胎在滚动方向上打滑。加速滑移为负,制动滑为正 } } //车轮动画相关 public void WheelsAnimation() { for (int i = 0; i < wheels.Length ; i++) { //获取当前空间的车轮位置 和 角度 wheels[i].GetWorldPose(out wheelPosition, out wheelRotation); //赋值给 wheelMesh[i].transform.position = wheelPosition; wheelMesh[i].transform.rotation = wheelRotation * Quaternion .AngleAxis (90,Vector3 .forward ); } } }
CameraFllow
using System.Collections; using System.Collections.Generic; using UnityEngine; //------------------------------------- //————————————————————————————————————— //___________项目: ______________ //___________功能: 相机的跟随 //___________创建者:秩沅_______________ //_____________________________________ //------------------------------------- public class CameraFllow : MonoBehaviour { //目标物体 public Transform target; private CarMoveControl Control; public int speed; //鼠标滑轮的速度 public float ScrollSpeed = 45f; //Y轴差距参数 public float Ydictance = 0f; public float Ymin = 0f; public float Ymax = 4f; //Z轴差距参数 public float Zdictance = 4f; public float Zmin = 4f; public float Zmax = 8f; //相机看向的角度 和最終位置 public float angle = -25 ; public Vector3 lookPosition; void LateUpdate() { //Z轴和Y轴的距离和鼠标滑轮联系 Ydictance += Input.GetAxis("Mouse ScrollWheel") * ScrollSpeed * Time.deltaTime;//平滑效果 Zdictance += Input.GetAxis("Mouse ScrollWheel") * ScrollSpeed * Time.deltaTime; //設置Y軸和x轴的滚轮滑动范围 Ydictance = Mathf.Clamp(Ydictance , Ymin ,Ymax ) ; Zdictance = Mathf.Clamp(Zdictance , Zmin, Zmax ) ; //确定好角度,四元数 * 三维向量 = 三维向量 lookPosition = Quaternion.AngleAxis(angle, target .right) * -target.forward ; //更新位置 transform.position = target.position + Vector3.up * Ydictance - lookPosition * Zdictance ; //更新角度 transform.rotation = Quaternion.LookRotation(lookPosition); //实时速度 Control = target.GetComponent<CarMoveControl>(); speed = (int )Control.Km_H / 4; speed = Mathf.Clamp(speed,0, 55 ); //对应最大200公里每小时 } }
InputMana
using System.Collections; using System.Collections.Generic; using UnityEngine; //------------------------------------- //————————————————————————————————————— //___________项目: ______________ //___________功能: 输入控制管理器 //___________创建者:秩沅_______________ //_____________________________________ //------------------------------------- public class InputManager : MonoBehaviour { //单例模式管理 static private InputManager inputManagerment; static public InputManager InputManagerment => inputManagerment; public float horizontal; //水平方向动力值 public float vertical; //垂直方向动力值 public bool handbanl; //手刹动力值 void Awake() { inputManagerment = this; } void Update() { //与Unity中输入管理器的值相互对应 horizontal = Input.GetAxis("Horizontal"); vertical = Input.GetAxis("Vertical"); handbanl = Input.GetAxis("Jump")!= 0 ? true :false ; //按下空格键时就是1,否则为0 } }
⭐🅰️⭐
你们的点赞👍 收藏⭐ 留言📝 关注✅是我持续创作,输出优质内容的最大动力!、