Unity中的车辆控制

WheelCollider(车轮碰撞器)是一种特殊的地面车辆碰撞器,它具有内置的碰撞检测、车轮物理引擎和一个基于滑移的轮胎摩擦模型。WheelCollider是专门为有轮子的车辆所做的设计。此处把坦克作为车辆来实现坦克的车辆碰撞和车辆运动。

车轮碰撞器

在添加轮子时,给车辆(此处是坦克整体tank)添加碰撞器Rigidbody,且坦克较重,需要在Rigidbody中调整坦克的质量(Mass属性,这里调整为300),如下图:

在这里插入图片描述
在坦克模型下建立名为PhysicalBody的空物体,用于存放坦克的碰撞器组件。再在PhysicalBody里添加wheelL1、wheelL2、wheelR1、wheelR2这4个空物体代表坦克的四个轮子。在PhysicalBody里添加2个名为collider的空物体,用于给坦克添加碰撞器(坦克车身有上下两部分,故添加2个collider),此时坦克层次模型如下图:
在这里插入图片描述
给2个collider添加BoxCollider组件(Component –> Physics –> Box Collider),然后点击collider的属性面板的Edit Collider调整位置和大小。再给4个轮子分别添加WheelCollider(Component –> Physics –> WheelCollider),调整位置和大小,注意轮子的位置、大小、角度的细微差别会影响物理性能,所以要根据Transform的数值进行调整。L1表示左前轮,L2表示左后轮,R1表示右前轮,R2表示右后轮。最后调整结果见下图:

在这里插入图片描述

WheelCollider的属性

WheelCollider是用Unity3D制作汽车类型游戏的关键所在,它不仅可以模拟轮子的碰撞过程,还模拟了汽车的悬挂系统、引擎系统、轮胎摩擦等汽车的关键物理特性。WheelCollider的属性及说明见下表:

属性 说明
mass 车轮的质量
radius 轮子半径
suspensionDistance 车轮悬挂的最大延长距离
center 轮子的中心位置(相对于本地坐标系)
suspensionSpring 车轮悬挂的参数,通过添加弹簧和阻尼力,悬挂试图达到的目标位置
forwardFriction 在车轮指向方向上的摩擦力的属性
sidewaysFriction 轮胎侧面方向上的摩擦力的属性

车轮是由motorTorque、brakeTorque和steerAngle属性控制的,它们的含义见下表:

属性或方法 说明
motorTorque 在轮轴上的电机力矩
brakeTorque 刹车的力矩
steerAngle 车轮转向角度

一般来说,重心、悬挂系统和轮胎(摩擦力属性)对汽车的性能有着很大的影响。

  1. 重心:由于车辆的重心通常不是车的中心位置,若要得到更真实的效果,可以通过代码设置Rigidbody.centerOfMass来调整重心位置。
  2. 悬挂系统:车的悬挂系统可以增强轮胎和路面的摩擦。下面是与悬挂系统有关的参数及说明:
属性或方法 说明
spring 悬挂弹簧。该值决定了 悬挂弹簧的刚性,把它设得很高可以使弹簧很软,所以车轮将有更大的震动范围,把它设得很小,将使悬挂很硬
damper 悬挂阻尼器,可以使弹簧震动变得平滑
targetPosition 目标位置。静止状态下悬挂的距离,0表示充分伸展弹簧,1表示充分压缩弹簧
  1. 轮胎摩擦力:Forward Friction是前后方向的摩擦力属性,影响motorTorque和brakeTorque的效果。Sideways Friction是左右方向的摩擦力属性,影响steerAngle的效果。下面是与摩擦力相关的参数及说明:
参数 说明
extremumSlip 滑动极值点(默认为1)
exyremumValue 滑动极值的力(默认为20000)
asymptoteSlip 渐近线滑动点(默认为2)
asymptoteValue 渐近线滑动上的力(默认为10000)
stiffness 用于extremumValue和asymptoteValue值的倍数(默认为1)

控制车辆

汽车的前轮和后轮分别悬挂在两条轴上,每条轴上两个轮子的步调是一致的。新建名为AxleInfo的Script脚本,添加代表车轴信息的AxleInfo类,(此处的炮管可参见前面的博客)代码如下:

using System.Collections; using System.Collections.Generic; using UnityEngine; [System.Serializable]  public class AxleInfo { public WheelCollider leftWheel; public WheelCollider rightWheel; public bool motor; public bool steering; } 

编写名为tank的Script脚本拖到坦克上,代码如下:

using System.Collections; using System.Collections.Generic; using UnityEngine; public class Tank : MonoBehaviour {  public Transform turret;  private float turretRotSpeed = 0.5f;  public Transform gun;  private float maxRoll = 10f; private float minRoll = -4f;  private float turretRotTarget = 0; private float turretRollTarget = 0;  public List<AxleInfo> axleInfos;  private float motor = 0; public float maxMotorTorque;  private float brakeTorque = 0; public float maxBrakeTorque = 100;  private float steering = 0; public float maxSteeringAngle;  void Start() {  turret = transform.Find("turret");  gun = turret.Find("gun"); }  void Update() {  PlayerCtrl();  foreach(AxleInfo axleInfo in axleInfos) {  if (axleInfo.steering) { axleInfo.leftWheel.steerAngle = steering; axleInfo.rightWheel.steerAngle = steering; }  if (axleInfo.motor) { axleInfo.leftWheel.motorTorque = motor; axleInfo.rightWheel.motorTorque = motor; }  if (true) { axleInfo.leftWheel.brakeTorque = brakeTorque; axleInfo.rightWheel.brakeTorque = brakeTorque; } }  TurretRotation(); TurretRoll(); }  public void TurretRotation() { if (Camera.main == null) return; if (turret == null) return;  float angle = turret.eulerAngles.y - turretRotTarget; if (angle < 0) angle += 360; if (angle > turretRotSpeed && angle < 180) turret.Rotate(0f, -turretRotSpeed, 0f); else if (angle > 180 && angle < 360 - turretRotSpeed) turret.Rotate(0f, turretRotSpeed, 0f); }  public void TurretRoll() { if (Camera.main == null) return; if (turret == null) return;  Vector3 worldEuler = gun.eulerAngles; Vector3 localEuler = gun.localEulerAngles;  worldEuler.x = turretRollTarget; gun.eulerAngles = worldEuler;  Vector3 euler = gun.localEulerAngles; if (euler.x > 180) euler.x -= 360; if (euler.x > maxRoll) euler.x = maxRoll; if (euler.x < minRoll) euler.x = minRoll; gun.localEulerAngles = new Vector3(euler.x, localEuler.y, localEuler.z); }  public void PlayerCtrl() {  motor = maxMotorTorque * Input.GetAxis("Vertical"); steering = maxSteeringAngle * Input.GetAxis("Horizontal");  turretRotTarget = Camera.main.transform.eulerAngles.y; turretRollTarget = Camera.main.transform.eulerAngles.x; } } 

最后设置tank模型的AxleInfos的size设置为2(前后两条车轴),并将4个WheelCollider拖入其中,设置为后驱,如下图:

在这里插入图片描述
选择坦克的4个WheelCollider,调整参数,可以得到更好的体验,见下图:

在这里插入图片描述

刹车

玩家按下后退键时,是刹车还是后退。可以使用车轮碰撞器的rpm(转速)属性判断。如果转速大于某个值(这里取5),可以视为坦克前进,小于某个值(这里取-5)为后退,转速为0则表示静止,而不单单根据后退键来看。修改PlayerCtrl,代码如下:

 public void PlayerCtrl() {  motor = maxMotorTorque * Input.GetAxis("Vertical"); steering = maxSteeringAngle * Input.GetAxis("Horizontal");  brakeTorque = 0; foreach(AxleInfo axlenInfo in axleInfos) {  if (axlenInfo.leftWheel.rpm > 5 && motor < 0) brakeTorque = maxBrakeTorque;  else if(axlenInfo.leftWheel.rpm <-5 && motor > 0) brakeTorque = maxBrakeTorque; continue; }  turretRotTarget = Camera.main.transform.eulerAngles.y; turretRollTarget = Camera.main.transform.eulerAngles.x; } 

运行游戏,可以体验到刹车效果。

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理

在线客服
在线客服
QQ客服