はじめに
こんにちは!
Life is Tech ! Advent Calendarの9日目を担当するGeekです!
私がF1をはじめとしたモータースポーツオタクなのは、みなさんご存知かと思います。
昨日、F1とSUPER GTの2024シーズンも終了してしまいました...
さて、そんな私はかれこれ5年間、Unityでレースゲームを作り続けています。
大学のAO入試でもレースゲームを提出し、卒業制作でもレースゲームを制作しています。
そこで、今回は誰でも簡単に出来るWheel Colliderを用いた車の挙動づくりをご紹介します!
この記事の意義
「いや、僕私、レースゲーム作らないんですけど...」と思った方も多いかもしれません。
しかし、ゲームにおける車ってレースゲームにしか登場しないものでしょうか?
思い出してみると、シューティングゲーム、特にバトルロワイヤルゲームにはよく登場しませんか?
あの挙動を、Wheel Colliderを活用することで簡単に実現できます!
車が簡単に実装できれば、作れるゲームの幅の広がるかもしれませんね!
目指すもの
環境
Unity 6000.0.25f1
Wheel Colliderとは
Wheel Collider は、陸上車両用の特殊なコライダーです。組み込み衝突検出、ホイール物理特性、スリップベースのタイヤ摩擦モデルを含みます。ホイール以外のオブジェクトにも使用できますが、特にホイールのある車両向けに設計されています。
Unity Documentationより
要するに、車やバイクの駆動、タイヤ、サスペンションとかをシミュレートできるコライダーだよ!ということです。
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(タイヤの見た目)
- Front Right(右前タイヤ)(Wheel Colliderをアタッチ)
親オブジェクトについて
このオブジェクトにアタッチするのは、
- Rigidbody
- Box Collider
- 車を制御するためのスクリプト
の3つです。
Rigidbody
必ず調整しなければ行けない項目はMassのみです。
実際の車は1500kgほどが一般的ですので、Massは1500くらいが無難です。
Box Collider
CenterとSizeを調整して、車のボディが覆われるように設定してください。
この時、地面に接してしまわないように車の底部がColliderの底部になるよう調整してください。
シャコタンになってタイヤが接地しなくなります。
車を制御するためのスクリプト
車の運転は、走る、曲がる、止まる。
もっと詳しく言うと、前進後退、右折左折、停止ができればOKです。
これを成業するためにWheel Colliderには
- motorTorque(回転の力)
- steerAngle(左右の舵角)
- brakeTorque(ブレーキの力)
という変数が用意されていて、これに値を代入すれば車が動きます。
あとはInputの内容を値に反映してあげれば良いわけです。
今回はWASDキーor矢印キーで前後左右の操作、スペースキーでブレーキという操作を前提にサンプルのスクリプトを用意しました。
サンプルコード
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;
}
}
}
これで親オブジェクトの設定は完了です!
Wheel Colliderについて
まず、Front Right~Rear Leftのタイヤが置かれる位置に座標をセットしてください。
次は、四輪すべてに追加したWheel Colliderの設定項目です。
ここはサスペンションの硬さ、減衰力、タイヤの摩擦力などかなり専門的な領域です。
基本的にこの設定を守ってもらえれば、しっかりとした挙動の車になるかと思います。
4つのWheel Collider、すべて同じ値でOKです。
強いて変わるとするなら、タイヤの見た目に応じてタイヤの半径が変わると思うので、Sceneビューを見ながらRadiusを調整してください。
実際のサイズに合わせる。
親オブジェクトのSample Car ControllerスクリプトにあるWheelsに上から順番に割り当ててください。
CenterOfMassについて
車の重心は中央よりちょっと上くらいがおすすめです。
親オブジェクトのSample Car Controllerスクリプトに割り当ててください。
おしまい!
以上が、最もシンプルな車の挙動の実装方法です。
今回は初心者向けということで、Wheel Colliderの詳しい説明は省きましたが、気になる方は調べてみてください!
これでレースゲームを作る第一歩を踏み出せますので、まずはF1を観るところからはじめてみましょう。
今回お借りした3Dモデル
Mazda Miata MX-5 NA - Sketchfab