PR

【Unity】フライトシミュレーターを作る:ゲームシステム

Unityを使って作成した鳥人間コンテストの滑空機部門を想定したフライトシミュレーターのゲームシステムについての開発者用の備忘録

実際に作成したフライトシミュレーターはこれ

keywords: Unity,物理演算,フライトシミュレーター,人力飛行機,微小擾乱理論

スポンサーリンク

はじめに

Unityを使って鳥人間コンテストの滑空機部門を想定したフライトシミュレーターを作成する

Unityのバージョンは2020.3.8f1

Unityについては多くの入門サイトがあったが,今回特に参考にしたのはこちら

Unityの全般的な知識は上のサイトで,物理演算の基本については下のサイトを参考にした

Unity入門【初心者為の使い方講座】【実際にゲームを作って解説】 _ ゲームの作り方!
Unity カテゴリーの記事一覧 - エフアンダーバー

↓鳥人間コンテストのフライトシミュレーターの先駆者様

みえ日記
人力飛行機 シミュレータ HPASim のはなし - きかいや。

↓今回作成したプログラム

BRSimulator/Assets/Script at main · mtkbirdman/BRSimulator
Contribute to mtkbirdman/BRSimulator development by creating an account on GitHub.

↓その他の解説記事

それではいってみよう

ゲームシステムの概要

今回のフライトシミュレーターはいたってシンプルで,以下の3つのシーンで構成されている

シーン - Unity マニュアル
シーン (scene) には、ゲームの環境とメニューが含まれています。各シーンファイルを一意のレベルと考えてください。各シーンに、本質的にゲームをデザインし構築する環境、障害物、装飾を配置します。
  1. タイトル画面
  2. モデル選択
  3. フライト

基本的には2.と3.を行ったり来たりするだけなので,タイトル画面は正直なくてもいい

この記事ではこれら3つのシーンについて1ずつ説明していく

MyGameManeger

ゲーム全体を管理するScriptとして,MyGameManegerを作成した
Unity 2Dアクションの作り方【ゲームマネージャーを作ろう】 _ ゲームの作り方!

mtkbirdman.com/BirdmanRallySim/MyGameManeger.cs at master · mtkbirdman/mtkbirdman.com
mtk_birdman's blog @mtk_birdman. Contribute to mtkbirdman/mtkbirdman.com development by creating an account on GitHub.

MyGameManegerは,「シーンが移動しても保持しておきたい値」を管理するもので,今回は以下の変数を管理している

変数名type初期値説明
Landingboolfalse着水したかどうか.着水するとtrue
HUDActivebooltrueHUDが表示されているかどうか.表示されているとtrue
HorizontalLineActiveboolfalse水平線が表示されているかどうか.表示されているとtrue
SettingActiveboolfalse設定画面が表示されているかどうか.表示されているとtrue
CameraSwitchboolfalseカメラが切り替えられているかどうか.FPS視点ならtrue.TPS視点ならfalse
SettingChangedboolfalse初期条件が変更されたかどうか.変更されていればtrue
GustMagfloat0.000f風速 [m/s]
GustDirectionfloat0.000f風向き [deg]
Airspeed_TOfloat0.000f初速 [m/s]
alpha_TOfloat0.000f初期迎角 [deg]
PlaneNamestring"QX-20"選択されたモデルの名前
PlaneGameObjectnull選択されたモデルのGameObject

これらの変数は,どのシーンのどのスクリプトからもMyGameManeger.instance.(変数名)でアクセスすることができる

タイトル画面 (TitelScene)

最初に表示される画面で,以下の機能を有している

  • スタートボタンを押すとモデル選択画面に進む

ほぼ下の記事のとおりである
Unity 2Dアクションの作り方【タイトル画面作成】【入門】 _ ゲームの作り方!

ボタンを押すと次のシーンに進むスクリプトのみ書き換えたので説明する

LoadSceneButton.cs

Canvas/Buttonにアタッチされているスクリプト

mtkbirdman.com/BirdmanRallySim/Button/LoadSceneButton.cs at master · mtkbirdman/mtkbirdman.com
mtk_birdman's blog @mtk_birdman. Contribute to mtkbirdman/mtkbirdman.com development by creating an account on GitHub.

public void OnClick(string SceneName)とすることで,インスペクターにOnClick()の引数を入力することができるようになる

これにより,いろいろなボタンに対してこのスクリプトを適用することができるようになった

今回はSceneManager.LoadSceneを使ってModelSelectSceneにすすむよう設定する
SceneManagement.SceneManager-LoadScene - Unity スクリプトリファレンス

モデル選択画面 (ModelSelectScene)

タイトル画面の次に表示される画面で,以下の機能を有している

  • フライトシミュレーターに使うモデルを選択する
  • クリックされた画像のモデルをフライトシミュレーターで使用するよう設定する
  • モデル選択後,フライトシーンに移動する
  • 画像クリック後からフライトシーンに移動するまでの間,「Loading...」を表示する

ヒエラルキーウィンドウはこんな感じ

基本はタイトル画面と同じだが,Canvasの子オブジェクトにモデル選択用のボタンとLoadingTextがある

ModelSelectButton.cs

Canvas/Button0~Button2にアタッチされているスクリプト

mtkbirdman.com/BirdmanRallySim/Button/ModelSelectButton.cs at master · mtkbirdman/mtkbirdman.com
mtk_birdman's blog @mtk_birdman. Contribute to mtkbirdman/mtkbirdman.com development by creating an account on GitHub.

Start()の中で,GameObject.Findを使ってLoadTextのGameObjectを取得し,GameObject.SetActiveで非アクティブにしている
GameObject-Find - Unity スクリプトリファレンス
GameObject-SetActive - Unity スクリプトリファレンス

LoadSceneButtonと同様にpublic void OnClick(int number)とすることで,インスペクターでそれぞれのボタンに数字を割り当てることができ,ボタンごとに違う処理を行っている

今回はMyGameManeger.instance.PlaneNameにモデルの名前を入れ,LoadingTextをアクティブにし,FlightSceneに進むようにする

フライト画面 (FlightScene)

今回のメイン画面であり,以下のGameObjectから構成されている

  • SystemController
  • Plane
  • HUD
  • SETTING
  • WarterProDaytime

ひとつづつ説明していく

SystemController

いろんなスクリプトがアタッチされた空のゲームオブジェクトである

以下のスクリプトがアタッチされている

  • ModelController.cs
  • MyCameraController.cs
  • SettingController.cs
  • HUDController.cs
  • LoadSceanController.cs
ModelController.cs

モデルを切り替えるためのスクリプトで,以下の機能を有している

  • Planeの子オブジェクトにおいて,選択されたモデル以外の物を非アクティブにする
  • MyGameManeger.instance.Planeに選択されたモデルのGameObjectを入れる
mtkbirdman.com/BirdmanRallySim/SystemController/ModelController.cs at master · mtkbirdman/mtkbirdman.com
mtk_birdman's blog @mtk_birdman. Contribute to mtkbirdman/mtkbirdman.com development by creating an account on GitHub.

foreach(Transform child in GameObject.transform){}をつかうことで,GameObjectが持つすべての子オブジェクトにアクセスすることができる
C# - Unityでオブジェクトの子要素を全て非アクティブにする方法|teratail

あとはif文を使って選択されたモデル以外をGameObject.SetActive(false)で非アクティブにし,GameObject.Find()を使ってMyGameManeger.instance.Planeに選択されたモデルのGameObjectを入れるだけである

ちなみにこのスクリプトは,Script Execution Orderを使うことで,すべてのスクリプトのStart()の中で一番最初に実行されるよう設定している
Script Execution Order - Unity マニュアル

MyCameraController.cs

カメラを切り替えるためのスクリプトで,以下の機能を有している

  • Spaceキーを押すとカメラを切り替える
mtkbirdman.com/BirdmanRallySim/SystemController/MyCameraController.cs at master · mtkbirdman/mtkbirdman.com
mtk_birdman's blog @mtk_birdman. Contribute to mtkbirdman/mtkbirdman.com development by creating an account on GitHub.

Start()の中で,FPSカメラ,TPSカメラ,HUDのキャンバス,SETTINGのキャンバスを取得している

FPSカメラとTPSカメラは選択されたモデルの子オブジェクトとして存在しているので,Transform.Findで取得してからGameObject.GetComponentを使っている
Transform-Find - Unity スクリプトリファレンス
GameObject-GetComponent - Unity スクリプトリファレンス

void Update()
{
    if(Input.GetKeyDown("space")){SwitchCamera();}
}

Update()の中でInput.GetKeyDown()を使いSpaceキーが押されたことを検知し,自作関数のSwitchCamera()を呼び出している
Input-GetKeyDown - Unity スクリプトリファレンス

SwitchCamera()では,MyGameManeger.instance.CameraSwitchtrueならFPSカメラからTPSカメラに切り替え,falseならTPSカメラからFPSカメラに切り替えるための操作を行う

TPSカメラからFPSカメラに切り替える(CameraSwitch=true)ときは以下の操作を行う
Behaviour-enabled - Unity スクリプトリファレンス
Canvas-worldCamera - Unity スクリプトリファレンス

  • TPSカメラを無効にし,FPSカメラを有効にする
  • HUDとSETTINGのキャンバスのカメラをFPSカメラに設定する
  • CameraSwitch=falseにする
  • HorizontalLineを非アクティブにし,HorizontalLineActive=falseにする
SettingController.cs

設定画面の表示/非表示を切り替えるスクリプトで,以下の機能を有している

  • Tabキーを押すと設定画面の表示/非表示を切り替える
  • 設定画面を開いている間はフライト画面を止める
mtkbirdman.com/BirdmanRallySim/SystemController/SettingController.cs at master · mtkbirdman/mtkbirdman.com
mtk_birdman's blog @mtk_birdman. Contribute to mtkbirdman/mtkbirdman.com development by creating an account on GitHub.

Input.GetKeyDown()に加え,時間を止めるためにTime.timeScaleを使っている
Time-timeScale - Unity スクリプトリファレンス

HUDController.cs

HUDの表示/非表示を切り替えるスクリプトで,以下の機能を有している

  • Iキーを押すとHUDの表示/非表示を切り替える
  • FPS画面のときにHキーを押すと水平線の表示/非表示を切り替える
mtkbirdman.com/BirdmanRallySim/SystemController/HUDController.cs at master · mtkbirdman/mtkbirdman.com
mtk_birdman's blog @mtk_birdman. Contribute to mtkbirdman/mtkbirdman.com development by creating an account on GitHub.

HUDのGameObjectに関しては他のスクリプトからもGameObject.Find()で参照される可能性があるので,非表示のときに非アクティブにするのではなく,Canvas.planeDistanceをいじってカメラの描画範囲外に出すという方法をとっている

LoadSceanController.cs

キー入力に応じてシーン移動を行うスクリプトで,以下の機能を有している

  • Rキーを押すとフライトを最初からスタートする
  • Eキーを押すと初期条件をデフォルトの設定に戻してフライトを最初からスタートする
  • Qキーを押すとモデル選択画面に戻る
mtkbirdman.com/BirdmanRallySim/SystemController/LoadSceanController.cs at master · mtkbirdman/mtkbirdman.com
mtk_birdman's blog @mtk_birdman. Contribute to mtkbirdman/mtkbirdman.com development by creating an account on GitHub.

Plane

飛行機のモデルが入っているゲームオブジェクトである

Planeの子オブジェクトにはそれぞれの機体のGameObjectとサムネ撮影用のカメラがある

さらに,それぞれの機体のGameObjectにはラダー,エレベーター,FPSカメラ,TPSカメラがくっついている

TPSカメラの子オブジェクトにあるTrai Rendererは機体の軌跡を表示するために使っている

機体モデル

機体モデルについては次の記事を参照

機体モデルにアタッチされている物理演算のスクリプトは次の記事を参照

Trail Renderer

機体の軌跡を表示するためにTrail Rendererを使っている
Trail Renderer - Unity マニュアル

TPSカメラの後ろから巨大なTrailを表示して,それを真上からカメラで撮影することによって画面左下のMAPを表示させている

HUD

画面に速度などの値を表示するためのゲームオブジェクトで,以下の要素で構成されている

  • 計器類
  • HorizontalLine
  • MAP
  • Buttons

HorizontalLineはただの赤くて細いImageで,Buttonsはタイトル画面にあるボタンとほぼ同じなので,ここでは計器類の表示とMAPの表示について説明する

計器類の表示

今回は飛距離,速度,高度,姿勢角,迎角横滑り角,突風の情報を表示しているが,姿勢角以外のプログラムはだいたい同じなのでここでは速度を例に説明する

mtkbirdman.com/BirdmanRallySim/HUD/Airspeed.cs at master · mtkbirdman/mtkbirdman.com
mtk_birdman's blog @mtk_birdman. Contribute to mtkbirdman/mtkbirdman.com development by creating an account on GitHub.

Start()の中でTextとAerodynamicCalculator.csのスクリプトを変数に格納している

こうすることで,script.(publicな変数名)とすればAerodynamicCalculator.csの変数にアクセスすることができる

姿勢角の計算についてはこちら

左手系のクォータニオンから右手系のオイラー角を求める必要がある

MAP

ミニマップの実装についてはこの記事を参考にした
【Unity】3Dゲームでミニマップを表示させる方法 - Qiita

SETTING

設定画面を表示して初速などの変更を行うためのゲームオブジェクト

mtkbirdman.com/BirdmanRallySim/HUD/Setting.cs at master · mtkbirdman/mtkbirdman.com
mtk_birdman's blog @mtk_birdman. Contribute to mtkbirdman/mtkbirdman.com development by creating an account on GitHub.

ここまでくれば説明はいらない気がする

WaterProDaytime

水面に関してはStandard AssetsのWaterProDaytimeを使用した
Standard Assets (for Unity 2018.4) _ アセットパック _ Unity Asset Store
【Unity】Standard AssetsがImport Packageに表示されていないときの対処方法 - Qiita

水面に反射する機体がとてもいい感じである

WaterProDaytimeの設定は以下の記事を参考にいい感じに決定
Unityで湖や海を作成する _ Unityを使った3Dゲームの作り方(かめくめ)

Landing.cs

WaterProDaytimeにBox Colliderと以下のスクリプトをアタッチすることで着水判定をしている
Box Collider - Unity マニュアル

mtkbirdman.com/BirdmanRallySim/HUD/Landing.cs at master · mtkbirdman/mtkbirdman.com
mtk_birdman's blog @mtk_birdman. Contribute to mtkbirdman/mtkbirdman.com development by creating an account on GitHub.

おわりに

Unityで鳥コン滑空機のフライトシミュレーターを作成した

描画やスクリプトを最適化したら動作自体はもう少し軽くできるかもしれない

Unity
質問・感想・意見などあれば気軽にTwitterのDMかコメントお願いします!
スポンサーリンク

コメント