本教程将引导您完成使用 PhysX 轮碰撞器一种用于地面车辆的特殊碰撞器。它具有内置的碰撞检测、车轮物理和基于滑移的轮胎摩擦模型。它可以用于轮子以外的物体,但它是专门为带轮子的车辆设计的。 更多信息
参见 词汇表 创建一个基本的功能齐全的四轮汽车的过程。
步骤包括
要遵循这些说明,您需要
要创建地面
Ground
。此平面是汽车行驶的地面。首先,将汽车模型放置在场景场景包含游戏环境和菜单。可以将每个唯一的场景文件视为一个唯一的关卡。在每个场景中,放置环境、障碍物和装饰物,从本质上讲,将游戏分段设计和构建。 更多信息
参见 词汇表
Assets
文件夹(项目选项卡)的内容 更多信息Car
资源。Assets
文件夹(默认位置)中。查看层次结构窗口中汽车游戏对象的层次结构。有一个名为 Car
的根游戏对象,以及汽车车身模型和每个车轮模型的子游戏对象。
配置汽车车身以进行碰撞当物理引擎检测到两个游戏对象的碰撞器发生接触或重叠时,就会发生碰撞,前提是至少有一个具有刚体组件并且处于运动状态。 更多信息
参见 词汇表
Car
根游戏对象上,添加一个刚体一个组件,允许游戏对象受到模拟重力和其它力的影响。 更多信息1500
。此值定义汽车的重量(以千克为单位)。对于轮碰撞器的默认悬架设置,这是一个合适的重量。有关更多信息,请参见轮碰撞器悬架:质量和悬架值。Car Body
游戏对象上,添加一个网格碰撞器一个自由形式的碰撞器组件,它接受网格引用来定义其碰撞表面形状。 更多信息要向车轮模型添加轮碰撞器,需要在与车轮模型相同的位置创建四个新的独立游戏对象(但不是作为车轮的子游戏对象)。
一种快速设置此操作以使其大致位于相同位置的方法是复制车轮游戏对象,然后配置新游戏对象
Wheel Back Left (1)
。为清楚起见,改为在游戏对象名称中添加“Collider”一词;例如,Wheel Back Left collider
。汽车游戏对象的层次结构现在应如下所示
接下来,需要调整轮碰撞器的位置和大小以匹配车轮模型。
选择轮碰撞器时,场景视图对正在创建的世界进行交互式查看。使用场景视图选择和放置场景、角色、摄像机、灯光和所有其他类型的游戏对象。 更多信息
参见 词汇表将显示一个Gizmo与场景中游戏对象关联的图形叠加层,并在场景视图中显示。内置场景工具(如移动工具)是 Gizmo,并且可以使用纹理或脚本创建自定义 Gizmo。某些 Gizmo 仅在选择游戏对象时绘制,而其他 Gizmo 无论选择哪些游戏对象,都会由编辑器绘制。 更多信息
参见 词汇表,它提供了轮碰撞器设置的可视化效果(请参阅轮碰撞器可视化)。可以使用 Gizmo 检查轮碰撞器的位置和大小与车轮模型的位置和大小是否匹配。
要更清楚地查看车轮方向和 Gizmo,请将场景的绘制模式设置为线框,并将场景方向设置为等轴测。
当使用添加轮碰撞器中描述的工作流首次添加轮碰撞器时,它们太低了(在场景视图中,轮碰撞器圆圈出现在车轮模型网格下方)。这是因为悬架距离从这些游戏对象的位置开始,并向下延伸由悬架距离设置中指定的值指定的距离。场景视图可视化效果将悬架距离显示为沿轮碰撞器 Gizmo 的 Y 轴向下延伸的橙色线条。
绿色圆圈轮廓显示车轮位于悬架距离范围的中点,应将其视为车轮的正常位置,此时汽车没有被压低或抬起。因此,每个轮碰撞器的绿色轮廓需要以其对应的车轮网格为中心。
要更正此问题,需要将 WheelCollider 游戏对象向上(在 Y 轴上)移动轮碰撞器悬架距离值的一半。在此示例项目中,悬架距离为 0.3(默认值),因此需要将 WheelCollider 游戏对象向上移动 0.15 个单位。
Unity 允许您在数字字段中输入简单的数学计算。您可以使用它来添加到 Y 轴值。
+0.15
(例如,如果值为 0.5,则该值现在应显示为 0.5+0.15
)。Unity 将 +0.15 应用于先前的值,这会将 WheelCollider 游戏对象在 Y 轴上向上移动 0.15 个单位。
轮碰撞器 Gizmo 现在应完美地以车轮网格为中心
当使用添加轮碰撞器中描述的工作流首次添加轮碰撞器时,它们太大(在场景视图中,轮碰撞器 Gizmo 大于车轮模型网格)。
要准确更正此问题,需要知道车轮模型的确切半径。此信息应可从您的 3D 建模软件或创建模型的技术美术师那里获得。
在此示例项目中,车轮模型的半径为 0.44。
0.44
。如果车轮模型的精确半径未知或不可用,您可以使用轮碰撞体 Gizmo 将其半径近似匹配到模型。或者,您可以使用一个球形碰撞体一种球形碰撞体组件,用于处理游戏对象的碰撞,例如球体或其他可以粗略地近似为球体以用于物理目的的事物。 更多信息
参见 术语表来获取半径,因为球形碰撞体自动调整大小以包含其关联模型的网格。
如何使用球形碰撞体获取半径
轮碰撞体现在应该与车轮模型的位置和大小完全匹配。
要控制汽车,您需要向项目中添加脚本一段代码,允许您创建自己的组件、触发游戏事件、随时间修改组件属性并以任何您喜欢的方式响应用户输入。 更多信息
参见 术语表来执行以下操作
在此示例中,我们使用两个脚本执行此操作:CarControl.cs
和 WheelControl.cs
。
创建一个名为 CarControl.cs
的 C# 文件,并将下面的代码粘贴到其中
using UnityEngine;
public class CarControl : MonoBehaviour
{
public float motorTorque = 2000;
public float brakeTorque = 2000;
public float maxSpeed = 20;
public float steeringRange = 30;
public float steeringRangeAtMaxSpeed = 10;
public float centreOfGravityOffset = -1f;
WheelControl[] wheels;
Rigidbody rigidBody;
// Start is called before the first frame update
void Start()
{
rigidBody = GetComponent<Rigidbody>();
// Adjust center of mass vertically, to help prevent the car from rolling
rigidBody.centerOfMass += Vector3.up * centreOfGravityOffset;
// Find all child GameObjects that have the WheelControl script attached
wheels = GetComponentsInChildren<WheelControl>();
}
// Update is called once per frame
void Update()
{
float vInput = Input.GetAxis("Vertical");
float hInput = Input.GetAxis("Horizontal");
// Calculate current speed in relation to the forward direction of the car
// (this returns a negative number when traveling backwards)
float forwardSpeed = Vector3.Dot(transform.forward, rigidBody.velocity);
// Calculate how close the car is to top speed
// as a number from zero to one
float speedFactor = Mathf.InverseLerp(0, maxSpeed, forwardSpeed);
// Use that to calculate how much torque is available
// (zero torque at top speed)
float currentMotorTorque = Mathf.Lerp(motorTorque, 0, speedFactor);
// …and to calculate how much to steer
// (the car steers more gently at top speed)
float currentSteerRange = Mathf.Lerp(steeringRange, steeringRangeAtMaxSpeed, speedFactor);
// Check whether the user input is in the same direction
// as the car's velocity
bool isAccelerating = Mathf.Sign(vInput) == Mathf.Sign(forwardSpeed);
foreach (var wheel in wheels)
{
// Apply steering to Wheel colliders that have "Steerable" enabled
if (wheel.steerable)
{
wheel.WheelCollider.steerAngle = hInput * currentSteerRange;
}
if (isAccelerating)
{
// Apply torque to Wheel colliders that have "Motorized" enabled
if (wheel.motorized)
{
wheel.WheelCollider.motorTorque = vInput * currentMotorTorque;
}
wheel.WheelCollider.brakeTorque = 0;
}
else
{
// If the user is trying to go in the opposite direction
// apply brakes to all wheels
wheel.WheelCollider.brakeTorque = Mathf.Abs(vInput) * brakeTorque;
wheel.WheelCollider.motorTorque = 0;
}
}
}
}
将此 CarControl.cs
脚本添加到 Car
根游戏对象。
CarControl.cs
脚本根据用户输入处理汽车行为,例如加速、扭矩和制动。有关详细信息,请参阅代码注释。
CarControl.cs
脚本的某些元素引用了下一节中创建的 WheelControl.cs
脚本。
创建一个名为 WheelControl.cs
的 C# 文件,并将下面的代码粘贴到其中
using UnityEngine;
public class WheelControl : MonoBehaviour
{
public Transform wheelModel;
[HideInInspector] public WheelCollider WheelCollider;
// Create properties for the CarControl script
// (You should enable/disable these via the
// Editor Inspector window)
public bool steerable;
public bool motorized;
Vector3 position;
Quaternion rotation;
// Start is called before the first frame update
private void Start()
{
WheelCollider = GetComponent<WheelCollider>();
}
// Update is called once per frame
void Update()
{
// Get the Wheel collider's world pose values and
// use them to set the wheel model's position and rotation
WheelCollider.GetWorldPose(out position, out rotation);
wheelModel.transform.position = position;
wheelModel.transform.rotation = rotation;
}
}
将此脚本添加到每个轮碰撞体游戏对象。
WheelControl.cs
脚本使用 WheelCollider.GetWorldPose
获取轮碰撞体在场景中的位置。然后,脚本将该位置信息分配给指定的轮模型游戏对象。有关详细信息,请参阅代码注释。
WheelControl.cs
脚本的每个实例都必须引用其对应的轮模型游戏对象。
为每个轮碰撞体分配正确的轮模型游戏对象
您还需要选择哪些车轮接收来自 CarControl 脚本的电机输入和转向输入。要通过轮控制属性模拟四轮驱动汽车
要测试汽车,请进入播放模式并使用箭头键或 WASD 键移动和转向。请注意,输入控件仅在游戏视图具有焦点时有效。
要更好地查看汽车在场景中移动
Car
根游戏对象,然后按 Shift + F。现在您已经有了基本的设置,您可以尝试更改不同的设置以观察它们如何影响汽车的移动。您也可以使用不同的汽车模型遵循这些说明,并观察其设置的异同。