i-school - 3Dダイビングゲーム 手順7
 以下の内容で順番に実装を進めていきます。

 この手順では、キャラが湖の水面に着水した際の接触判定処理と、その判定に合わせて、カメラの追従処理を停止する処理を実装していきます。

手順7 −着水処理の実装−
 9.スクリプトを使って、キャラが水面を通過した判定を行うようにする
10.キャラが着水したら、カメラの追従を停止する制御を行う



新しく学習する内容


 ・Tagの設定
 ・OnTriggerEnterメソッド
 ・外部のスクリプトから変数の情報を参照する


9.スクリプトを使って、キャラが水面を通過した判定を行うようにする

1.設計


 湖に着水した、という単語をプログラム化していく手順です。

 湖に着水したら、という問いかけをプログラムで制御を行うには、「着水」という情報を作るところから始めます。
この情報はキャラが管理することが望ましいですから、キャラが着水したのか、あるいは着水はしていないのか、という情報を持つことが必要になります

 こちらは bool 型で情報を管理できるようにします。inWater という変数を用意して、false = 着水していない、true = 着水した、というように切り替えるようにすれば
この変数を参照することで、「湖に着水したら」という条件を表現することが出来るようになります


 湖との着水の判定ですが、水面のゲームオブジェクトには、Box 型の Collider を設置済です。
このコライダーにキャラのゲームオブジェクトにアタッチされているコライダーが侵入したら、それを「湖に着水した」と判定するようにします

 コライダーだけではどのゲームオブジェクトのコライダーに侵入したのか判定が難しいので、
水面のゲームオブジェクトには Tag を設定します。これはゲームオブジェクトの分類を行うとともに、判定時に特定の Tag かどうか、という方法で利用できます。

 
 何回も判定が発生してしまってはバグの温床になりますので、この変数をさらに利用して、すでに湖に着水している場合には、
2回目以降は同じ処理をしない、という制御も含めるようにします。そうすれば、1回だけ湖に着水した時にだけ、期待している制御行動を処理させることが出来ます。


 日本語をプログラム化するときには、ロジックを組む、という言葉を使います。
物事を論理的に考えて、どのような制御の組みあわせを作ることによって、実装したい処理を実現できるようします。


2.WaterProDaytime ゲームオブジェクトにTagを設定する


 ヒエラルキーから Stage ゲームオブジェクトの子オブジェクトである WaterProDaytime ゲームオブジェクトを選択し、インスペクターの名前の左下にある Tag の設定を変更します。
左クリックすることでプルダウンメニューが表示されますので、一番下にある Add Tag を選択します。

 任意の文字列をTagとして登録できますので、+ ボタンをおして、Water を登録してください。





 もう一度、WaterProDaytime ゲームオブジェクトを選択して、同じように Tag の設定を選択すると、登録したWater のTagが追加されていますので、
Untagged(Tag なし)の状態を Water に変更してください


<手順動画 Tagの設定>
https://gyazo.com/d04237ae569f268f9bc7fa380a831837


WaterProDaytime ゲームオブジェクト インスペクター画像



3.PlayerController スクリプトを修正する


 すでに作成されている PlayerController スクリプトを修正します。
設計の手順で説明を行いましたように bool 型の inWater 変数を用意して、こちらと、先ほど水面のゲームオブジェクトに設定した Tag とを組み合わせて if 文の条件式に利用します

 こちらの判定には、Unityが最初から提供してくれている、OnTriggerEnter というメソッドを利用します。
これは IsTrigger のスイッチが入っているコライダーと、このスクリプトがアタッチされているゲームオブジェクトのコライダー
(つまり、Penguin ゲームオブジェクトにアタッチされている Capsule Collider)とが接触して通過(侵入)した際に、自動的に呼び出されるメソッドです。
このように、ある一定の条件を満たした際に自動的に呼び出されるメソッドのことをコールバック・メソッドといいます


PlayerController.cs

 <= クリックすると開きます



4.<OnTriggerEnterメソッド>


 Unityの MonoBehaviour クラスの持つメソッドの1つです。
このメソッドが記述されたスクリプトのアタッチされてるコライダーを持つゲームオブジェクト(キャラ)が、他のコライダーを持つゲームオブジェクトを通過した際に接触(侵入)判定を行うメソッドです。

 このスクリプトがアタッチされているゲームオブジェクトのコライダーの中に、侵入したゲームオブジェクトがある場合、その情報を Collider 型で取得し、メソッド内で利用できる状態にしてくれます

 通常コライダーを持つオブジェクト同士は接触し停止しますが、いずれか片方のゲームオブジェクトのコライダーの IsTrigger のスイッチがオンになっている場合、
コライダーを持つゲームオブジェクトを通過することができます。その際に、このメソッドが侵入判定を行います。

    // IsTriggerがオンのコライダーを持つゲームオブジェクトを通過した場合に呼び出される、コールバック・メソッド
    private void OnTriggerEnter(Collider col) {
        if (col.gameObject.tag == "Water" && inWater == false) {

            inWater = true;


            // TODO 水しぶきのエフェクトを生成

            Debug.Log("着水 :" + inWater);
        }
    }

Unity公式スクリプトリファレンス
OnTriggerEnter
https://docs.unity3d.com/ja/current/ScriptReferenc...


5.Penguin ゲームオブジェクトの PlayerController スクリプトを確認する


 スクリプトの修正が済みましたので、Penguin ゲームオブジェクトのインスペクターから PlayerController スクリプトを確認しましょう。

 着水したかどうかの判定を管理するための inWater 変数が追加されていると思います。
このままスイッチはオフ(false)の状態のままにしておいてください。水面のコライダーに侵入した際に、スイッチがオン(true)に入れば制御は成功です。


Penguin ゲームオブジェクト インスペクター画像



6.ゲームを実行して動作を確認する


 ゲームを実行して、キャラを落下させます。水面のすぐ下に配置してある IsTrigger にチェックの入っている Box Collider コンポーネントに対して
キャラのゲームオブジェクトが侵入して Capsule Collider が接触したとき、PlayerController スクリプトに追加した OnTriggerEnter メソッドが自動的に呼び出されます。

 この処理の中では、Water の Tag を持つゲームオブジェクトに侵入した際に、inWater を true にして重複判定を防ぐとともに着水状態を作り出します
このように bool 型を利用することでゲーム内に特定の状況・状態の設定を組み込むことが出来ます

 また Debug.Log メソッドがありますので、Console に、着水の文字と、inWater の値(true) とが表示されれば、制御は成功です。
inWater が false の際にしか、if 文の条件は成立しないため、Console ビューには1回しかDebug.Logは表示されないはずです


<実行動画>
https://gyazo.com/ea4cc758e9973d3a7386efbb1c3096c3


Console ビュー画像



 以上でこの手順は完成です。


10.キャラが着水したら、カメラの追従を停止する制御を行う

1.設計


 キャラに着水という状態の制御(isWater 変数)が追加されましたので、次は、カメラの追従をこの変数を利用して制御します。

 ・キャラが着水していない(inWater = false) => カメラはキャラを追従する
 ・キャラが着水した(inWater = true)         =>  カメラはキャラの追従を止めて、水面を映すようにする

 このように制御を行います。
この制御処理は CameraController スクリプトに記述していきます。


 こういった設計ロジックを考えていくコツは、どの情報があれば、どんな処理を行うことができるのか、というイメージを持つことです

 ・キャラが水面用のゲームオブジェクトに侵入すると、inWater 変数が true になって、着水の状態になる
 ・この着水の状態によって、何か条件として利用できることはないか、考える
 ・カメラが着水後も追従してしまっていることに注目し、この制御処理を行うには、何をどうすればいいか、何を利用できるかを考える
 ・着水に合わせてカメラの追従の制御を行えれば都合がいい、着水の判定は inWater 変数を確認(参照)すれば、制御に組み込んで利用できる

 このように、1つの処理を順序立てて、どうやったらロジックとしてつながっていくだろうか、この情報は使えないだろうか、という視点で考えてみましょう。


2.CameraController スクリプトを修正する


 宣言してあった変数を変更します。
GameObject 型の playerObj 変数を削除して、代わりに、PlayerController 型の playerController 変数を宣言して利用します

 変更する理由は2つあります。1つ目は、PlayerController スクリプトに追加された、inWater 変数をこのスクリプトから参照したいためです。
この変数の参照を行い、どのような状態になっているかを確認することによって、その変数の状態に応じて、こちらのスクリプトも制御することが出来るからです。
その結果、設計で説明した、カメラの追従処理の切り替えが実装できます。

 もう1つの理由は、playerObj 変数を利用して参照していた transform 変数については、GameObject 型だけではなく、
自作した PlayerController 型からでも同じように参照することが出来ます

 つまり、PlayerController 型へ参照を行うことができれば、着水状態を確認するための inWater 変数と
位置情報を確認するための transform 変数の両方への参照が1つで行えるようになります

 そういった理由があるため、以前利用していた GameObject 型の変数は削除し、その参照を利用出来る上に、別の参照も可能になる
PlayerController 型の変数を新しく用意して宣言を行っています。


CameraController.cs

 <= クリックすると開きます。



3.<外部のスクリプトから変数の情報を参照する>


 以前は GameObject 型の参照を利用して Transform コンポーネントの情報を取得していました。
先ほども説明しましたが、スクリプトを利用することでも、そのスクリプトがアタッチされているゲームオブジェクトの Transform コンポーネントの情報を取得することが可能です。

 無理に GameObject 型で情報を取得せずとも、スクリプトを経由することで必要な情報にたどり着くことが出来ます


4.Main Camera ゲームオブジェクトの CameraController スクリプトのアサイン情報に Penguin ゲームオブジェクトをドラッグアンドドロップしてアサインする


 スクリプトの修正が済みましたので、Main Camera ゲームオブジェクトのインスペクターから、Camera Controller スクリプトを確認します。

 変数の宣言を変えていますので、今度は GameObject 型ではなく、PlayerController 型でのアサイン情報を求められるようになります。


Main Camera ゲームオブジェクト インスペクター画像



Main Camera ゲームオブジェクト 以前のインスペクター画像(アサインできる型が異なることに注目すること)



 ヒエラルキーにある、PlayerController スクリプトがアタッチされているゲームオブジェクトのみ、この情報にはアサイン出来ます。
試しに、DirectionalLight ゲームオブジェクトや Stage ゲームオブジェクトなどをドラッグアンドドロップしてみてください。
以前とは違い、GameObject 型ではないため、これらのゲームオブジェクトはアサインできません。

 Penguin ゲームオブジェクトをドラッグアンドドロップしてください。
自動的に、Penguin ゲームオブジェクトにアタッチされている、PlayerController スクリプトがアサインされます


<手順動画 アサイン>
https://gyazo.com/55a80bfce82d9c6cc400eb5e51bd12d8


 アサインできる情報には、必ず( )書きで、アサインできる型が表示されています
また、アサインが完了している場合には、None ではなく、ゲームオブジェクトの名前が表示されます

Main Camera ゲームオブジェクト アサイン後のインスペクター画像



5.ゲームを実行して動作を確認する


 ゲームを実行して、キャラを着水させてみてください。着水状態を判断したカメラが追従を止めるように制御されていれば成功です。
水中でキャラを動かしても追従しなくなっています。


<実行動画>
https://gyazo.com/61ebbc29696d7c8674176e476ed48aae


 以上でこの手順は終了です。

 => 次は 手順8 −着水時のエフェクト処理の実装− です。