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;
    }

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

  • 11
    点赞
  • 93
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值