【Unity】Loypolyの魚AIを自由に泳がす~A* Pathfinding の使い方備忘録~

こんばんわ。VyseArtのトナカイです。

( ようやくはてな記法について理解しました笑)

先日unityのアセットストアで最大70%OFFの割引セールをやっていまして、目をつけていたアセットA* PathFinding Proが半額だったので購入しました^^

 

それを使うと簡単に人工知能AIの動きが作れるということだったので、実際に作ってみました。

 

タイトルの通り現在ローポリで探索ゲームを作成中です。

 

https://youtu.be/X4dhlfHO0CU

 

UnityはNavmeshAgentという機能があって、これも人工知能に関するものなのですが、私にはどうもうまく扱えず(何かが引っかかって動かなくなってしまったり)、人工知能は一端あきらめていました。

 

このアセットは何とか動画のような形にできました。

比較的簡単に人工知能を実装できたと思います^^

 

今回はその備忘録です。


f:id:odekakeneko:20191207223835p:plain
A*オブジェクトを作成

A* Pathfinding Pro(有料です!)をアセットストアからインポートしたらヒエラルキーに「A*」という 空のゲームオブジェクトを作ります(画像の他のオブジェクトはここでは無視してください)。そして、、


f:id:odekakeneko:20191207225001p:plain
A*オブジェクトのインスペクタ

A*のインスペクタはこうなっています。AddComponentで「Pathfinder」と検索してアタッチすると、A Star Pathというスクリプトが付きます。

 

Graphの名前はたしか「Grid Graph」だったのですが「Water Graph」に変えました。

こちら私がすごいなと感じたのは、このGraph、複数で作成ができてGraphごとに取得ができるようです。

 

それの何がすごいかというと、Water Graph内だけで動き回ってほしいAIにはそのグラフの範囲だけ設定すればよいのです。

 

NavGraph gg;

gg = GetComponent<Astarpath>.graphs[0];

グリッドグラフの取得の方法…添え字を使います。

 

AIとなるオブジェクトには、SeekerとAILerpというスクリプトをつけます。
Seekerスクリプトは必須で消せません。AILerpはSeekerに依存していると表示が出ました。

(ここら辺私なりに色々彷徨いました。A*Pathfindingが壊れているのかとまで思ったのですが、自分のコードと向き合って直したところ、動画のようなものが作れました)

 

AIとなるオブジェクトにつけたスクリプトFish.csは下記のようになります。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Pathfinding;

public class Fish : Item
{
    NavGraph gg;
    float radius = 20f;

    IAstarAI ai;

    void Start(){
        //グラフを取得する
        gg = GameObject.Find("A*").GetComponent<AstarPath>().graphs[0];    //WaterGraphを取得
        ai = Getcomponent<IAstarAI>();
    }

    void Update(){
        Swim();
    }

    private void Swim() 
    {
        if(!ai.pathPending && ( ai.reachedDestination || !ai.hasPath))
        {
            ai.destination = gg.GetNearest(PickRandomPoint()).clampedPosition;
            ai.SearchPath();
        }
    }

    Vector3 PickRandomPoint()
    {
        var point = Random.insideUnitSphere * radius;

        point.y = 0;
        point += ai.position;
        return point;
    }
}

Fish.csですが、動画の動きとは少しスクリプトを割愛をしてあります(例えば最初は泳いでなくて、くるくる回っているところとか、フラグを使ってifで条件分岐するとできますね)。

私的にポイントは、関数Swim内の
ai.destination = gg.GetNearest(PickRandomPoint()).clampedPosition;
にあると思っています。
ランダムなポイントをとってくるのはA* Pathfindingを使わなくてもコードをかけるのですが、その近くのノードをとってきてVector3型で返すというのがこのアセットを使ってできることだと思います。

ほかにも、A*Pathfindingは動的にBake(このアセットではScan)ができるということで、それに関してはまだ勉強中というか効果もわかっていないところなのですが、それらもできたら掲載したいと思います。

以上。