Unityを使って作成した鳥人間コンテストの滑空機部門を想定したフライトシミュレーターのゲームシステムについての開発者用の備忘録
実際に作成したフライトシミュレーターはこれ
keywords: Unity,物理演算,フライトシミュレーター,人力飛行機,微小擾乱理論
はじめに
Unityを使って鳥人間コンテストの滑空機部門を想定したフライトシミュレーターを作成する
Unityのバージョンは2020.3.8f1
Unityについては多くの入門サイトがあったが,今回特に参考にしたのはこちら
Unityの全般的な知識は上のサイトで,物理演算の基本については下のサイトを参考にした
≫Unity入門【初心者為の使い方講座】【実際にゲームを作って解説】 _ ゲームの作り方!
≫Unity カテゴリーの記事一覧 - エフアンダーバー
↓鳥人間コンテストのフライトシミュレーターの先駆者様
≫みえ日記
≫人力飛行機 シミュレータ HPASim のはなし - きかいや。
↓今回作成したプログラム
↓その他の解説記事
それではいってみよう
ゲームシステムの概要
今回のフライトシミュレーターはいたってシンプルで,以下の3つのシーンで構成されている
- タイトル画面
- モデル選択
- フライト
基本的には2.と3.を行ったり来たりするだけなので,タイトル画面は正直なくてもいい
この記事ではこれら3つのシーンについて1ずつ説明していく
MyGameManeger
ゲーム全体を管理するScriptとして,MyGameManegerを作成した
≫Unity 2Dアクションの作り方【ゲームマネージャーを作ろう】 _ ゲームの作り方!
MyGameManegerは,「シーンが移動しても保持しておきたい値」を管理するもので,今回は以下の変数を管理している
変数名 | type | 初期値 | 説明 |
Landing | bool | false | 着水したかどうか.着水するとtrue |
HUDActive | bool | true | HUDが表示されているかどうか.表示されているとtrue |
HorizontalLineActive | bool | false | 水平線が表示されているかどうか.表示されているとtrue |
SettingActive | bool | false | 設定画面が表示されているかどうか.表示されているとtrue |
CameraSwitch | bool | false | カメラが切り替えられているかどうか.FPS視点ならtrue.TPS視点ならfalse |
SettingChanged | bool | false | 初期条件が変更されたかどうか.変更されていればtrue |
GustMag | float | 0.000f | 風速 [m/s] |
GustDirection | float | 0.000f | 風向き [deg] |
Airspeed_TO | float | 0.000f | 初速 [m/s] |
alpha_TO | float | 0.000f | 初期迎角 [deg] |
PlaneName | string | "QX-20" | 選択されたモデルの名前 |
Plane | GameObject | null | 選択されたモデルのGameObject |
これらの変数は,どのシーンのどのスクリプトからもMyGameManeger.instance.(変数名)
でアクセスすることができる
タイトル画面 (TitelScene)
最初に表示される画面で,以下の機能を有している
- スタートボタンを押すとモデル選択画面に進む
ほぼ下の記事のとおりである
≫Unity 2Dアクションの作り方【タイトル画面作成】【入門】 _ ゲームの作り方!
ボタンを押すと次のシーンに進むスクリプトのみ書き換えたので説明する
LoadSceneButton.cs
Canvas/Buttonにアタッチされているスクリプト
public void OnClick(string SceneName)
とすることで,インスペクターにOnClick()
の引数を入力することができるようになる
これにより,いろいろなボタンに対してこのスクリプトを適用することができるようになった
今回はSceneManager.LoadScene
を使ってModelSelectScene
にすすむよう設定する
≫SceneManagement.SceneManager-LoadScene - Unity スクリプトリファレンス
モデル選択画面 (ModelSelectScene)
タイトル画面の次に表示される画面で,以下の機能を有している
- フライトシミュレーターに使うモデルを選択する
- クリックされた画像のモデルをフライトシミュレーターで使用するよう設定する
- モデル選択後,フライトシーンに移動する
- 画像クリック後からフライトシーンに移動するまでの間,「Loading...」を表示する
ヒエラルキーウィンドウはこんな感じ
基本はタイトル画面と同じだが,Canvasの子オブジェクトにモデル選択用のボタンとLoadingTextがある
ModelSelectButton.cs
Canvas/Button0~Button2にアタッチされているスクリプト
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を入れる
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キーを押すとカメラを切り替える
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.CameraSwitch
がtrue
なら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キーを押すと設定画面の表示/非表示を切り替える
- 設定画面を開いている間はフライト画面を止める
Input.GetKeyDown()
に加え,時間を止めるためにTime.timeScale
を使っている
≫Time-timeScale - Unity スクリプトリファレンス
HUDController.cs
HUDの表示/非表示を切り替えるスクリプトで,以下の機能を有している
- Iキーを押すとHUDの表示/非表示を切り替える
- FPS画面のときにHキーを押すと水平線の表示/非表示を切り替える
HUDのGameObjectに関しては他のスクリプトからもGameObject.Find()
で参照される可能性があるので,非表示のときに非アクティブにするのではなく,Canvas.planeDistance
をいじってカメラの描画範囲外に出すという方法をとっている
LoadSceanController.cs
キー入力に応じてシーン移動を行うスクリプトで,以下の機能を有している
- Rキーを押すとフライトを最初からスタートする
- Eキーを押すと初期条件をデフォルトの設定に戻してフライトを最初からスタートする
- Qキーを押すとモデル選択画面に戻る
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の表示について説明する
計器類の表示
今回は飛距離,速度,高度,姿勢角,迎角横滑り角,突風の情報を表示しているが,姿勢角以外のプログラムはだいたい同じなのでここでは速度を例に説明する
Start()
の中でTextとAerodynamicCalculator.csのスクリプトを変数に格納している
こうすることで,script.(publicな変数名)
とすればAerodynamicCalculator.csの変数にアクセスすることができる
姿勢角の計算についてはこちら
左手系のクォータニオンから右手系のオイラー角を求める必要がある
MAP
ミニマップの実装についてはこの記事を参考にした
≫【Unity】3Dゲームでミニマップを表示させる方法 - Qiita
SETTING
設定画面を表示して初速などの変更を行うためのゲームオブジェクト
ここまでくれば説明はいらない気がする
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 マニュアル
おわりに
Unityで鳥コン滑空機のフライトシミュレーターを作成した
描画やスクリプトを最適化したら動作自体はもう少し軽くできるかもしれない
コメント