【Unity3D赛车游戏】【六】如何在Unity中为汽车添加发动机和手动挡变速?插图


👨‍💻个人主页:@元宇宙-秩沅

👨‍💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅!

👨‍💻 本文由 秩沅 原创

👨‍💻 收录于专栏:Unity游戏demo

🅰️Unity3D赛车游戏



文章目录

    • 🅰️Unity3D赛车游戏
    • 前言
      • 常见问题
    • 🎶(==A==)车辆模型——绘制发动机马力与转速曲线
        • 😶‍🌫️添加并绘制AnimationCurve 动画曲线
        • 😶‍🌫️AnimationCurve .EvaluateAPI
    • 🎶(==B==)车辆模型——发动机和手动挡位的初步实现
        • 😶‍🌫️添加发动机相关的属性
        • 😶‍🌫️更新输入控制脚本增添换挡输入
        • 😶‍🌫️换挡管理,挡位比率
    • 🎶(==C==)车辆模型——脚本记录
        • 😶‍🌫️CarMoveControl
        • 😶‍🌫️CameraContorl
        • 😶‍🌫️UIContorl
        • 😶‍🌫️ InputManager

前言


😶‍🌫️版本: Unity2021
😶‍🌫️适合人群:Unity初学者
😶‍🌫️学习目标:3D赛车游戏的基础制作
😶‍🌫️技能掌握:


常见问题


🎶(A车辆模型——绘制发动机马力与转速曲线


😶‍🌫️添加并绘制AnimationCurve 动画曲线

shift控制Y轴伸缩,ctrl控制x轴伸缩

【Unity3D赛车游戏】【六】如何在Unity中为汽车添加发动机和手动挡变速?插图(1)

  • 跑车发动机一般是7百左右,我们就按照跑车的最大功率来做
    【Unity3D赛车游戏】【六】如何在Unity中为汽车添加发动机和手动挡变速?插图(2)

😶‍🌫️AnimationCurve .EvaluateAPI

通过X轴获取Y轴值

【Unity3D赛车游戏】【六】如何在Unity中为汽车添加发动机和手动挡变速?插图(3)


🎶(B车辆模型——发动机和手动挡位的初步实现


😶‍🌫️添加发动机相关的属性

【Unity3D赛车游戏】【六】如何在Unity中为汽车添加发动机和手动挡变速?插图(4)
【Unity3D赛车游戏】【六】如何在Unity中为汽车添加发动机和手动挡变速?插图(5)

发动机功率=扭矩转速n

知识百科:说到汽车发动机,要了解几个参数。排量,功率,扭矩,转速。那么这里和参数之间的关系如何,
排量,就是发动机气缸排出气体的多少。因此说到排量,不管四缸,三缸,二缸,一缸,只要大小一样,排量就相同。
功率,单位时间内做功的多少。那么排量越大,单位时间做功就会越多,因此,排量越大,功率也会越大。
扭矩,它的单位是N·M,所以它是力运动单位距离的结果。它反应的是加速度。扭矩越大,加速能力就越强。
转速,它是单位时间内齿轮转动的圈数。齿轮转的越快,传输给轮胎的转速就越高,车子就跑的越快。

  • 关键代码
    //汽车引擎发动机相关
    public void CarEnginePower()
    {
        WheelRPM();//将轮轴的转速获取

        // 扭矩力(发动机功率) =  功率=扭矩*转速*n
        
        motorflaot = -enginePowerCurve.Evaluate(engineRPM)* gears[gerrsNurrentNum] * InputManager.InputManagerment.vertical;
        float velocity = 0.0f;

        //发动机的转速 与 车轮转速 和 挡位比率 成比例

        engineRPM = Mathf.SmoothDamp(engineRPM, 1000 + Mathf.Abs(wheelsRPM) * 3.6f * (gears[gerrsNurrentNum]), ref velocity, smoothTime);
        print(engineRPM);

        VerticalContorl(); //驱动管理
    }

【Unity3D赛车游戏】【六】如何在Unity中为汽车添加发动机和手动挡变速?插图(6)


😶‍🌫️更新输入控制脚本增添换挡输入

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;

    }
}


😶‍🌫️换挡管理,挡位比率

【Unity3D赛车游戏】【六】如何在Unity中为汽车添加发动机和手动挡变速?插图(7)

    //换挡管理
    public void shifterGearsChange()
    {
        if(InputManager.InputManagerment .addGears ) //如果按下E键,加挡
        {
            if(gerrsNurrentNum < gears.Length - 1  )

            gerrsNurrentNum++;
        }
        if(InputManager.InputManagerment.lowGears ) //如果按下Q键,减档
        {
            if (gerrsNurrentNum > 0)

                gerrsNurrentNum--;
        }

    }

🎶(C车辆模型——脚本记录


【Unity3D赛车游戏】【六】如何在Unity中为汽车添加发动机和手动挡变速?插图(8)
【Unity3D赛车游戏】【六】如何在Unity中为汽车添加发动机和手动挡变速?插图(9)

😶‍🌫️CarMoveControl
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//-------------------------------------
//—————————————————————————————————————
//___________项目:       ______________
//___________功能:  车轮的运动
//___________创建者:_______秩沅________
//_____________________________________
//-------------------------------------
//驱动模式的选择
public enum EDriveType
{
frontDrive,   //前轮驱动
backDrive,    //后轮驱动
allDrive      //四驱
}
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;
//-------------------------------------------
//驱动模式选择 _默认前驱
public 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;
//当前的挡位
public int gerrsNurrentNum = 0;
//差速比
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()
{
if(InputManager.InputManagerment .addGears ) //如果按下E键,加挡
{
if(gerrsNurrentNum < gears.Length - 1  )
gerrsNurrentNum++;
}
if(InputManager.InputManagerment.lowGears ) //如果按下Q键,减档
{
if (gerrsNurrentNum > 0)
gerrsNurrentNum--;
}
}
}
😶‍🌫️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;
//-------------------------------------
//—————————————————————————————————————
//___________项目:       ______________
//___________功能:  UI相关的脚本管理
//___________创建者:_______秩沅________
//_____________________________________
//-------------------------------------
public class UIContorl : MonoBehaviour
{
//------------------仪表盘----------------
//速度指针开始角度和最终角度
private float startAngel = 215, ednAngel = -35;
//速度指针偏差角度
private float offAngel;
//获取速度的对象
public CarMoveControl control;
//速度指针组件
public Transform node;
//----------------------------------------
void Update()
{
//偏差角度 = 每度(速度)旋转的角度 * 速度
offAngel = (startAngel - ednAngel) / 180 * control.Km_H;
//offAngel = (startAngel - ednAngel)  * control.engineRPM /10000;
//仪表盘的管理,与速度同步
node.eulerAngles = new Vector3 (0, 0, startAngel -offAngel);
}
}
😶‍🌫️ 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;
}
}

⭐【Unityc#专题篇】之c#进阶篇】

⭐【Unityc#专题篇】之c#核心篇】

⭐【Unityc#专题篇】之c#基础篇】

⭐【Unity-c#专题篇】之c#入门篇】

【Unityc#专题篇】—进阶章题单实践练习

⭐【Unityc#专题篇】—基础章题单实践练习

【Unityc#专题篇】—核心章题单实践练习


你们的点赞👍 收藏⭐ 留言📝 关注✅是我持续创作,输出优质内容的最大动力!


【Unity3D赛车游戏】【六】如何在Unity中为汽车添加发动机和手动挡变速?插图(10)


本站无任何商业行为
个人在线分享 » 【Unity3D赛车游戏】【六】如何在Unity中为汽车添加发动机和手动挡变速?
E-->