最终效果

文章目录
前言
在游戏开发中,车辆控制系统是一个非常常见且重要的功能模块。无论是赛车游戏、开放世界游戏还是模拟驾驶游戏,一个稳定且真实的车辆控制系统都能大大提升玩家的游戏体验。
本教程将带领大家从零开始,在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、相机跟随

效果
二、最终车辆控制代码
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;
}
}
专栏推荐
完结
好了,我是向宇
,博客地址:https://xiangyu.blog.csdn.net,如果学习过程中遇到任何问题,也欢迎你评论私信找我。
赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注
,你的每一次支持
都是我不断创作的最大动力。当然如果你发现了文章中存在错误
或者有更好的解决方法
,也欢迎评论私信告诉我哦!