Unityでリアルな車の挙動を簡単に作ろう！

# はじめに
こんにちは！
Life is Tech ! Advent Calendarの9日目を担当するGeekです！
私がF1をはじめとしたモータースポーツオタクなのは、みなさんご存知かと思います。
昨日、F1とSUPER GTの2024シーズンも終了してしまいました...

さて、そんな私はかれこれ5年間、Unityでレースゲームを作り続けています。
大学のAO入試でもレースゲームを提出し、卒業制作でもレースゲームを制作しています。
そこで、今回は誰でも簡単に出来るWheel Colliderを用いた車の挙動づくりをご紹介します！

# この記事の意義
「いや、僕私、レースゲーム作らないんですけど...」と思った方も多いかもしれません。
しかし、ゲームにおける車ってレースゲームにしか登場しないものでしょうか？
思い出してみると、シューティングゲーム、特にバトルロワイヤルゲームにはよく登場しませんか？
あの挙動を、Wheel Colliderを活用することで簡単に実現できます！
車が簡単に実装できれば、作れるゲームの幅の広がるかもしれませんね！

# 目指すもの
キーボード操作で運転できる車を作ろう！
![画面収録 2024-12-09 1.36.13_5.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241868/db3c26b2-a489-a894-e521-c3cd92a1e5f9.gif)


# 環境
Unity 6000.0.25f1

# Wheel Colliderとは
> Wheel Collider は、陸上車両用の特殊なコライダーです。組み込み衝突検出、ホイール物理特性、スリップベースのタイヤ摩擦モデルを含みます。ホイール以外のオブジェクトにも使用できますが、特にホイールのある車両向けに設計されています。
[Unity Documentation](https://docs.unity3d.com/ja/2018.4/Manual/class-WheelCollider.html)より

要するに、車やバイクの駆動、タイヤ、サスペンションとかをシミュレートできるコライダーだよ！ということです。

# Wheel Colliderの使い方
それでは早速実装方法をご紹介します！
このWheel Collider、他のコンポーネントにはない複雑な使い方をします。
まずはじめに、車を構成するゲームオブジェクトの親子関係を箇条書きで示します。
- Car(空でも可)
    - CenterOfMass(車の重心を決めるための空のオブジェクト)
    - Body(車のボディの見た目)(Positionはすべて0)
    - Wheels(Wheel Colliderがアタッチされているゲームオブジェクトを子に持つ親)(Positionはすべて0)
        - Front Right(右前タイヤ)(Wheel Colliderをアタッチ)
            - Wheel Object(タイヤの見た目)
        - Front Left(左前タイヤ)(Wheel Colliderをアタッチ)
            - Wheel Object(タイヤの見た目)
        - Rear Right(後ろ右タイヤ)(Wheel Colliderをアタッチ)
            - Wheel Object(タイヤの見た目)
        - Rear Left(後ろ左タイヤ)(Wheel Colliderをアタッチ)
            - Wheel Object(タイヤの見た目)

実際の画面
![スクリーンショット 2024-12-09 1.49.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241868/fd41d8f0-c68d-3f8a-7094-c4a69af5ddb3.png)
## 親オブジェクトについて
このオブジェクトにアタッチするのは、
- Rigidbody
- Box Collider
- 車を制御するためのスクリプト
の3つです。
### Rigidbody
必ず調整しなければ行けない項目はMassのみです。
実際の車は1500kgほどが一般的ですので、Massは1500くらいが無難です。
### Box Collider
CenterとSizeを調整して、車のボディが覆われるように設定してください。
この時、地面に接してしまわないように車の底部がColliderの底部になるよう調整してください。
シャコタンになってタイヤが接地しなくなります。
![スクリーンショット 2024-12-09 1.53.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241868/ec2b5df2-7935-4608-c08e-dfa83f10ec91.png)
### 車を制御するためのスクリプト
車の運転は、走る、曲がる、止まる。
もっと詳しく言うと、前進後退、右折左折、停止ができればOKです。
これを成業するためにWheel Colliderには
- motorTorque(回転の力)
- steerAngle(左右の舵角)
- brakeTorque(ブレーキの力)
という変数が用意されていて、これに値を代入すれば車が動きます。
あとはInputの内容を値に反映してあげれば良いわけです。
今回はWASDキーor矢印キーで前後左右の操作、スペースキーでブレーキという操作を前提にサンプルのスクリプトを用意しました。

<details><summary>サンプルコード</summary>

```C#:SampleCarController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;

public class SampleCarController : MonoBehaviour
{
    private Rigidbody RB;
    [SerializeField] Transform CenterOfMass;
    //Rigidbody.centerOfMassを上書きして、車の重心を決めるためのTransform
    [SerializeField] WheelCollider[] Wheels;
    //Wheel Colliderがアタッチされている各タイヤ
    [SerializeField] Transform[] Obj;
    //タイヤの見た目(AwakeでWheelsから取得するため割当不要)

    [SerializeField] string XAxisName = "Horizontal";
    [SerializeField] string YAxisName = "Vertical";
    [SerializeField] KeyCode BrakeKey = KeyCode.Space;
    //前後移動はVertical、ハンドル操作はHorizontalで行う。(InputManager参照)

    [SerializeField] Vector2 InputVector;
    //キー操作を受け取る
    [SerializeField] float BrakeInput = 0;
    //ブレーキのキー入力を受け取る

    [SerializeField] float AccelPower = 1000f;
    //車のパワー
    [SerializeField] float HandleAngle = 45f;
    //最大でハンドルが切れるタイヤの角度
    [SerializeField] float BrakePower = 1000f;
    //ブレーキの力

    [SerializeField] float[] DriveWheels = new float[] { 0f, 0f, 1.0f, 1.0f };
    //駆動させるタイヤ。0なら駆動しない、1なら駆動する。(パワーでタイヤを回すかどうか。初期値は後輪駆動)
    [SerializeField] float[] SteerWheels = new float[] { 1.0f, 1.0f, 0f, 0f };
    //ハンドル操作で曲がるタイヤ。

    // Start is called before the first frame update
    void Awake()
    {
        Wheels = GetComponentsInChildren<WheelCollider>();
        RB = GetComponent<Rigidbody>();
        RB.centerOfMass = CenterOfMass.localPosition;

        Obj = new Transform[Wheels.Length];
        for (int i = 0; i < Wheels.Length; i++)
        {
            Obj[i] = Wheels[i].transform.GetChild(0);
        }
    }

    // Update is called once per frame
    void Update()
    {
        ControllInput();

        CarControll();
    }
    private void ControllInput()
    {
        InputVector = new Vector2(Input.GetAxis(XAxisName), Input.GetAxis(YAxisName));
        BrakeInput = Input.GetKey(BrakeKey) ? BrakePower : 0f;
    }

    private void CarControll()
    {
        for (int i = 0; i < Wheels.Length; i++)
        {
            Wheels[i].motorTorque = InputVector.y * DriveWheels[i] * AccelPower;
            Wheels[i].steerAngle = InputVector.x * SteerWheels[i] * HandleAngle;
            Wheels[i].brakeTorque = BrakeInput;

            Vector3 _pos;
            Quaternion _dir;
            Wheels[i].GetWorldPose(out _pos, out _dir);
            Obj[i].position = _pos;
            Obj[i].rotation = _dir;
        }
    }
}
```

</details>

これをアタッチし、以下のように値を設定してください。
![スクリーンショット 2024-12-09 2.14.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241868/6e3d7d15-6110-5398-fe95-1d2451b06330.png)

これで親オブジェクトの設定は完了です！

## Wheel Colliderについて
まず、Front Right~Rear Leftのタイヤが置かれる位置に座標をセットしてください。

次は、四輪すべてに追加したWheel Colliderの設定項目です。
ここはサスペンションの硬さ、減衰力、タイヤの摩擦力などかなり専門的な領域です。
基本的にこの設定を守ってもらえれば、しっかりとした挙動の車になるかと思います。
4つのWheel Collider、すべて同じ値でOKです。
![スクリーンショット 2024-12-09 2.18.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241868/3078c310-476c-fbac-2bde-25166edf1d99.png)

強いて変わるとするなら、タイヤの見た目に応じてタイヤの半径が変わると思うので、Sceneビューを見ながらRadiusを調整してください。
<img src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241868/334ca882-10e9-f29e-36bf-b59bc86b0faf.png" width = 50%><img src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241868/0affe328-b7e8-1279-3355-f79536830576.png" width = 50%>

実際のサイズに合わせる。


親オブジェクトのSample Car ControllerスクリプトにあるWheelsに上から順番に割り当ててください。

## CenterOfMassについて
車の重心は中央よりちょっと上くらいがおすすめです。
親オブジェクトのSample Car Controllerスクリプトに割り当ててください。
![スクリーンショット 2024-12-09 2.19.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241868/bb51fe4a-e471-0821-4219-b8c6af513ac2.png)

# おしまい！
以上が、最もシンプルな車の挙動の実装方法です。
今回は初心者向けということで、Wheel Colliderの詳しい説明は省きましたが、気になる方は調べてみてください！
これでレースゲームを作る第一歩を踏み出せますので、まずはF1を観るところからはじめてみましょう。

今回お借りした3Dモデル
[Mazda Miata MX-5 NA - Sketchfab](https://sketchfab.com/3d-models/mazda-miata-mx-5-na-d51fcd44b74f4daf8012c41e0400c041)