こんにちは、ともくんのゲーム作り部屋にようこそ!
このページでは、
「レースゲームで使えるコースを自分で作成してみたい!」
「Unityで円形のコースを作ってみたいんだけど、どう作ればいいの?」
というお悩みの方に向けた内容となっています。
ブログ本編の前に少しだけ雑談、、、
前回の更新から期間が空いてしまいましたが、この期間ずっとAndroidのアプリ開発を行っていました!
ゲームではなく日常的に使うようなアプリで、「.NET MAUI」というフレームワークを使ったので、Unityと同じC#言語で毎日コードを書き続けていました。
上手くいかないことばかりの連続で、大したものじゃないけど半年以上もかかってしまいましたが、C#の書き方については以前より(きっと)レベルアップしたはず!
アプリ自体は一通り完成したけど、現在Google Playにアップロード申請中なので、また公開できたらこのブログでも紹介しようかなと思います。
そして、久しぶりにUnityに戻ってきたのですが、実はアプリ開発中に作りたいゲームを決めていて、それが競馬のシミュレーションゲームです!(ギャンブルは全くやらないけど競馬を見るのが好きなタイプ)
これから競馬ゲームを作りながら、自分で分からなかった部分や上手くいかなかった部分などを備忘録的にブログでまとめていきます。
Unityでレースゲームなどに使うコースってどうやって作ったらいいのかを調べていたところ、Spline(スプライン)という機能を使うのが良さそうでした。
このSplineという機能は、簡単に言えば3D上に自由に線を作成することができる機能で、その線を基準として地面を作成したり、その線に沿って移動させるといったことができます。
実際に、僕も競馬ゲームで使う競馬場コースをSplineで作ってみたのですが、以下のようなものを簡単に作ることができました。

そこでこのページでは、Unityでレースゲームなどを作る際に便利なSplineがどんな機能なのか、また実際に僕がSplineで上記の競馬場コースを作るまでの内容をまとめていきます。
コース作成に使えるSpline(スプライン)ってどんな機能?
Unity公式の機能であるSplineを使うことで、主に以下の2つを行うことができます。
- 自由な形状のメッシュを描写できる
- 形状に沿ってオブジェクトの移動ができる
それぞれをもう少し詳しく説明していきます。
点を使って自由な形状のメッシュを描写できる機能
元々、UnityにはCubeやPlaneなど初めから準備されてある3Dオブジェクトがありますよね。

これらでコースを作ろうとすると直線は描写できるのですが、どうしても曲線部分を上手く表すことができません。
そこで登場するのがSplineという機能で、これはコースの形状となる部分に点を配置していくと、それを自動で滑らかに繋げてくれます。

そして、この線を基準として幅を広げるようなイメージで道を作ることができます。

このようにSplineを使うと、テンプレートの3Dオブジェクトでは作れないような、自分だけの曲線オブジェクトを簡単に作ることができます。
形状(パス)に沿ってオブジェクトを移動させることができる
Splineにはもう一つ便利な機能があって、それは作成したコースの形状に沿ってオブジェクトを移動させることができるということです。
例えば、以下のようなコースをSplineの機能で作ったとします。

この上にオブジェクトを配置してスクリプトを使って移動させたとしても、当然まっすぐ移動させたらコースから外れてしまいます。

もちろんコースに沿わせるようにスクリプトから直接座標を指示すれば良いのですが、正直複雑なコースになればなるほどそんなのほぼ無理ですよね。
そこでSplineが持つEvaluateメソッドを使うと、以下のようにコースに沿ってオブジェクトを動かすことができます。

このようにSplineはコースを作成するだけでなく、その線に沿って移動することができる便利な機能です。
ただし、このEvaluate系のメソッドをそのまま使うと、僕の場合は思った動きをしてくれなかったので、サンプリングしてデータを自分で作り直すというちょっと面倒な処理を加えて使っています。
※次回以降の記事でその辺りはまとめていくつもりなのでしばらくお待ちください。
Splineを使って競馬場のコースを作成する手順
それでは、実際に僕が作ろうとしている競馬ゲームにおいて、簡単な競馬場コースをSplineで作成してみます。
Splinesパッケージをインストール
まずは、Splineの機能を使えるようにしたいので、パッケージのインストールをしていきます。
パッケージの管理はPackage Managerが行っているので、メニューからWindow > Package Management > Package Managerを選択します。

そして、開いたPackage Managerの中にあるUnity Registryを選択して、検索部分に「Splines」と入力し表示されたパッケージをインストールします。

これでインストールが完了すれば、Splineの機能が使えるようになります。
Create Splineでコースの仮形状を描く
いよいよコース形状をSplineで作っていきますが、今回作るのは以下のようなコースとなります。

シーンビューのツールの中にある「Create Spline」を選択します。(無い場合はヒエラルキーウィンドウの+ボタンからSpline > Draw Splines Tool…を選択)

すると、Splineの点を置くことができるモードになります。
あとで配置座標を数値で指定していくので、ここでは適当にマウスをクリックして6箇所ほど置いていきます。

すべてを置き終わったら、最初に付けた点をもう一度クリックして全ての点を繋げてあげることでコース形状が出来上がるので、そしたら一旦「View Tool」などを選択してSplineモードから戻します。

Spline Containerで各ポイント(Knot)の座標調整
次に、適当に配置した点を微調整して、作りたいコース形状にしていきます。
今作ったSplineのオブジェクトを選択すると、インスペクターウィンドウに「Spline Container」というものがあると思います。
このSpline Containerの中で、先ほど打った点(Knot)がそれぞれどこの座標なのか、またその点における曲線の傾きを決める接線をどうするかなど、細かい部分を調整することができます。

今回作りたいコースから、一番左下の点を基準座標として計算した場合、各点の座標を以下のように配置すると、きれいなコースを作れることがわかりました。

ということで、それぞれ上記で計算した座標をSpline Containerの各KnotのPositionの値に直接入れていきます。

すると、以下のような形状になりましたが、直線部分のコースが直線になっていないし、思ったようなコースにはまだなっていません。

Bezier(ベジェ)ハンドルでカーブの傾きを調整する
そこで、次に行うのがポイント毎における曲線の傾きというものを変えていきます。
まず事前に、シーンビューのツールモードでSplineツールに変更しておきます。

次に、いずれかのKnotを選択して「Bezier(ベジェ)」というものにしておきます。

このBezierにすることで、その点における曲線の傾きを決める接線をBezierハンドルで調整できるようになります。
シーンビューに戻ると、今選択しているKnotの点が光っていて、接線が表示されているのが分かります。

この状態で、ツールからMove Toolなどを選択して、接線の端のポイントにカーソルを合わせて移動すると、接線の向きや長さを変更することができるようになります。

上記のように接線が変わると、曲線の傾き度合いが変わりコース形状自体が変化するようになるので、これで調整していきます。
実際に、ここでは各ポイントにおける接線を調整して以下の形状を作ってみました。

なお、今回作っている競馬場のコースは、各直線上の4箇所および曲線の2箇所をそれぞれのいずれか1箇所の曲線の傾きを決めたら、他の箇所の傾きも同じになるように直接代入しているので、かなり計算されたきれいなコースとなっています。
Spline Extrudeで線を基準に地面(コース)を作る
コース形状を作ることができたら、この線を元にして地面を作っていきます。
この地面を作るために使うのが、Spline Extrudeというコンポーネントです。
先ほど作成したコース形状のオブジェクト(Spline Containerがついているもの)を選択して、インスペクターウィンドウのAddComponetからSplines > Spline Extrudeを選びます。

Spline Extrudeにはいくつか設定項目があるのですが、重要になるのは以下の3つかなと思います。
Type:断面の形状タイプ
Typeは、Splineから地面を作成した際に断面となる部分の形状を指定することができます。
- Circle:断面が円形
- Square:断面が正方形
- Road:断面が平ら
- Spline Profile:別のSplineを使う
断面というと少し分かりにくいですが、今回作っているコースを真横から見たときにそれぞれ以下のようになるのが分かります。



競馬場の断面は平らで良いので、ここではRoadを選択しています。
Radius:コースの幅
Radiusは、Splineから地面を作成する幅を決める値となっています。
Splineの線を中心として、Radiusで指定した幅の分の地面が作成されます。
競馬場の幅は20m前後が多いようなので、ここでは「20」と設定することで、以下のようにSplineを軸として道幅を作ることができました。

Auto Refresh Generation:自動更新処理
元となるSplineが変更された場合に、作成している地面も一緒に更新させるかどうかという項目です。
このAuto Refresh Generationをオンにしておけば、Splineを変更した時にすぐに地面も変わってくれるのでデフォルトのオンのままでいいと思います。
地面(コース)のマテリアルを変更する
最後に、作成したコースのマテリアルを変更してあげましょう。
そのままだと一般道のような色のコースオブジェクトになってしまうので、ここでは競馬場っぽく芝の色に変更してあげます。
マテリアルの変更は通常のオブジェクトと同様で、プロジェクトウィンドウの+ボタンから「Material」を選択します。

作成されたマテリアルを選択して、インスペクターウィンドウのShaderを選択、ここではUniversal Render Pipeline > Litを選び、Base Mapの色を変更してあげます。

あとは、このマテリアルを先ほどのコースオブジェクトにアタッチしてあげれば、コースの色が変更されます。
最終的に、以下のような競馬場の元となるコースが作成できました。

コース周囲に柵(ラチ)を自動配置する
さて、競馬場のコースを作成できましたが、競馬場ってコースの内側と外側に柵があるのを知っていますか?
これをラチと言いますが、せっかくなので作成したコースにラチを置いて競馬場っぽくしてみようと思います。
ラチはコースの周囲にたくさん置いていく必要があるのですが、一つ一つ置いていくのはかなり大変な作業になります。
そこで「Spline Instantiate」というコンポーネントを使って、自動でSplineの周囲にオブジェクトを配置できる便利機能を使って作業していきます。
配置したい柵(ラチ)のオブジェクトをPrefab化する
まずは、事前にラチのオブジェクトを作成しておきます。
ここでは、Cylinderの3Dオブジェクトを使って以下のような簡単なラチとなるオブジェクトを作ってみました。

ベース(脚)部分を片方だけにしましたが、これを繋げてあげればラチのように見えるかなと思っています。
ただ、このラチは大量生産する必要があるので、アセットフォルダの方にドラッグ&ドロップしてPrefab化しておきます。

Spline Instantiateで等間隔かつ周囲に配置する
ラチをPrefab化できたら、コースとなるオブジェクト(Spline Containerがついているもの)を選択して、インスペクターウィンドウのAddComponentからSplines > Spline Instantiateを選びます。

このSpline Instantiateは、Splineに沿ってオブジェクトを自動で生成して配置することができる機能で、今回のようにSplineの外側や内側などに同じオブジェクトを配置するような場合にめちゃくちゃ便利な機能です。
まず、先ほどPrefab化したラチを「Items To Instantiate」の中にドラッグ&ドロップなどで指定しておきます。

すると、以下のようにコース上に指定したオブジェクトがずらっと並ぶと思います。

いやいや、並んだけど向きが違う!w
僕と同じように向きが違ってしまった場合、Up AxisやForward Axisの設定を変更してみましょう。
Forward Axisを「Object X+」に変更したところ、以下のようにちゃんとした向きで並びました。

次に、Spacingという項目ですが、それぞれのオブジェクト同士の空白を決めていて、オブジェクトをどれくらいの間隔で置いていくかという設定項目です。
今回はこの値を「3.5」にしています。
あとは、ラチを置きたいのはSplineの線上ではなく、コースオブジェクトの内と外の周りに置きたいので、Position Offsetを使って座標をずらしてあげます。
Position Offsetに値を入れるとその分、配置されているオブジェクトの位置がずれるのが分かるので、それを見ながら内側用としてX軸を-16.5ずらしてあげて、外側用にはX軸を+2.5ずらすようにしてみました。
ここまで完了したら、最後に「Bake Instances」を選択してあげます。

すると、以下のように指定したPrefabが自動で大量に生成されて、ラチが置かれているのが分かります。

内側と外側で2回実行することで、以下のように競馬場のコースの周囲にラチを簡単に置くことができました。

カーブ部分でラチがずれてしまう時の対処法
ここまでで競馬場コース自体は完成したのですが、実はカーブ部分をよくよく見てみると、、、

まっすぐな構造のラチをカーブに沿わせて配置したため、ラチ同士の接続部分に隙間や角度のずれが生じてしまっていました。
直線状のオブジェクトをSpline Instantiateで曲線を含めて敷き詰めようとすると、どうしてもこうしたずれが発生してしまいます。
そこでここでは、「手すり部分」と「脚の部分」を切り分けて配置するという方法で解決しました!
修正手順:3本のSplineで「手すり」と「脚」を分離する
まず、コース内のラチを置きたい内側と外側に1本ずつ新しくSplineを追加します。
画像が少し見にくいかもしれませんが、真ん中にこれまで作ったコース用のSplineが書いてあり、その外と内にSplineを追加しています。


そしたら、それぞれにSpline Extrudeを付けていくのですが、コースを作った時はTypeの項目をRoadにしましたが、このSplineは地面ではなく手すりの部分にしたいので、円形状になるCircleを選択します。
さらに、手すりは地面より上に配置する必要があるので、Y座標を少し上げておきます。

これで一度確認してみると、以下のように手すり風にちゃんとなっていて、カーブ部分もきれいに曲がっています。

あとは、先ほど作ったラチのオブジェクトを分解して脚だけのPrefabを作っておき、

最後に、Spline Instantiateを使って脚部分を配置していくのですが、Spline自体を上に1.8ずらしているので、脚は反対に地面に付くまで下に下げておく必要があります。

これで以下のようにカーブの際もラチがずれることなく、きれいなコースを作ることができました!

まとめ
このページでは、Unityでコースなどを作成するのに便利なSplineという機能について、どんなことが出来るのか、実際に自分でコースを作ってみたやり方などをまとめていきましたが、いかがでしたでしょうか?
Splineは、自由に線を描写することができる機能で、レースゲームなどのコースの形状を作るのにとても便利な機能となっています。
今回は非常にシンプルな競馬場のコースを作ってみましたが、さらに坂を付けたり、回転させてみたり、複雑なコース作りでも簡単にかつ直感的に作ることができる機能だなと思います。
また、記事内にも書きましたが、何と言ってもSplineはコースを作るだけじゃなくて、その上に沿って移動させることもできるので、例えば今回の競馬ゲームのようにCPUによる移動処理などを作る際はかなり活用できるのかなと思います。
最後までお読みいただきまして、ありがとうございました!




コメント