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

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

ただいまの
回答率

90.60%

  • C#

    6859questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

  • Unity3D

    1247questions

    Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

巡回する敵AIについて

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 2,300

TKM_waiwai

score 10

Unityにて3Dのゲームを作っています。
Playerから逃げる敵AIを作っており、ある程度近づくと逃げていきある程度距離が出来るとランダムにウロウロ巡回させるようにさせたいのですが、ランダムにウロウロしてくれずPlayerと離れている時はずっとその場で止まったままになってしまいます。
近づくと逃げてはくれますが。。。

現段階でさせようとしているのは敵に目的地を指定させており、その目的地に向かって進むようにし、その目的地に近づくと別の目的地がランダムで決められ今度はそこへ敵が向かうという流れを使ってランダムでウロウロ巡回させようとしています。
Playerとの距離が近くなるとMove関数が呼ばれ逃げます。
目的地との距離が近くなるとDoPatrol関数が呼ばれ次の目的地がランダムで呼ばれるというしくみになっています。
ですが、なぜか敵は止まったままになってしまいます。
恐らく目的地という物が存在出来ていないのかなと思うのですが、解決出来ませんでした。
どうしたらランダムで巡回してくれるでしょうか。
現状のEnemyソースに間違いや足りない箇所などがあればアドバイスよろしくお願い致します。

【巡回AIの参考URL】

http://tongullman.blogspot.jp/2015/11/unity-navmesh-ai.html

【編集】
ソースを一部書き直しました。
参考にしたURLを貼りました。

質問の仕方が下手で申し訳ありません。

using UnityEngine;
using System.Collections;

public class Enemy : MonoBehaviour
{
    public float m_speed = 2.0f;  //移動速度
    public float m_rotation;        //回転速度
    public Transform m_target;  //追いかけるオブジェクト
    NavMeshAgent m_agent;

    private static Vector3 m_position;
    private float m_patroldistance;
    private float m_targetdistance;

    void Awake()
    {
        m_agent = GetComponent<NavMeshAgent>();
    }

    void Start()
    {
        DoPatrol();
    }

    void Update()
    {   
        m_patroldistance = Vector3.Distance(this.m_agent.transform.position,m_position);
        m_targetdistance = Vector3.Distance(this.m_agent.transform.position, m_target.transform.position);

        //Playerとの距離が30f以下になると逃げる
        if(m_targetdistance <= 30f)
        {
            Move();
        }else if(m_patroldistance < 15f)
        {
            DoPatrol();
        }else
        {
            m_agent.SetDestination(m_position);
        }
    }

    void Move()
    {
        //ターゲットの方向を求める
        Vector3 vec = transform.position - m_target.position;    //m_target.position - transform.position;
        //ターゲットの方に向く
        transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(new Vector3(vec.x, 0, vec.z)), m_rotation);
        //進む方へ移動
        transform.Translate(Vector3.forward * m_speed);
    }

    public void DoPatrol()
    {
        var x = Random.Range(-50.0f, 50.0f);
        var z = Random.Range(-50.0f, 50.0f);
        m_position = new Vector3(x, 0, z);
        m_agent.SetDestination(m_position);
    }
}
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • ozwk

    2017/01/05 08:25

    m_positionはなぜstaticにしているんですか?

    キャンセル

  • TKM_waiwai

    2017/01/06 00:58

    質問の場所にも書きましたが、「http://tongullman.blogspot.jp/2015/11/unity-navmesh-ai.html」の巡回AIを参考にして作りました。

    キャンセル

回答 3

checkベストアンサー

+1

3Dゲームプログラミングは素人の回答ですみません、私はUnityもNavMeshAgentも触ったこともありません。

まず、この全体のソースの中で「NPCが進む」という行為はSetDestinationだけでできているでしょうか?
サンプルサイトの通りだと、SetDestinationしただけでNPCは移動しなければならないと思いますが、TKM_waiwaiさんのソースだとMoveではSetDestinationを呼んでおらず、Positionを適宜手動で更新しているように見えます。

    void Move()
    {
        // この中でSetDestinationが呼ばれていないのはなぜですか?
        // (逃げる先(目的地)の算出方法が分からない?)
        // また、MonoBehaviorのtransformにアクセスしており
        // ここではm_agentの状態が一切更新されていない
        Vector3 vec = transform.position - m_target.position;m.position;
        transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(new Vector3(vec.x, 0, vec.z)), m_rotation);
        transform.Translate(Vector3.forward * m_speed);
    }


ここから、m_agent.SetDestinationのみで移動できるように設定されていないのではと疑いを持ちました。
(Velocityとかデフォルトで設定されているものなのかもしれませんが…)

適当なポジションをインスペクタから設定してSetDestinationをコールするものを作り、それだけで移動する状態かどうかまず確認してみてはどうでしょうか。

また、Update内で毎回SetDestinationする必要性もないはずです。
SetDestinationは目的値の設定で、目的値に移動する前に経路探索の計算が必要なはずで、再設定が無視される作りなのかもしれませんがサンプルサイトと比較すると無駄な呼び出しのように思われます。
Unityのサイトには複数回同じ目的地の設定を行うことについては書かれておらず、呼び出しから数フレーム後まで経路探索が有効とならない場合があるとだけ書いてあることから、この呼び出しは不健全に思えます。

    void Update()
    {   
        m_patroldistance = Vector3.Distance(this.m_agent.transform.position,m_position);
        m_targetdistance = Vector3.Distance(this.m_agent.transform.position, m_target.transform.position);

        if(m_targetdistance <= 30f)
        {
            // この中でSetDestinationが呼ばれていないのはなぜですか?
            Move();
        }else if(m_patroldistance < 15f)
        {
            DoPatrol();
        }
        /* サンプルサイト通りなら不要では?
           距離が再び30f以上になると元のパトロール先に戻っていこうとする、ということですか?
           その場合、現在どのような移動を行っているかをフラグとして持ち
           「逃げる」「パトロールする」というステートが切り替えられた時に
           SetDestinationを更新するようにした方が丁寧です
        else
        {
            m_agent.SetDestination(m_position);
        }
        */
    }

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

0

Update の中ですが、if の else がないせいじゃないでしょうか?

        //Playerとの距離が30f以下になると逃げる
        if(プレーヤーとの距離 <= 30f)
        {
            プレーヤーから逃げる();
        }else if(目的地との距離 < 15f)
        {
            次の目的地を選ぶ();
        }else
        {
            目的地に移動(); // ← これがない
        }


蛇足ですが、c# の場合、関数名とか日本語にすると読みやすいですよ。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/01/05 01:31

    アドバイスありがとうございます!
    やってみます!

    キャンセル

  • 2017/01/05 01:55

    DoPatrol関数の中に入れている
    「m_agent.SetDestination(m_position);」でその目的地へ移動しているはずなので、
    else文に同じ文を追加したのですがやっぱりダメでした。。。

    キャンセル

  • 2017/01/05 08:49

    毎回 DoPatrol を呼んだら、毎回目的地がリセットされませんか?

    キャンセル

  • 2017/01/06 01:01

    毎回目的地がリセットされて良いはずなんです、、、

    キャンセル

  • 2017/01/06 08:40

    目的地に到着するごとに毎回でなく、毎フレームごとになってしまいますので、意図している動作と異なる気がします。

    キャンセル

  • 2017/01/06 09:24

    なるほど、確かにそうですね。

    どの辺で毎回DoPatrolを呼んできてしまっていますか?

    キャンセル

  • 2017/01/06 15:22

    if( 自分に近かった ) 逃げる。
    elseif( 目的に近かったら ) 次の目的地設定
    else 現在の目的地に移動
    となるべきかと思います。最後の else の際にも SetDestination にしてしまうと、目的地から遠くても次の目的地の設定になってしまうかと。

    キャンセル

0

2番めのelse ifって、実質到達不可になってますね。
最初のif文では30以下と記述していますが、15以下の状態は30以下の状態でもあるため、たとえ15以下であっても30以下のほうが実行されてしまっています。

なので、if文の記述を逆にしたら動きませんか?

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/01/04 16:54

    よく見ると変数名違うんですよ

    キャンセル

  • 2017/01/04 16:57

    お。ほんとだw コメントありがとうございます。

    キャンセル

  • 2017/01/05 08:49

    私も、その罠にはまりかけたんで、日本語記述をすすめてしまいました、、、

    キャンセル

  • 2017/01/05 08:54 編集

    patrolToAgentDistance
    targetToAgentDistance

    にすれば1文字目が違うからぱっと見でもわかりやすいですかね
    それでもTo以降が長い上に同じだから見間違えやすいんですが

    キャンセル

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

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

関連した質問

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

  • C#

    6859questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

  • Unity3D

    1247questions

    Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。