새 WheelCollider는 PhysX2에 비해 완전히 새로운 차량 시뮬레이션 라이브러리인 PhysX3 Vehicles SDK로 구동됩니다.
Unity 5.0에서 기본 기능만 있는 차량을 만드는 프로세스를 살펴보겠습니다.
GameObject -> 3D Object -> Plane을 선택하여 시작합니다. 이 평면은 자동차가 주행할 지면입니다. 트랜스폼이 없는 간단한 지면인지 확인해야 합니다(Transform -> Reset). Transform 스케일 컴포넌트에 100 같은 숫자를 입력하여 지면을 스케일합니다.
기본 차량 스켈레톤을 만듭니다.
먼저 게임 오브젝트를 차량 루트 오브젝트로 추가합니다(GameObject -> Create Empty). 이름을 car_root
로 변경합니다.
car_root
에 Physics 3D Rigidbody 컴포넌트를 추가합니다. 기본 질량 1kg은 기본 서스펜션 설정으로 너무 가볍습니다. 1,500kg으로 변경합니다.
차량 바디 콜라이더를 만들고 car_root
아래 박스를 부모로 지정합니다(GameObject -> 3D Object -> Cube). 로컬 공간에서 완벽하게 정렬되도록 변환을 초기화합니다. 차량 방향이 Z축을 따를 것이므로 z 스케일링을 3으로 설정하여 Z축을 따라 박스를 스케일합니다.
휠 루트를 추가합니다. car_root
와 GameObject -> Create Empty Child를 선택합니다. 이름을 wheels
로 변경합니다. 변환을 초기화합니다. 이 노드는 필수는 아니지만, 나중에 편리한 미세 조정을 위해 사용합니다.
첫 번째 휠을 만듭니다. wheels
오브젝트, GameObject -> Create Empty Child를 선택하고 이름을 frontLeft
로 지정합니다. 변환을 초기화합니다. 포지션을 (–1, 0, 1)로 설정합니다. Physics Component -> Wheel Collider를 휠에 추가합니다.
frontLeft
오브젝트를 복제합니다(Cmd+D 또는 Ctrl+D). x 포지션을 1로 변경합니다. 이름을 frontRight
로 변경합니다.
frontLeft
및 frontRight
오브젝트를 모두 선택하고 복제합니다. 두 오브젝트의 z 포지션을 모두 –1로 변경합니다. 이름을 각각 rearLeft
와 rearRight
로 변경합니다.
마지막으로, car_root
오브젝트를 선택하고, 트랜스폼 조종기를 사용해 지면에서 약간 위로 올립니다.
이제 다음과 같은 그림이 보입니다.
이 차를 실제로 운전할 수 있으려면 컨트롤러를 작성해야 합니다. 다음과 같이 스크립팅합니다.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class SimpleCarController : MonoBehaviour {
public List<AxleInfo> axleInfos; // the information about each individual axle
public float maxMotorTorque; // maximum torque the motor can apply to wheel
public float maxSteeringAngle; // maximum steer angle the wheel can have
public void FixedUpdate()
{
float motor = maxMotorTorque * Input.GetAxis("Vertical");
float steering = maxSteeringAngle * Input.GetAxis("Horizontal");
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;
}
}
}
}
[System.Serializable]
public class AxleInfo {
public WheelCollider leftWheel;
public WheelCollider rightWheel;
public bool motor; // is this wheel attached to motor?
public bool steering; // does this wheel apply steer angle?
}
간단히 이 코드 조각을 `car_root` 오브젝트에 적용하고, 아래와 같이 스크립트 파라미터를 세부 조정하며, 플레이 모드를 시작합니다. 설정을 다양하게 변경해 봅니다. 아래에 나와 있는 설정을 사용하면 무난합니다.
![](../uploads/Main/WheelColliderSettings.png)
차량 인스턴스 하나에 스티어링, 모터 또는 제동 토크를 저마다 가하는 휠을 20개까지 부착할 수 있습니다.
이제 비주얼 휠로 넘어가겠습니다. 보시다시피 WheelCollider는 시뮬레이션된 휠 포지션 및 회전을 WheelCollider의 트랜스폼에 다시 적용하지 않습니다. 따라서 비주얼 휠을 추가하려면 몇 가지 비결이 필요합니다.
여기에는 휠 지오메트리가 몇 개 필요합니다. 실린더를 사용하여 간단한 휠 모양을 만들 수 있습니다.
비주얼 휠을 추가하는 두 가지 방법이 있습니다. 첫 번째는 스크립트 프로퍼티에서 비주얼 휠을 수동으로 할당하는 것이고, 두 번째는 약간의 로직을 작성하여 자동으로 해당 비주얼 휠을 찾도록 하는 것입니다. 여기서는 후자를 선택하겠습니다.
비주얼 휠을 휠 콜라이더 오브젝트에 부착합니다.
이제 컨트롤러 스크립트를 다음과 같이 변경합니다.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
[System.Serializable]
public class AxleInfo {
public WheelCollider leftWheel;
public WheelCollider rightWheel;
public bool motor;
public bool steering;
}
public class SimpleCarController : MonoBehaviour {
public List<AxleInfo> axleInfos;
public float maxMotorTorque;
public float maxSteeringAngle;
// finds the corresponding visual wheel
// correctly applies the transform
public void ApplyLocalPositionToVisuals(WheelCollider collider)
{
if (collider.transform.childCount == 0) {
return;
}
Transform visualWheel = collider.transform.GetChild(0);
Vector3 position;
Quaternion rotation;
collider.GetWorldPose(out position, out rotation);
visualWheel.transform.position = position;
visualWheel.transform.rotation = rotation;
}
public void FixedUpdate()
{
float motor = maxMotorTorque * Input.GetAxis("Vertical");
float steering = maxSteeringAngle * Input.GetAxis("Horizontal");
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;
}
ApplyLocalPositionToVisuals(axleInfo.leftWheel);
ApplyLocalPositionToVisuals(axleInfo.rightWheel);
}
}
}