更新履歴2019/11/14レイヤーマスクによる判定のコードを修正しました。いうわけで、人生26年目の目前で花粉症と診断されてしまったりべるんです。今までニュースの「花粉が非常に多いため~」という話は完全スルーでしたが、いきなり敏感に聞くようになってしまいました。国民病と言われるのも納得ですね。した前置きを挟んだ後で、今回は「3Dゲームにおけるロックオン」に関するお話です。話としては以下の記事の続きになります。【Unity】3Dのカメラ視点移動とロックオン機能について超簡易的なロックオン機能を作ってみたので、それをもうちょっとマシな形に直したいという趣旨です。ロックオン可能なゲームでは、ロックオン対象の決定を複数の方式から選択できることがありますが、今回はシンプルに「最も近いオブジェクトをロックオンする」方式について考えてみました。対象を注視し続ける処理は前回と変わらないので、ロックオン対象を決定・取得する関数のみをご紹介します。}}playerは自キャラのGameObject型の参照で、Start()時に取得しています。ロックオンボタンを押した時に超短距離のSphereCastAll()を放ち、周囲のオブジェクトを取得します。返り値をforeachで回して各々の距離を測ります。短距離のキャストのためかRaycastHit.distanceは役に立たないので、Select()でGameObject型のListに直した上でVector3.Distance()を使用しました。最短距離のオブジェクトが見つかったらhit.transform.gameObjectの参照を取っておくことも忘れないようにしましょう。上の実装では画面外にいる対象までロックオンしてしまいます。そこでロックオン対象を「画面に表示されているオブジェクト」に限定します。}).ToList();}FilterTargetObject()という関数内でターゲット対象を絞ります。WorldToViewportPoint()でビューポートに変換した場合、画面左下が0:0、右上が1:1として正規化されるそうです。https://docs.unity3d.com/ja/2017.3/ScriptReference/Camera.WorldToViewportPoint.htmlということで、その範囲からXY軸が出ていないかをWhere()内から返すことで、はみ出していないオブジェクトのListが取得できます。ロックオン対象とするオブジェクトの限定これまでの処理は(画面外以外で)ロックオン対象を限定していないため、どんなオブジェクトでもロックオン対象としてしまいます。実体のあるオブジェクトならまだしも、音やエフェクト用のオブジェクトをロックオンされても困りますよね。ロックオン対象を限定する方法を考えてみると、以下のような方法が思いつきました。共通のタグを付けるロックオン対象に共通するタグを付け、その文字列を比較して限定する方法です。シンプルで分かりやすい方法ですね。.ToList();}ただ、ロックオン対象の選別のためだけにタグを参照するのも微妙な気がします。現行のUnity(2017)では複数のタグが設定できないのが厳しい感じですね。インタフェースを実装する特定のインタフェースを実装し、オブジェクトがそのインタフェースを実装しているかどうかで判断する方法です。.ToList();}いざ作ってみるとWhere()内でforeachな上にGetComponents()と、少し処理が冗長な気が否めません。ターゲットとしたいオブジェクトに「インタフェースを実装したクラス」を作る必要があることです。ないケースとは思いますが、スクリプトを設定しないターゲットをロックオン対象にしたい場合は不便かもしれません。レイヤーマスクで判定するSphereCastAll()のオーバーロードでレイヤーマスクを指定できるものがあります。レイヤーを追加し、ロックオン対象となるオブジェクトのみに該当レイヤーを設定します。この場合、スクリプトの修正はSphereCastAll()の引数のみになります。h.transform.gameObject).ToList();LayerMask.GetMask()でターゲット対象のレイヤー名を指定しましょう。難点はレイヤーの追加と設定が面倒なことくらいでしょうか。複数のレイヤーを指定することもできるので、この中では最も柔軟な方法かと思います。【レイヤーマスクで判定する】の部分の”LayerMask.NameToLayer(“Enemy”)”に関してなのですが、LayerMask.NameToLayerはレイヤーマスクの番号を返す関数なので、正しくはLayerMask.GetMaskでターゲットのレイヤーを指定する必要があります。PMmonacaさんご指摘ありがとうございます。記事内容を修正しました。仮に`NameToLayer()`を使う場合はビットシフトが必要ですね。ツイートこのブログを書いている人りべるんアザラシが大好きな山梨県産Webエンジニア。2019年3月よりフリーランスSEとして東京で活動中。