【unity实战】简易的车辆控制系统

最终效果

文章目录

前言

在游戏开发中,车辆控制系统是一个非常常见且重要的功能模块。无论是赛车游戏、开放世界游戏还是模拟驾驶游戏,一个稳定且真实的车辆控制系统都能大大提升玩家的游戏体验。

本教程将带领大家从零开始,在Unity中实现一个简易但功能完整的车辆控制系统。

这个系统采用了Unity内置的WheelCollider组件来处理车辆物理,相比完全自定义的物理实现更加稳定高效。我们还会学习如何调整车辆的重心、转向灵敏度等参数,使车辆操控感更加真实。

最终我们将得到一个可以自由驾驶的车辆,具备加速、刹车、转向等基本功能,并且车轮会随着运动正确旋转,相机也会智能跟随车辆移动。

让我们开始这个有趣的项目吧!在实现过程中,你可以随时调整参数来获得不同的驾驶体验,找到最适合你游戏的操控感觉。

一、实战

1、模型下载

https://assetstore.unity.com/packages/3d/vehicles/land/1950s-classic-car-6-variant-322054

2、添加刚体和碰撞体

3、提前车辆,并添加WheelCollider组件,配置参数

4、车辆移动

csharp 复制代码
// 车轴枚举
public enum Axel
{
    Front,  // 前轮
    Rear    // 后轮
}

// 车轮结构体
[Serializable]
public struct Wheel
{
    public GameObject wheelModel;        // 车轮模型
    public WheelCollider wheelCollider; // 车轮碰撞器
    public Axel axel;                    // 所属车轴
}

[SerializeField] public float maxAcceleration = 10.0f;    // 最大加速度
public List<Wheel> wheels;               // 车轮列表

float _moveInput;     // 移动输入值

private Rigidbody _carRb;     // 车辆刚体组件

void Start()
{
    // 获取刚体组件并设置重心
    _carRb = GetComponent<Rigidbody>();
}

void Update()
{
    GetInputs();        // 获取输入
}

void FixedUpdate()
{
    Move();     // 移动控制
}

// 获取输入
void GetInputs()
{
    _moveInput = Input.GetAxis("Vertical");   // 获取垂直输入
}

// 移动控制
void Move()
{
    foreach (var wheel in wheels)
    {
        // 设置车轮马达扭矩
        wheel.wheelCollider.motorTorque = _moveInput * 600 * maxAcceleration;
    }
}

配置

效果

5、刹车

csharp 复制代码
public float brakeAcceleration = 50.0f;  // 刹车加速度

void FixedUpdate()
{
    Move();     // 移动控制
    Brake();    // 刹车控制
}

// 刹车控制
void Brake()
{
    // 如果按下空格键或没有移动输入
    if (Input.GetKey(KeyCode.Space) || _moveInput == 0)
    {
        foreach (var wheel in wheels)
        {
            // 设置刹车扭矩
            wheel.wheelCollider.brakeTorque = 300 * brakeAcceleration;
        }
    }
    else
    {
        foreach (var wheel in wheels)
        {
            // 取消刹车扭矩
            wheel.wheelCollider.brakeTorque = 0;
        }
    }
}

效果

6、转向和车辆重心

csharp 复制代码
public float turnSensitivity = 1.0f;    // 转向灵敏度
public float maxSteerAngle = 30.0f;      // 最大转向角度
public Vector3 centerOfMass;            // 车辆重心
float _steerInput;    // 转向输入值

void Start()
{
    // 获取刚体组件并设置重心
    _carRb = GetComponent<Rigidbody>();
    _carRb.centerOfMass = centerOfMass;
}

void FixedUpdate()
{
    Move();     // 移动控制
    Brake();    // 刹车控制
    Steer();    // 转向控制
}

// 获取输入
void GetInputs()
{
    _moveInput = Input.GetAxis("Vertical");   // 获取垂直输入
    _steerInput = Input.GetAxis("Horizontal"); // 获取水平输入
}

// 转向控制
void Steer()
{
    foreach (var wheel in wheels)
    {
        // 只对前轮进行转向
        if (wheel.axel == Axel.Front)
        {
            var _steerAngle = _steerInput * turnSensitivity * maxSteerAngle;
            // 平滑过渡转向角度
            wheel.wheelCollider.steerAngle = Mathf.Lerp(wheel.wheelCollider.steerAngle, _steerAngle, 0.6f);
        }
    }
}

效果

7、动画化车轮

csharp 复制代码
void Update()
{
    GetInputs();        // 获取输入
    AnimateWheels();     // 动画化车轮
}

// 动画化车轮
void AnimateWheels()
{
    foreach (var wheel in wheels)
    {
        Quaternion rot;
        Vector3 pos;
        // 获取车轮碰撞器的世界位置和旋转
        wheel.wheelCollider.GetWorldPose(out pos, out rot);
        // 更新车轮模型的位置和旋转
        wheel.wheelModel.transform.position = pos;
        wheel.wheelModel.transform.rotation = rot;
    }
}

效果

8、相机跟随

参考:【unity知识】最新的Cinemachine3简单使用介绍

效果

二、最终车辆控制代码

csharp 复制代码
using UnityEngine;
using System;
using System.Collections.Generic;

public class CarController : MonoBehaviour
{
    // 车轴枚举
    public enum Axel
    {
        Front,  // 前轮
        Rear    // 后轮
    }

    // 车轮结构体
    [Serializable]
    public struct Wheel
    {
        public GameObject wheelModel;        // 车轮模型
        public WheelCollider wheelCollider; // 车轮碰撞器
        public Axel axel;                    // 所属车轴
    }

    [SerializeField] public float maxAcceleration = 10.0f;    // 最大加速度
    public float brakeAcceleration = 50.0f;  // 刹车加速度

    public float turnSensitivity = 1.0f;    // 转向灵敏度
    public float maxSteerAngle = 30.0f;      // 最大转向角度

    public Vector3 centerOfMass;            // 车辆重心

    public List<Wheel> wheels;               // 车轮列表

    float _moveInput;     // 移动输入值
    float _steerInput;    // 转向输入值

    private Rigidbody _carRb;     // 车辆刚体组件

    void Start()
    {
        // 获取刚体组件并设置重心
        _carRb = GetComponent<Rigidbody>();
        _carRb.centerOfMass = centerOfMass;
    }

    void Update()
    {
        GetInputs();        // 获取输入
        AnimateWheels();     // 动画化车轮
    }

    void FixedUpdate()
    {
        Move();     // 移动控制
        Brake();    // 刹车控制
        Steer();    // 转向控制
    }

    // 获取输入
    void GetInputs()
    {
        _moveInput = Input.GetAxis("Vertical");   // 获取垂直输入
        _steerInput = Input.GetAxis("Horizontal"); // 获取水平输入
    }

    // 移动控制
    void Move()
    {
        foreach (var wheel in wheels)
        {
            // 设置车轮马达扭矩
            wheel.wheelCollider.motorTorque = _moveInput * 600 * maxAcceleration;
        }
    }

    // 转向控制
    void Steer()
    {
        foreach (var wheel in wheels)
        {
            // 只对前轮进行转向
            if (wheel.axel == Axel.Front)
            {
                var _steerAngle = _steerInput * turnSensitivity * maxSteerAngle;
                // 平滑过渡转向角度
                wheel.wheelCollider.steerAngle = Mathf.Lerp(wheel.wheelCollider.steerAngle, _steerAngle, 0.6f);
            }
        }
    }

    // 刹车控制
    void Brake()
    {
        // 如果按下空格键或没有移动输入
        if (Input.GetKey(KeyCode.Space) || _moveInput == 0)
        {
            foreach (var wheel in wheels)
            {
                // 设置刹车扭矩
                wheel.wheelCollider.brakeTorque = 300 * brakeAcceleration;
            }
        }
        else
        {
            foreach (var wheel in wheels)
            {
                // 取消刹车扭矩
                wheel.wheelCollider.brakeTorque = 0;
            }
        }
    }

    // 动画化车轮
    void AnimateWheels()
    {
        foreach (var wheel in wheels)
        {
            Quaternion rot;
            Vector3 pos;
            // 获取车轮碰撞器的世界位置和旋转
            wheel.wheelCollider.GetWorldPose(out pos, out rot);
            // 更新车轮模型的位置和旋转
            wheel.wheelModel.transform.position = pos;
            wheel.wheelModel.transform.rotation = rot;
        }
    }
}

三、车辆引擎声音

新增脚本,根据速度计算的动态音高

csharp 复制代码
using UnityEngine;

public class CarSounds : MonoBehaviour
{
    [Header("速度参数")]
    public float maxSpeed = 40f;       // 引擎声音最大速度阈值
    private float currentSpeed;  // 当前车辆速度

    [Header("音频参数")]
    public float minPitch = 0.2f;    // 引擎最小音高 (默认值示例)
    public float maxPitch = 1f;    // 引擎最大音高 (默认值示例)
    private float pitchFromCar;      // 根据速度计算的动态音高

    private Rigidbody carRb;     // 车辆刚体组件
    private AudioSource carAudio; // 音频源组件

    void Start()
    {
        // 获取组件引用
        carAudio = GetComponent<AudioSource>();
        carRb = GetComponent<Rigidbody>();
    }

    void Update()
    {
        EngineSound(); // 每帧更新引擎声音
    }

    /// <summary>
    /// 根据车速动态调整引擎音效
    /// </summary>
    void EngineSound()
    {
        // 获取当前速度(忽略垂直方向)
        currentSpeed = carRb.linearVelocity.magnitude;

        // 计算速度比例映射到音高范围
        pitchFromCar = Mathf.Clamp(currentSpeed / maxSpeed, minPitch, maxPitch);

         carAudio.pitch =  pitchFromCar;
    }
}

专栏推荐

地址
【unity游戏开发入门到精通------C#篇】
【unity游戏开发入门到精通------unity通用篇】
【unity游戏开发入门到精通------unity3D篇】
【unity游戏开发入门到精通------unity2D篇】
【unity实战】
【制作100个Unity游戏】
【推荐100个unity插件】
【实现100个unity特效】
【unity框架/工具集开发】
【unity游戏开发------模型篇】
【unity游戏开发------InputSystem】
【unity游戏开发------Animator动画】
【unity游戏开发------UGUI】
【unity游戏开发------联网篇】
【unity游戏开发------优化篇】
【unity游戏开发------shader篇】
【unity游戏开发------编辑器扩展】
【unity游戏开发------热更新】
【unity游戏开发------网络】

完结

好了,我是向宇,博客地址:https://xiangyu.blog.csdn.net,如果学习过程中遇到任何问题,也欢迎你评论私信找我。

赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注,你的每一次支持都是我不断创作的最大动力。当然如果你发现了文章中存在错误或者有更好的解决方法,也欢迎评论私信告诉我哦!

相关推荐
EngZegNgi2 小时前
Unity —— Android 应用构建与发布
android·unity·自动化·游戏引擎·构建
R-G-B3 小时前
【01】OpenCV C#——C#开发环境OpenCvSharp 环境配置 工程搭建 及代码测试
opencv·c#·opencvsharp·opencvsharp环境搭建·opencvsharp开发环境·opencv c#·opencvsharp代码测试
三千道应用题5 小时前
WPF&C#超市管理系统(4)入库管理
c#·wpf
智者知已应修善业5 小时前
【c#窗体荔枝计算乘法,两数相乘】2022-10-6
经验分享·笔记·算法·c#·.net
时光追逐者7 小时前
C#拾遗补漏之 Dictionary 详解
开发语言·c#·.net·.net core
q__y__L14 小时前
C#线程同步(二)锁
开发语言·性能优化·c#
cheniie15 小时前
Unity相机控制
unity·相机控制
Yueeyuee_17 小时前
【C#学习Day15笔记】拆箱装箱、 Equals与== 、文件读取IO
笔记·学习·c#
R-G-B19 小时前
【33】C# WinForm入门到精通 ——表格布局器TableLayoutPanel【属性、方法、事件、实例、源码】
开发语言·c#·c# winform·表格布局器·tablelayoutpane