質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.61%

【Unity2D】プレイヤーを追いかける敵を作りたい!【NavMeshAjent】

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,759

score 0

1/7 : 追記しました。
1/9 : 自己解決しました。

初めに

Unity2Dで、プレイヤーを追いかける敵キャラを作りたいと考え、NavMeshAgentを使ってみました。
しかし、参考にするサイトがいずれも3Dの場合で、私の環境とは異なるので、なかなかうまくいかなかったのですが、こちらの2019-2Dのコードを見つけました。(以下、☆とする)
以下、私が実行したことを列挙します。
また、今回は「宇宙飛行士(Player)にインベーダー(AlienSpaceship)が追いかけてくる」という状況をつくろうとしています。

1.タイルマップを設置
:今回はテストですので、障害物はないマップを作りました

2.GridごとTilemapを静的に変更

3.GridのTilemapにTilemapCollider2Dと、☆からDLしたNavMeshSourceTag2Dを付与

4.空のGameObjctを作成し、それに☆からDLしたNavMeshBuider2Dを付与。

5.値をなにもいじらずにそこのBakeをクリック。
:なぜかコンソールにエラーが残っているとうまくBakeできなかったので、コンソールをリセットしました。

6.ナビゲーションウインドウを開くと、マップ全体が青がかっていました。
:これでメッシュは正常に生成されていると思います。

イメージ説明

7.インベーダー(AlienSpaceship)に次のスクリプトを付与

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

public class Alien_move: MonoBehaviour
{
  //追いかける目標、今回はPlayer。
    public GameObject target;

  //毎フレームルートを考えることで、無駄なく動かせるようにする
    void Update()
    {
      //agentを作成
            NavMeshAgent agent = GetComponent<NavMeshAgent>();
      //目標をtargetに設定
            agent.destination = target.transform.position;

    }
}

8.インベーダーのインスペクター画面で、targetにPlayerをアタッチし、NavMeshAgentを付与

9.ゲームを起動

![イメージ説明](c378e93e9739cae842da08ecbcd83eb6.png)

10.警告とエラーが多数が吐かれ、インベーダーが動かないので手動で停止
警告は

Failed to create agent because there is no valid NavMesh

エラーは

"SetDestination" can only be called on an active agent that has been placed on a NavMesh.
UnityEngine.AI.NavMeshAgent:set_destination(Vector3)
Alien_move:Update() (at Assets/Scenes/Scripts/Enemy/Alien_move.cs:17)

問題点:

警告の内容から、そもそもNavMeshが生成されていないようです。しかし、6の作業でNavMeshが生成されていることが確認できているので、矛盾しています。
メッシュはできていることが確認出来ていて、かつインベーダーにも動けるようなコードを与えていることから、インベーダーの方ができているメッシュを認識できていないと考えます。
また、調べてもどの記事も3Dで解説されている上に、☆のスクリプトを用いている記事が少ない。

解決するためにやるべきだと考えていること:

もしかしたら、何かレイヤーの違いのようなもので、情報共有ができていないのではないかと考えます。ですので、そのねじれを解くことが問題解決のカギになると考えています。

==========

試した解決策:

・TilemapCllider2Dの「トリガーにする」と「エフェクターで使用」にチェック
・NavMeshSourceTag2DのAreaの値を変更
・インベイダーのUpdate内の作業を、開始から10秒後に動作するように変更
:警告はすぐ出たが、10秒後にエラーを吐き始めた
・エージェントタイプをデフォルトであった、Humanoidから、自作の適当なエージェントに変更。
・デフォルトであった、Humanoidの値を大きくしたり、小さくしたりした

いずれも、同じように警告とエラーを吐いて終わりました。

補足:

ナビゲーションウインドウのBakeを押しても反応しませんでした。

質問内容:

まずは、私のエラーへの見解があっているかどうか。つぎに、やるべきことがあっているかどうか。 最後に、どうやってやるべきことを実行するか。 ついでに、もし普通のNavMeshを2D環境で使う方法があるならそれを教えていただけると嬉しいです。

長文失礼いたしました。
よろしくお願いしたします。

追記

返答をいただいた方から、ご指摘を頂きました。
作業4で作ったGameObjectのNavMeshBuilder2DのBakeOnEnableにチェックを入れていませんでした。
また、マップが正常に生成されているかどうかを見るためによりデコボコしたマップでメッシュを生成したときの画像を添付します。
イメージ説明

また、この変更により新しい警告が出てきたので、追記させていただきます。

Failed to create agent because it is not close enough to the NavMesh
UnityEngine.AI.NavMesh:AddNavMeshData(NavMeshData)
NavMeshBuilder2D:RebuildNavmesh(Boolean) (at Assets/NavMeshComponents-2019.3-2D/Assets/NavMeshComponents/Scripts/NavMeshBuilder2D.cs:88)
NavMeshBuilder2D:OnEnable() (at Assets/NavMeshComponents-2019.3-2D/Assets/NavMeshComponents/Scripts/NavMeshBuilder2D.cs:34)

やはり推察通り、agentがNavmeshを正常に確認できていないようです。
このエラーを調べたところ、次の解決策でうまくいったという方がいたので、試してみました。
1.ベースオフセットの値を変える
2.NavMeshBuilder2Dの更新方法を手動から更新にする
3.NavMeshSurfaceを追加し、そこでBakeする
これをした後に実行してみると、以下のエラーが増えました。

ArgumentException: The Object you want to instantiate is null.
UnityEngine.Object.CheckNullArgument (System.Object arg, System.String message) (at <480508088aee40cab70818ff164a29d5>:0)
UnityEngine.Object.Instantiate[T] (T original) (at <480508088aee40cab70818ff164a29d5>:0)
Alien_move.Start () (at Assets/Scenes/Scripts/Enemy/Alien_move.cs:15)

また、TilemapにNavMeshSurfaceを追加し、そこでBakeすると治った方がいるようなので試してみましたが、結果は変わりませんでした。
というのも、その方はAgentTypeが既定?のHumanoid以外で実行されており、この方法はそれを解消する方法らしいです。私はそのままHumanoidを使っているので、効果はないみたいです。

また、以下のコードを追記することで治った方がいるようです。

GameObject _prefab = (GameObject)Resources.Load ("Characters/" + _type);
GameObject _character = Instantiate (_prefab);
_character.GetComponent<NavMeshAgent> ().enabled = true;


これを私のAlien_move(作業7で追加したコード)のStart()に入れたところ、_typeが未定義ということで弾かれてしまいました。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • sakura_hana

    2021/01/05 12:03

    「なぜかコンソールにエラーが残っているとうまくBakeできなかったので、コンソールをリセットしました。」の部分ですが、これはエラー表示を消しただけでエラーが解決したわけではありません。
    なので残ったエラーが原因でBakeできていない可能性があります。(手順6で出来ているように見えても「ナビメッシュは生成されているが、そのメッシュが正常ではない」かもしれません)
    Bake前のエラー内容を確認してください。

    キャンセル

  • Uch_

    2021/01/05 16:21

    回答ありがとうございます。

    説明不足で申し訳ありません。
    「なぜかコンソールにエラーが残っているとうまくBakeできなかったので、コンソールをリセットしました。」の部分でのエラーというのは、本文の手順10で出た、
    "SetDestination" can only be called on an active agent that has been placed on a NavMesh.
    UnityEngine.AI.NavMeshAgent:set_destination(Vector3)
    Alien_move:Update() (at Assets/Scenes/Scripts/Enemy/Alien_move.cs:17)
    のエラーです。前回実行してみたときのものが残っていたのです。

    確かに、ナビメッシュは生成されてはいるけど、そのメッシュが異常という可能性はあると思います。
    しかし、bake前、bake後、実行前のコンソールにはいずれも一切警告エラーは出ていないので、わかりかねるんです。

    また自分で調べたところ、3Dの環境ではAgentで動かすオブジェクトがメッシュの上にいないと動かないようです。私の環境は2Dですので、そもそも上と下みたいな関係はないはずなのですが、もしかしたらと思い立ったので書かせていただきます。それは関係ないでしょうか?

    キャンセル

  • sakura_hana

    2021/01/06 09:48

    エラーについては了解です。
    実際に試していないので間違っていたらすみませんが、以下のページにある「実際に使う場合はBakeOnEnableにチェックを入れる必要があります。」の部分は設定できていますか?
    https://watablog.tech/2020/09/29/post-1886/
    あとマップの形を変えたり穴を空けたりしてBakeが正しく出来ていそうか確認出来るようにしてみてください。
    またプレイヤーの位置(座標)が本当にマップ上かを確認してください。(知らない内にZ軸がとても離れている等の可能性があります)

    キャンセル

  • Uch_

    2021/01/07 11:47

    返答ありがとうございます。

    BakeOnEnableはチェックしていませんでした。ありがとうございます。
    穴をあけたり、削れたマップを作製し、Bakeしたところ、正常にデコボコなメッシュができました。なので、メッシュは正常に作成できているようです。追記部分に画像を上げてあります。
    テストで実行している間、Tilemap、Grid、Player、AlienSpaseshipのZ軸を監視しましたが、いずれも0で変化しませんでした。
    新たな警告が出たので、追記部分を確認してください。

    よろしくお願いします。

    キャンセル

回答 1

check解決した方法

0

自己解決

回答してくれた方には申し訳ないのですが、そもそもやり方が違いました。
これから見てくれる方のために、うまくいったやり方を残しておきます。

1.アドオンをDL、解凍、設置

https://github.com/h8man/NavMeshPlus
↑のURLのGitLabのページから入手できるアドオンをDL、解凍、Assetの欄に置いてください。
本文の☆のデータが残っていると、データが競合して動かなくなるので、消去してください。

2.マップを設置

この工程が少々面倒です。
まず、地面、歩ける場所となる部分をTilemapを用いて作成します。
もし、障害物、壁などを追加したい場合は、二枚目のTilemapを用いてそれらを設置してください。(タイルマップごとで判定してNavMeshを作っているようなので、見た目は壁でも全部歩けるようになってしまします。)
ここでは、地面となるTilemapをGroud、壁のみを描いたTilemapをWallと呼びます。

3.NavMeshModifireを各Tilemapにアタッチ

作業1でインストールしたアドオンの中にNavMeshModifireというナニか(勉強不足でごめんなさい。)があるので、それを各Tilemapにアタッチします。コンポーネントの追加画面で検索をかければ出てきます。
ここで、いずれもOverrideAreaにチェックをいれます。すると、AreaTypeという欄が増えるので、歩け所が描かれているマップにはWalkable、歩けない場所、壁や障害物が設置されてるマップにはNotWalkableを設定します。今回はGroundをWalkable、WallをNotWalkableに設定します。

4.空のオブジェクトを作成

5.作業4で作ったオブジェクトにNavMeshSurface2dをアタッチ

NavMeshSurfaceとは別物なので注意です。NavMeshModifire同様、検索をかければすぐ出てきます。
まず要素の下の方にある、RotateSurfaceToXYをクリックします。すると、オブジェクトのTransform欄の回転の値が「-90.00001」になることを確認してください。
つぎにOverrideByGridと、CompressBoundsにチェックを入れてください。
最後にBakeを押すと、メッシュが生成されます。
ちゃんと、歩ける場所と壁が分かれてメッシュが生成されているか確認してください。
メッシュは青っぽいアミアミになってるのでわかりやすいと思います。
また、メッシュはNavMeshSurface2dがアタッチされているオブジェクトを選択しているときと、ナビゲーションウインドウを開いているときしか見えないので、注意してください。

6.動かすオブジェクト、追われるオブジェクトを作成し、タグをつける

マップの作製より先にやってもいいですが、今回は説明のために順番を付けています。
今回は追われるオブジェクトをPlayer、Playerを追うオブジェクトをAlienとします。
それらにタグを付けます。(付けなくても恐らく動きはしますが、今回私がうまくいった方法を説明しています。)
タグ自体は何でもいいですが、私はPlayerにPlayer、AlienにEnemyを付けました。

7.オブジェクトを動かすためのスクリプト作成

今回私のはAlien_moveにしました。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

public class Alien_move : MonoBehaviour
{

    [SerializeField] Transform target;
    private NavMeshAgent agent;

    void Start()
    {
        target = GameObject.FindGameObjectWithTag("Player").transform;
        agent = GetComponent<NavMeshAgent>();
        agent.updateRotation = false;
        agent.updateUpAxis = false;
    }

    void Update()
    {
        agent.SetDestination(target.position);

    }
}

Playerのところは、付けたタグに応じて変更してください。
書けたらこのスクリプトを保存、動かしたいオブジェクトにアタッチしてください。今回はAlienにアタッチします。
また、これのインスペクター画面のTargetに追いかけたいオブジェクトを入れます。
今回はPlayerをいれます。

8.動かしたいオブジェクトにNavMeshAgentをアタッチ

ここは何もいじる必要はありません。
でも、ここの値が動くための速度だったりするので、いじりたい人は勝手にどうぞ。

9.テスト

実際に再生して、動かしてみましょう。
ちゃんと動くことが確認できると思います。
今回は割愛しましたが、Playerを動けるようにすると、ちゃんと動いた先に動くようになります。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.61%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る