👨💻个人主页:@元宇宙-秩沅
👨💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅!
👨💻 本文由 秩沅 原创
👨💻 收录于专栏:Unity游戏demo
⭐🅰️Unity3D赛车游戏⭐
⭐前言⭐
–
😶🌫️版本: Unity2021
😶🌫️适合人群:Unity初学者
😶🌫️学习目标:3D赛车游戏的基础制作
😶🌫️技能掌握:
⭐常见问题⭐
🎶(A)车辆模型——自动变速箱的添加
😶🌫️ 变档显示
//速度转文本字符
Km_H.text = control.Km_H.ToString();
//挡位转文本字符
gearsNum.text = control.gerrsNurrentNum + 1 .ToString();
😶🌫️ 自动换挡
不仅仅是发动机牵引着汽车去运动。是发动机跟轮胎一起控制汽车去前进,我们前面没有添加发动机,就是靠轮胎的扭矩力去控制汽车的前进
怎么来理解自动档位变速箱呢?当发动机。每个档位的发动机。它超过八千转的时候就要换挡了。所以当我们现在设置发动机的最大转是八千,最小转是五千,超过八千转我们就自动加档。小于了五千转,我们就自动减档。——这个最大转和最小转是模拟跑车的。
当然,判断换挡的依据不仅仅是靠超过最大的这个发动机的最大转,连同每个档位设置的那个限速作为一起判断依据。如下图所示,每个档位的限速如果超过了这个限速,并且超过了最大转速,我们就换挡。
- 我们用代码来实现这个功能
//换挡管理
//换挡管理
public void shifterGearsChange()
{
switch (nowGearsType)
{
//档位类型是手动档的时候
case EChooseGreas.handMovement:
if (InputManager.InputManagerment.addGears) //如果按下E键,加挡
{
if (gerrsNurrentNum < gears.Length - 1)
gerrsNurrentNum++;
}
if (InputManager.InputManagerment.lowGears) //如果按下Q键,减档
{
if (gerrsNurrentNum > 0)
gerrsNurrentNum--;
}
break;
//档位类型是自动档的时候handMovement
case EChooseGreas.aotomutic:
//如果车子不在地面不会自动换档
if (!IsGrounp()) return;
//当发动机转速大于最高转速 并且 速度也超过了相应挡位的限速 ,数组不越界 并且不是倒车 就加档
if (engineRPM > maxRPM && Km_H >= gearSpeed[gerrsNurrentNum] && gerrsNurrentNum < gears.Length - 1 && !BackCar())
gerrsNurrentNum++;
//当发动机小于最小转时 减档 (此时未加判断是因为就是要 更好的减速)
if (engineRPM < minRPM && gerrsNurrentNum > 0)
gerrsNurrentNum--;
break;
default:
break;
}
😶🌫️ 倒车的问题
此时并不是我们按下S键就代表倒车了,而是当整个车子它的速度向后面,也就是说整个车辆它向后移动的时候才叫到车。所以我们的判断依据不仅仅是根据按了S键才倒车。并且倒车的时候,我们的仪表盘上面会显示出一个R的一个倒车的表示字母。
- CarMoveContorl
- UIContorl
😶🌫️ 解决空中也换挡的问题
当车飞到空中的时候也存在我们自动换挡的情况。所以我们要避免这个情况。就要加一个地面判断。
//是否接触地面判断
public bool IsGrounp()
{
for (int i = 0; i < 4; i++)
{
//如果车轮不在地面就返回fasle
if (wheels[i].isGrounded == false)
return false;
}
return true;
}
🎶(B)脚本记录
😶🌫️CarMoveControl
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//-------------------------------------
//—————————————————————————————————————
//___________项目: ______________
//___________功能: 车轮的运动
//___________创建者:_______秩沅________
//_____________________________________
//-------------------------------------
//驱动模式的选择
internal enum EDriveType
{
frontDrive, //前轮驱动
backDrive, //后轮驱动
allDrive //四驱
}
//自动挡手动挡的选择
internal enum EChooseGreas
{
aotomutic, //自动挡
handMovement //手动档
}
public class CarMoveControl : MonoBehaviour
{
//-------------------------------------------
[Header("----------轮碰撞器特征-------------")]
//四个轮子的碰撞器
public WheelCollider[] wheels;
[SerializeField]
//网格的获取
private GameObject[] wheelMesh;
//四个轮胎扭矩力的大小
public float f_right;
public float f_left;
public float b_right;
public float b_left;
//车轮打滑参数识别
public float[] slip;
//初始化三维向量和四元数
private Vector3 wheelPosition = Vector3.zero;
private Quaternion wheelRotation = Quaternion.identity;
//-------------------------------------------
//驱动模式选择 _默认前驱
[SerializeField]
private EDriveType DriveType = EDriveType.frontDrive;
[Header("----------车辆属性特征-------------")]
//车刚体
public Rigidbody rigidbody;
//轮半径
public float radius = 0.25f;
//扭矩力度
public float motorflaot = 8000f;
//刹车力
public float brakVualue = 800000f;
//速度:每小时多少公里
public int Km_H;
//加速的速度增量
public float shiftSpeed = 4000;
//下压力
public float downForceValue = 1000f;
//质心
public Vector3 CenterMass;
[Header("----------发动机属性特征-------------")]
//发动机马力与转速曲线
public AnimationCurve enginePowerCurve;
//车轮的RPM平均转速
public float wheelsRPM;
//发动机转速
public float engineRPM;
//汽车齿轮比(挡位)
public float[] gears;
//默认为自动挡
[SerializeField]
private EChooseGreas nowGearsType = EChooseGreas.aotomutic;
//当前的挡位
public int gerrsNurrentNum = 0;
//发动机的最大转,和最小转
public float maxRPM = 8000f, minRPM = 5000f;
//每个挡位的限速
public float[] gearSpeed;
//差速比
public float diffrirentialRation;
//离合器
private float clutch;
//平滑时间参数
private float smoothTime = 0.09f;
//一些属性的初始化
private void Start()
{
//刚体初始化
rigidbody = GetComponent<Rigidbody>();
//轮胎平滑参数数组初始化
slip = new float[4];
}
private void FixedUpdate()
{
VerticalAttribute();//车辆物理属性管理
WheelsAnimation(); //车轮动画
CarEnginePower(); //汽车发动机
HorizontalContolr(); //转向管理
HandbrakControl(); //手刹管理
ShiftSpeed();//加速相关
}
//车辆物理属性相关
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 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 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);
}
}
//加速以及动画相关
public void ShiftSpeed()
{
//按下shift加速键时
if (InputManager.InputManagerment.shiftSpeed)
{
//向前增加一个力
rigidbody.AddForce(-transform.forward * shiftSpeed);
}
else
{
rigidbody.AddForce(transform.forward * 0);
}
}
//汽车引擎发动机相关
public void CarEnginePower()
{
WheelRPM();//将轮轴的转速获取
// 扭矩力(发动机功率) = 功率=扭矩*转速*n
motorflaot = -enginePowerCurve.Evaluate(engineRPM) * gears[gerrsNurrentNum];
float velocity = 0.0f;
//发动机的转速 与 车轮转速 和 挡位比率 成比例
engineRPM = Mathf.SmoothDamp(engineRPM, 1000 + Mathf.Abs(wheelsRPM) * 3.6f * (gears[gerrsNurrentNum]), ref velocity, smoothTime);
print(engineRPM);
VerticalContorl(); //驱动管理
shifterGearsChange(); //换挡管理
}
//获得车轮的转速
public void WheelRPM()
{
float sum = 0;
for (int i = 0; i < 4; i++)
{
sum += wheels[i].rpm;
}
//四个车轮轮轴的平均转速
wheelsRPM = sum / 4;
}
//换挡管理
public void shifterGearsChange()
{
switch (nowGearsType)
{
//档位类型是手动档的时候
case EChooseGreas.handMovement:
if (InputManager.InputManagerment.addGears) //如果按下E键,加挡
{
if (gerrsNurrentNum < gears.Length - 1)
gerrsNurrentNum++;
}
if (InputManager.InputManagerment.lowGears) //如果按下Q键,减档
{
if (gerrsNurrentNum > 0)
gerrsNurrentNum--;
}
break;
//档位类型是自动档的时候handMovement
case EChooseGreas.aotomutic:
//如果车子不在地面不会自动换档
if (!IsGrounp()) return;
//当发动机转速大于最高转速 并且 速度也超过了相应挡位的限速 ,数组不越界 并且不是倒车 就加档
if (engineRPM > maxRPM && Km_H >= gearSpeed[gerrsNurrentNum] && gerrsNurrentNum < gears.Length - 1 && !BackCar())
gerrsNurrentNum++;
//当发动机小于最小转时 减档 (此时未加判断是因为就是要 更好的减速)
if (engineRPM < minRPM && gerrsNurrentNum > 0)
gerrsNurrentNum--;
break;
default:
break;
}
}
//倒车判断
public bool BackCar()
{
//当车轮的转速小于0 则代表倒车
if (wheelsRPM > 1) return true;
else return false;
}
//是否接触地面判断
public bool IsGrounp()
{
for (int i = 0; i < 4; i++)
{
//如果车轮不在地面就返回fasle
if (wheels[i].isGrounded == false)
return false;
}
return true;
}
}
😶🌫️InputManager
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; //手刹动力值
public bool shiftSpeed; //加速shift键
//public float clutch; //离合器
public bool addGears; //升档
public bool lowGears; //降档
void Awake()
{
inputManagerment = this;
}
void FixedUpdate()
{
//与Unity中输入管理器的值相互对应
horizontal = Input.GetAxis("Horizontal");
vertical = Input.GetAxis("Vertical");
handbanl = Input.GetAxis("Jump")!= 0 ? true :false ; //按下空格键时就是1,否则为0
shiftSpeed = Input.GetKey(KeyCode.LeftShift) ? true : false;
//clutch = Input.GetKey(KeyCode.LeftShift) ? 0 : Mathf.Lerp(clutch ,1,Time .deltaTime);
addGears = Input.GetKeyDown(KeyCode.E ) ? true : false;
lowGears = Input.GetKeyDown(KeyCode.Q ) ? true : false;
}
}
😶🌫️CameraContorl
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//-------------------------------------
//—————————————————————————————————————
//___________项目: ______________
//___________功能: 相机的管理
//___________创建者:秩沅_______________
//_____________________________________
//-------------------------------------
public class CameraContorl : MonoBehaviour
{
//目标物体
public Transform target;
private CarMoveControl Control;
public float speed;
[Header("----------相机基础属性-------------")]
//鼠标滑轮的速度
public float ScrollSpeed = 45f;
public float Ydictance = 0f;
private float Ymin = 0f;
private float Ymax = 4f;
public float Zdictance = 4f;
private float Zmin = 4f;
private float Zmax = 15f;
//相机看向的角度 和最終位置
public float angle = -25 ;
private Vector3 lastPosition;
private Vector3 lookPosition;
[Header("----------加速时相机属性-------------")]
//加速时的跟随力度
[Range(1, 5)]
public float shiftOff;
//目标视野 (让其显示可见)
[SerializeField ]
private float addFov;
//当前视野
private float startView;
public float off = 20;
//为一些属性初始化
private void Start()
{
startView = Camera.main.fieldOfView; //将相机的开始属性赋入
addFov = 30;
}
void LateUpdate()
{
FllowEffect(); //相机属性显示
CameraAtrribute(); //相机跟随功能
FOXChange(); //加速时相机视野的变化
}
//相机属性显示
public void CameraAtrribute()
{
//实时速度
Control = target.GetComponent<CarMoveControl>();
speed = Mathf .Lerp (speed , Control.Km_H / 4 ,Time.deltaTime ) ;
speed = Mathf.Clamp(speed, 0, 55); //对应最大200公里每小时
}
//相机跟随功能
public void FllowEffect()
{
//Z轴和Y轴的距离和鼠标滑轮联系
Ydictance += Input.GetAxis("Mouse ScrollWheel") * ScrollSpeed * Time.deltaTime;//平滑效果
Zdictance += Input.GetAxis("Mouse ScrollWheel") * ScrollSpeed * Time.deltaTime*2;
//設置Y軸和x轴的滚轮滑动范围
Ydictance = Mathf.Clamp(Ydictance, Ymin, Ymax);
Zdictance = Mathf.Clamp(Zdictance, Zmin, Zmax);
//确定好角度,四元数 * 三维向量 = 三维向量 和最终位置
lookPosition = Quaternion.AngleAxis(angle, target.right) * -target.forward;
lastPosition = target.position + Vector3.up * Ydictance - lookPosition * Zdictance;
差值更新位置,速度越快镜头跟随越快,速度越慢镜头跟随越慢
transform.position = lastPosition;
//更新角度
transform.rotation = Quaternion.LookRotation(lookPosition);
}
//加速时相机视野的变化
public void FOXChange()
{
if(Input.GetKey(KeyCode.LeftShift) ) //按下坐标shift键生效
{
Camera.main.fieldOfView = Mathf.Lerp(Camera.main.fieldOfView , startView + addFov ,Time .deltaTime * shiftOff );
}
else
{
Camera.main.fieldOfView = Mathf.Lerp(Camera.main.fieldOfView, startView, Time.deltaTime * shiftOff);
}
}
}
😶🌫️UIContorl
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
//-------------------------------------
//—————————————————————————————————————
//___________项目: ______________
//___________功能: UI相关的脚本管理
//___________创建者:_______秩沅________
//_____________________________________
//-------------------------------------
public class UIContorl : MonoBehaviour
{
//------------------仪表盘----------------
//速度指针开始角度和最终角度
private float startAngel = 215, ednAngel = -35;
//速度指针偏差角度
private float offAngel;
//获取速度的对象
public CarMoveControl control;
//速度指针组件
public Transform node;
//KM/H显示
public Text Km_H;
//挡位显示
public Text gearsNum;
//----------------------------------------
void Update()
{
//偏差角度 = 每度(速度)旋转的角度 * 速度
offAngel = (startAngel - ednAngel) / 180 * control.Km_H;
//offAngel = (startAngel - ednAngel) * control.engineRPM /10000;
//仪表盘的管理,与速度同步
node.eulerAngles = new Vector3 (0, 0, startAngel -offAngel);
//速度转文本字符
Km_H.text = control.Km_H.ToString();
//如果是倒车的情况 ,变成 红色的 R
if(control.BackCar())
{
gearsNum.text = "R";
gearsNum.color = Color.red;
}
else
{
//挡位转文本字符 ,绿色
gearsNum.text = (control.gerrsNurrentNum + 1).ToString();
gearsNum.color = Color.green;
}
}
}
⭐【Unityc#专题篇】之c#进阶篇】
⭐【Unityc#专题篇】之c#核心篇】
⭐【Unityc#专题篇】之c#基础篇】
⭐【Unity-c#专题篇】之c#入门篇】
⭐【Unityc#专题篇】—进阶章题单实践练习
⭐【Unityc#专题篇】—基础章题单实践练习
⭐【Unityc#专题篇】—核心章题单实践练习
你们的点赞👍 收藏⭐ 留言📝 关注✅是我持续创作,输出优质内容的最大动力!、文章来源:https://www.toymoban.com/news/detail-685427.html
文章来源地址https://www.toymoban.com/news/detail-685427.html
到了这里,关于【Unity3D赛车游戏】【七】如何在Unity中为汽车添加自动变速箱自动换挡?的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!