Version: 6000.3
语言: 中文
车轮碰撞器悬架
车轮碰撞器组件参考

使用车轮碰撞器创建汽车

本教程将引导您完成使用 PhysX 创建基本功能四轮汽车的过程车轮对撞机 用于停飞车辆的专用对撞机。它具有内置的碰撞检测、车轮物理和基于打滑的轮胎摩擦模型。它可用于车轮以外的物体,但它是专门为带轮子的车辆设计的。更多信息
请参阅术语表
.

这些步骤包括:

  1. 准备项目
  2. 准备汽车模型
  3. 添加 Wheel 碰撞器,并设置它们的位置和半径
  4. 添加脚本来控制汽车行为,包括汽车运动和车轮旋转
  5. 测试汽车

准备项目

要遵循这些说明,您需要:

  • 新的空旷场景
  • 演示车模型(下载:car.fbx,导入到打开的项目中
  • 汽车行驶的地面。

要创建地面曲面:

  1. 创建平面游戏对象Unity 场景中的基本对象,可以表示角色、道具、风景、相机、航路点等。游戏对象的功能由附加到它的组件定义。更多信息
    请参阅术语表
    并重命名它Ground. 这个平面是汽车行驶的地面。
  2. 将其位置设置为 (0,0,0),将其比例设置为 (100,1,100)。

准备汽车模型

首先,将汽车模型放在场景场景包含游戏的环境和菜单。将每个唯一的场景文件视为一个独特的关卡。在每个场景中,你放置你的环境、障碍物和装饰品,基本上是将你的游戏设计和构建成碎片。更多信息
请参阅术语表
:

  1. 项目窗口一个窗口,显示您的内容Assets文件夹(项目选项卡)更多信息
    术语表中查看
    ,选择导入的Car资产。
  2. 提取汽车模型的纹理,以便 Unity 可以在场景中显示它们。为此,请导航到检查器一个Unity 窗口,显示有关当前选定游戏对象、资产或项目设置的信息,允许您检查和编辑值。更多信息
    请参阅术语表
    窗口,然后执行以下作:
    1. 选择材料
    2. 选择纹理>提取纹理。在打开的文件资源管理器中,将它们保存在Assets文件夹(默认位置)。
    3. 选择应用
  3. 将汽车资产放置在场景中,位于地平面上或正上方。

在“层次结构”窗口中查看汽车游戏对象的层次结构。有一个名为Car,以及车身模型和每个车轮模型的子游戏对象。

配置车身碰撞当物理引擎检测到两个游戏对象的碰撞器接触或重叠时,当至少一个游戏对象具有刚体组件并且处于运动状态时,就会发生碰撞。更多信息
请参阅术语表
:

  1. Carroot GameObject,添加一个刚体允许游戏对象受到模拟重力和其他力影响的组件。更多信息
    请参阅术语表
    元件。
  2. 将刚体的“质量”设置为“1500”。此值定义汽车的重量(以千克为单位)。它是车轮碰撞器默认悬架设置的合适重量。有关详细信息,请参阅车轮碰撞器悬架:质量和悬架值
  3. Car BodyGameObject,添加一个网格碰撞体自由形式的碰撞器组件,它接受网格参考来定义其碰撞表面形状。更多信息
    请参阅术语表
    元件。
  4. 在新的网格Unity 的主要图形基元。网格构成了 3D 世界的很大一部分。Unity 支持三角或四边形多边形网格。Nurbs、Nurms、Subdiv 表面必须转换为多边形。更多信息
    请参阅术语表
    碰撞体一种不可见的形状,用于处理对象的物理碰撞。碰撞体不需要与对象的网格体完全相同的形状 - 在游戏中,粗略的近似值通常更有效且难以区分。更多信息
    请参阅术语表
    组件,启用 Convex

添加 Wheel 碰撞器

若要将 Wheel 碰撞器添加到 Wheel 模型,需要在与 Wheel 模型相同的位置创建四个新的单独游戏对象(但不能作为 Wheel 的子游戏对象)。

在大致相同的位置设置此设置的一种快速方法是复制滚轮游戏对象,然后配置新的游戏对象:

  1. 选择所有四个滚轮游戏对象。
  2. 复制游戏对象 (Ctrl/Cmd+D)。
  3. 选择所有四个重复项并执行以下作:
    1. 删除网格渲染器一种网格组件,它从 网格过滤器中获取几何体,并将其渲染到对象的变换组件定义的位置。更多信息
      请参阅术语表
      网格体过滤器(Mesh Filter一种网格体组件,用于从资产中获取网格体并将其传递给网格体渲染器(Mesh Renderer) 以在屏幕上渲染。更多信息
      请参阅术语表
      组件
    2. 添加 Wheel 碰撞器组件
  4. 将新的 Wheel 碰撞器重命名为 GameObjects。默认情况下,Unity 会为重复的游戏对象提供相同的名称,并在括号中添加一个数字;例如Wheel Back Left (1).为清楚起见,请改为将单词“Collider”添加到游戏对象名称中;例如Wheel Back Left collider.

汽车游戏对象层次结构现在应如下所示:

根汽车游戏对象和所有子游戏对象,包括车身、四个车轮模型游戏对象和四个车轮碰撞器游戏对象。
根汽车游戏对象和所有子游戏对象,包括车身、四个车轮模型游戏对象和四个车轮碰撞器游戏对象。

接下来,您需要调整车轮碰撞器的位置和大小以匹配车轮模型。

选择 Wheel 碰撞器时,将场景视图:您正在创建的世界的交互式视图。您可以使用场景视图来选择和定位场景、角色、摄像机、灯光和所有其他类型的游戏对象。更多信息
请参阅术语表
显示一个小工具与场景中的游戏对象关联的图形叠加层,并显示在场景视图中。移动工具等内置场景工具是 Gizmo,您可以使用纹理或脚本创建自定义 Gizmo。某些 Gizmo 仅在选择游戏对象时绘制,而其他 Gizmo 则由编辑器绘制,而不管选择了哪个游戏对象。更多信息
请参阅术语表
它提供了 Wheel 碰撞器设置的可视化效果(请参阅 Wheel 碰撞体可视化)。你可以使用小工具根据车轮模型的位置和大小检查车轮碰撞体的位置和大小。

要更清楚地看到滚轮方向和小工具,请将场景的 绘制(Draw) 模式设置为 线框(Wireframe) ,并将 场景方向(Scene orientation) 设置为 等距(Isometric)。

设置 Wheel 碰撞器位置

首次使用添加车轮碰撞器中所述的工作流程添加车轮碰撞器时,它们太低(在场景视图中,车轮碰撞体圆圈显示在车轮模型网格下方)。这是因为“挂起距离”从这些游戏对象的位置开始,向下延伸“挂起距离”设置中指定的距离。场景视图可视化将 悬挂距离(Suspension Distance) 显示为沿车轮碰撞器小工具的 Y 轴向下的橙色线。

绿色圆圈轮廓显示车轮位于悬架距离范围的中间点,当汽车在其悬架上没有被压扁或抬起时,应将其视为车轮的正常位置。因此,每个车轮碰撞器的绿色轮廓需要在其相应的车轮网格体上居中。

车轮碰撞器小工具指示车轮碰撞器相对于车轮模型的位置。在此图像中,车轮碰撞器太大且太低。
车轮碰撞器小工具指示车轮碰撞器相对于车轮模型的位置。在此图像中,车轮碰撞器太大且太低。

若要更正此问题,需要将 WheelCollider 游戏对象向上移动(在 Y 轴上)Wheel 碰撞器的“悬挂距离”值的一半。在此示例项目中,“悬挂距离”为 0.3(默认值),因此需要将 Wheel 碰撞器游戏对象向上移动 0.15 个单位。

Unity 允许您在数字字段中输入简单的数学计算。您可以使用它添加到 Y 轴值。

  1. 选择所有四个 Wheel 碰撞器游戏对象。
  2. 在检查器中,导航到变换的 Position 属性。
  3. Y 轴值中,将光标放在值的末尾。 加+0.15到值的末尾(例如,如果值为 0.5,则该值现在应为0.5+0.15).
  4. 按下 Return 键。

Unity 将 +0.15 应用于上一个值,这将 Wheel 碰撞器游戏对象沿 Y 轴向上移动 0.15 个单位。

车轮碰撞器小工具现在应该完全位于车轮网格体的中心:

车轮碰撞器小工具指示车轮碰撞器相对于车轮模型的位置。在此图像中,车轮碰撞器在车轮模型中正确居中。
车轮碰撞器小工具指示车轮碰撞器相对于车轮模型的位置。在此图像中,车轮碰撞器在车轮模型中正确居中。

设置 Wheel 碰撞体半径

首次使用添加车轮碰撞器中描述的工作流程添加车轮碰撞器时,它们太大(在“场景”视图中,车轮碰撞器小工具大于车轮模型网格体)。

要准确纠正此问题,您需要知道车轮模型的确切半径。此信息应可从您的 3D 建模软件或创作模型的技术美术师处获得。

在此示例项目中,车轮模型的半径为 0.44。

  1. 选择所有四个 Wheel 碰撞器游戏对象
  2. 在 Inspector 中,导航到 Wheel 碰撞器组件的 Radius 属性
  3. 半径(Radius) 设置为0.44.

如果车轮模型的确切半径未知或不可用,你可以使用 车轮碰撞器小工具将其半径与模型近似匹配。或者,您可以使用球体碰撞器球体形状的碰撞器组件,用于处理游戏对象(如球或其他出于物理目的可以粗略近似为球体)的碰撞。更多信息
请参阅术语表
以获取半径,因为球体碰撞器会自动调整大小以包含其关联模型的网格。

要使用球体碰撞器获取半径:

  1. 选择任何轮子模型游戏对象。
  2. 添加球体碰撞器。
  3. 记下球体碰撞器的 半径(Radius) 属性值。
  4. 删除 球体(Sphere) 碰撞器。
  5. 选择所有四个 Wheel 碰撞器游戏对象。
  6. 在 Inspector 中,导航到 Wheel 碰撞器组件的 Radius 属性。
  7. 将 车轮碰撞体半径(Wheel collider Radius) 设置为你记下的球体碰撞体半径(Sphere collider Radius) 值。

车轮碰撞器现在应该与车轮模型的位置和大小完全匹配。

两个车轮碰撞器小工具指示车轮碰撞器相对于车轮模型的位置。在此图像中,车轮碰撞器在车轮模型中正确居中,并且其半径与车轮模型的半径正确匹配。
两个车轮碰撞器小工具指示车轮碰撞器相对于车轮模型的位置。在此图像中,车轮碰撞器在车轮模型中正确居中,并且其半径与车轮模型的半径正确匹配。

添加脚本以控制汽车行为

要控制汽车,您需要添加脚本一段代码,允许您创建自己的组件、触发游戏事件、随时间修改组件属性以及以您喜欢的任何方式响应用户输入。更多信息
请参阅术语表
到执行以下作的项目:

  • 控制汽车运动:根据用户输入将转向、扭矩和制动值发送到车轮碰撞器。
  • 控制车轮移动:根据每个车轮碰撞器的状态移动和旋转车轮网格体。

在此示例中,我们使用两个脚本来执行此作:CarControl.csWheelControl.cs.

添加对汽车移动的控制

创建一个名为CarControl.cs,然后粘贴到下面的代码中:

using UnityEngine;

public class CarControl : MonoBehaviour
{
    [Header("Car Properties")]
    public float motorTorque = 2000f;
    public float brakeTorque = 2000f;
    public float maxSpeed = 20f;
    public float steeringRange = 30f;
    public float steeringRangeAtMaxSpeed = 10f;
    public float centreOfGravityOffset = -1f;

    private WheelControl[] wheels;
    private Rigidbody rigidBody;

    // Start is called before the first frame update
    void Start()
    {
        rigidBody = GetComponent<Rigidbody>();

        // Adjust center of mass to improve stability and prevent rolling
        Vector3 centerOfMass = rigidBody.centerOfMass;
        centerOfMass.y += centreOfGravityOffset;
        rigidBody.centerOfMass = centerOfMass;

        // Get all wheel components attached to the car
        wheels = GetComponentsInChildren<WheelControl>();
    }

    // FixedUpdate is called at a fixed time interval 
    void FixedUpdate()
    {
        // Get player input for acceleration and steering
        float vInput = Input.GetAxis("Vertical"); // Forward/backward input
        float hInput = Input.GetAxis("Horizontal"); // Steering input

        // Calculate current speed along the car's forward axis
        float forwardSpeed = Vector3.Dot(transform.forward, rigidBody.linearVelocity);
        float speedFactor = Mathf.InverseLerp(0, maxSpeed, Mathf.Abs(forwardSpeed)); // Normalized speed factor

        // Reduce motor torque and steering at high speeds for better handling
        float currentMotorTorque = Mathf.Lerp(motorTorque, 0, speedFactor);
        float currentSteerRange = Mathf.Lerp(steeringRange, steeringRangeAtMaxSpeed, speedFactor);

        // Determine if the player is accelerating or trying to reverse
        bool isAccelerating = Mathf.Sign(vInput) == Mathf.Sign(forwardSpeed);

        foreach (var wheel in wheels)
        {
            // Apply steering to wheels that support steering
            if (wheel.steerable)
            {
                wheel.WheelCollider.steerAngle = hInput * currentSteerRange;
            }

            if (isAccelerating)
            {
                // Apply torque to motorized wheels
                if (wheel.motorized)
                {
                    wheel.WheelCollider.motorTorque = vInput * currentMotorTorque;
                }
                // Release brakes when accelerating
                wheel.WheelCollider.brakeTorque = 0f;
            }
            else
            {
                // Apply brakes when reversing direction
                wheel.WheelCollider.motorTorque = 0f;
                wheel.WheelCollider.brakeTorque = Mathf.Abs(vInput) * brakeTorque;
            }
        }
    }
}

使用输入系统包添加对汽车移动的控制

如果使用的是输入系统包,请改用以下指南。首先,您需要在 Unity 的输入系统包中创建和配置输入作:

  1. 在 Unity 中,转到“资产”>“创建>输入作”并将其命名为CarInputActions.
  2. 双击以在输入作编辑器中将其打开。
  3. 创建一个名为Car(或您喜欢的任何名称)。

Car作映射,添加以下作:

  1. 添加一个名为“Movement”的新作。将 作类型(Action Type) 设置为 值(Value),将 控制类型(Control Type) 设置为 向量2(Vector 2)。
  2. 右键单击 移动(Movement) 并选择 添加上/下/左/右复合(Add Up/Down/Left/Right Composite)。
  3. 为每个绑定分配一个键盘输入。对于 WASD 配置,请将 Up 设置为 W,Down 设置为 S,Left 设置为 A,Right 设置为 D

最后,保存配置并从 actions 资产生成 C# 类:

  1. 在 输入作编辑器(Input Actions Editor) 中,选择 保存资产(Save Asset)
  2. 选择CarInputActions资产。
  3. 在“检查器”窗口中,选择“创建 C# 类”

创建一个名为CarControl.cs,然后粘贴到下面的代码中:

using UnityEngine;

public class CarControl : MonoBehaviour
{
    [Header("Car Properties")]
    public float motorTorque = 2000f;
    public float brakeTorque = 2000f;
    public float maxSpeed = 20f;
    public float steeringRange = 30f;
    public float steeringRangeAtMaxSpeed = 10f;
    public float centreOfGravityOffset = -1f;

    private WheelControl[] wheels;
    private Rigidbody rigidBody;

    private CarInputActions carControls; // Reference to the new input system

    void Awake()
    {
        carControls = new CarInputActions(); // Initialize Input Actions
    }
    void OnEnable()
    {
        carControls.Enable();
    }

    void OnDisable()
    {
        carControls.Disable();
    }
    
    // Start is called before the first frame update
    void Start()
    {
        rigidBody = GetComponent<Rigidbody>();

        // Adjust center of mass to improve stability and prevent rolling
        Vector3 centerOfMass = rigidBody.centerOfMass;
        centerOfMass.y += centreOfGravityOffset;
        rigidBody.centerOfMass = centerOfMass;

        // Get all wheel components attached to the car
        wheels = GetComponentsInChildren<WheelControl>();
    }
            
    // FixedUpdate is called at a fixed time interval
    void FixedUpdate()
    {
        // Read the Vector2 input from the new Input System
        Vector2 inputVector = carControls.Car.Movement.ReadValue<Vector2>();

        // Get player input for acceleration and steering
        float vInput = inputVector.y; // Forward/backward input
        float hInput = inputVector.x; // Steering input
        
        // Calculate current speed along the car's forward axis
        float forwardSpeed = Vector3.Dot(transform.forward, rigidBody.linearVelocity);
        float speedFactor = Mathf.InverseLerp(0, maxSpeed, Mathf.Abs(forwardSpeed)); // Normalized speed factor

        // Reduce motor torque and steering at high speeds for better handling
        float currentMotorTorque = Mathf.Lerp(motorTorque, 0, speedFactor);
        float currentSteerRange = Mathf.Lerp(steeringRange, steeringRangeAtMaxSpeed, speedFactor);

        // Determine if the player is accelerating or trying to reverse
        bool isAccelerating = Mathf.Sign(vInput) == Mathf.Sign(forwardSpeed);

        foreach (var wheel in wheels)
        {
            // Apply steering to wheels that support steering
            if (wheel.steerable)
            {
                wheel.WheelCollider.steerAngle = hInput * currentSteerRange;
            }

            if (isAccelerating)
            {
                // Apply torque to motorized wheels
                if (wheel.motorized)
                {
                    wheel.WheelCollider.motorTorque = vInput * currentMotorTorque;
                }
                // Release brakes when accelerating
                wheel.WheelCollider.brakeTorque = 0f;
            }
            else
            {
                // Apply brakes when reversing direction
                wheel.WheelCollider.motorTorque = 0f;
                wheel.WheelCollider.brakeTorque = Mathf.Abs(vInput) * brakeTorque;
            }
        }
    }
}

添加此CarControl.cs脚本添加到Carroot GameObject。

CarControl.cs脚本根据用户输入处理汽车行为,例如加速、扭矩和制动。有关详细信息,请参阅代码注释。

的一些元素CarControl.cs脚本引用WheelControl.cs下一节中创建的脚本。

添加对车轮移动的控制

创建一个名为WheelControl.cs,然后粘贴到下面的代码中:

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

将此脚本添加到每个 Wheel 碰撞器游戏对象。

WheelControl.cs脚本使用WheelCollider.GetWorldPose以获取 Wheel 碰撞体在场景中的位置。然后,该脚本将该位置信息分配给指定的车轮模型 GameObject。有关详细信息,请参阅代码注释。

每个实例WheelControl.cs脚本必须具有对其相应的车轮模型 GameObject 的引用。

若要将正确的车轮模型游戏对象分配给每个车轮碰撞器,请执行以下作:

  1. 选择 Wheel 碰撞器游戏对象
  2. 在“检查器”窗口中,导航到脚本创建的“滚轮控制”组件
  3. Wheel Model 设置为相应的车轮模型 GameObject(例如,在“Wheel Rear Left collider”游戏对象上,分配“Wheel Rear Left”车轮模型 GameObject):
  4. 对每个 Wheel 碰撞器重复此作。

您还需要选择哪些车轮从 CarControl 脚本接收电机输入和转向输入。要通过车轮控制属性模拟四轮驱动汽车:

  1. 在所有四个 Wheel 碰撞器游戏对象上,启用 Motorized
  2. 在两个前轮碰撞器游戏对象上,启用可纵。

测试汽车

要测试汽车,请进入播放模式并使用箭头或 WASD 键移动和转向。请注意,输入控件仅在游戏视图具有焦点时才有效。

要更好地查看在场景中移动的汽车:

  1. 排列编辑器窗口,以便场景视图和游戏视图同时可见。
  2. 将场景视图的焦点锁定到汽车上。为此,请选择Carroot GameObject,然后按 Shift + F。

现在您已经有了基本设置,您可以尝试更改不同的设置以观察它们如何影响汽车的运动。您还可以按照这些说明对不同的车型进行作,并观察其设置的异同。

车轮碰撞器悬架
车轮碰撞器组件参考