障害物を含む索敵プログラムの作り方[with Target Scanner]

メタルギアソリッドの様に、物陰に隠れることで敵の索敵範囲を回避するようなゲームはよくあると思います。敵の索敵範囲というのは、いわゆる当たり判定で表現されます。この当たり判定の形は、障害物に遮られたり、視界の角度などを考慮する必要があり、普通のColliderなどで作るのは大変です。そういった方にオススメなのがTarget Scanner!

目次

ターゲットスキャナーにできること

ターゲットスキャナーの設定

ターゲットスキャナーでは次のようなものを設定することが可能です。

  • Gizmoの表示
    • デバッグで役に立つ
    • PlayModeに入ると検出された場合に赤い線が表示されます
  • Transform
    • 索敵の中心
    • 向きや位置など
    • 設定しているコンポーネントとことなるTransformを設定できるようにしている
  • Alert Radius
    • 向きに関係なく接近を感じる範囲
    • 背後の気配を察知できるかどうか。ゲームだとほぼ0にしてそう
  • View Radius
    • 視界の範囲
    • いわゆる目の良さ。遠くまで見渡せるかどうか
  • View Angle
    • 視界の角度
    • 90の場合、正面に対して-45度から+45度までの範囲を見渡せる360にすると無敵
  • Target Layer
    • 索敵対象の相手のレイヤーを指定
  • Obstacle Layer
    • 障害物になるレイヤーを設定
  • Height Offset
    • 視点の高さ
    • 一部Gizmoに反映されないので注意
  • Max Height Difference
    • 検出できる高さの上限
    • Gizmoの表示が平面っぽくなってますが、検出方法としてはスフィアで行われています。そのため真上にも判定がありますが、視点の上下方向は角度ではなく高さの値で制限をかけています

ターゲットスキャナの主要メソッド

実際にこちらの機能を利用する際に使用するメソッドについて。いずれもTransformが返ってくるので、必要なコンポーネントなどは別途取り直し。

  • GetTarget
    • 一番最初に検出されたオブジェクトを返す
    • 何が返ってくるかはお楽しみ
    • 見つからない場合はnull
  • GetNearestTarget
    • 一番近いターゲットを返す
    • 見つからない場合はnull
  • GetTargetList
    • 検出できたターゲットをList形式で返す
    • 見つからない場合はnull

ピンクになってる場合

パッケージを導入すると、サンプルシーンが同梱されているのですが、開いたら下図の様になっている場合。

シーン内で利用されているマテリアルを更新することで改善出来ます。通常のレンダリングパイプラインであれば、ShaderをStandardに変更すると、シーン内を見渡せるようになります。

スライム

ターゲットスキャナーの機能を使うだけであればここは無視しても大丈夫!

実際に自分で使ってみる:索敵編

サンプルシーンを見て使える方はそのまま利用していただいて大丈夫です。ここでは実際に自分のプログラムに組み込むためにどうすればよいかを試してみたいと思います。

  • 索敵対象のレイヤー
    • 今回はEnemyとします。プレイヤー自身ではなく、操作キャラクター自身が敵を認識できるかどうか
  • スクリプトで設定
    • 索敵範囲を可視化する
    • 検索条件を決める
  • オブジェクトの設定とお試し

索敵対象のレイヤーを追加

まずは何かのインスペクターやProject Settings/Tags and Layersから索敵対象のレイヤーを追加します。今回はEnemyとします。

スクリプト作成

スクリプトは新しいスクリプトを作成します。重要になるポイントは以下

  • using追加
    • DC.Scannerを追加します
  • メンバ変数追加
    • public TargetScanner scanner;を追加します。(今回はscanner変数で通します。)
    • これは必要な分だけ追加が必要です。
    • 複数の目が必要な場合、リストや配列も対応しています
  • ターゲットを取得する処理
    • 記述はFixedUpdateで行います。
    • メソッドは以下
      • scanner.GetTarget()
      • scanner.GetNearestTarget();
      • scanner.GetTargetList();
  • デバッグ用の表示を追加
    • OnDrawGizmosメソッドを追加して、scanner.ShowGizmos()を記載しましょう

参考スクリプトは以下。スクリプト名はSeacherとします。

using System.Collections.Generic;
using UnityEngine;
using DC.Scanner;

public class Searcher : MonoBehaviour
{
    public TargetScanner scanner;

    Transform nearestTarget;
    Transform firstDetectedTarget;
    List<Transform> targetList;

    private void FixedUpdate()
    {
        firstDetectedTarget = scanner.GetTarget();
        nearestTarget = scanner.GetNearestTarget();
        targetList = scanner.GetTargetList();
    }

    private void OnDrawGizmos()
    {
        scanner.ShowGizmos();
    }
}

シーンのセットアップ

スクリプトが準備できたら検出の準備を行います。

スキャナー側

  • Searcherのオブジェクトを追加
    • 今回はCapsuleを使います
    • 名前を変更Searcher
    • Searcherスクリプトをアタッチ
  • Searcherコンポーネント設定
    • 必須になるのは以下
    • Transform:自分自身のオブジェクト
    • Target Layer:Enemyを指定
    • シーンで表示を確認したい場合はScanner Gizmosにチェックを入れる

ターゲット側

私の方では3つのターゲットを用意しました。

  • Cubeを作成
    • 必須なのはLayerをEnemyに変更
    • お好みで色を変更します

動かしてみて確認

私の方では各targetを検出したらテキストに表示させています。FirstとNearの違いは次の様なもの

  • First
    • 最初に発見したもの
    • これは距離に依存しないため、一番最初に目をつけた相手を追いかけ続けます
  • Near
    • いくつか検出範囲に存在する場合、一番近い相手を指します
    • 位置によって更新されるので、最も近いターゲットになにかしたい場合に有効

邪魔な壁を配置する

実質これが一番大事な要素。ここまで準備できていれば、あとはターゲットとの間に邪魔な壁を用意して機能の確認を行いましょう。

設定を追加する

  • レイヤーの追加
    • Enemyの様に、邪魔な壁に相当するLayerを追加します
    • 今回はObstacleレイヤーを追加します
  • 視界を遮るBoxを追加
    • 3D Object>Cubeを追加
    • レイヤーをObstacleに変更
  • 位置を調整
    • Searcherとターゲットの間に壁を移動させる
  • Searcher側の設定を変更する
    • Obstacle Layer:Obstacleを追加

動かしてみる

先程の処理と合わせることで、衝立の壁が間に入ると検出が出来なくなることを確認出来ます。サイコー

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

コメント

コメント一覧 (1件)

コメントする

目次