2021年8月5日木曜日

#8 建物を設置、作成してみる

  こんにちは!ぴちおです。


RTSといえば、

施設の建設は必須。


メニューで建物選択状態にする

マウス上に建物オブジェクトを追従させる

親オブジェクトの近くのみ設置可能にする。

他のオブジェクトがある場合は設置不可にする。

クリックした場所にオブジェクトを表示。


実装したい内容は上記の通り


まずは

床と親オブジェクト、子オブジェクトとゲームマネージャーを設置

plane

名前:Ground

scale:x5,y1,z5

shpere

名前:HomeBase

scale:x2,y2,z2


cylinder

名前:Institution

Prefabフォルダを作成し、そこにドラッグでPrefab化する。

スクリーン上のは削除

new script「InstitutionController」をアタッチ


Empty Object

new script「GameController」をアタッチ


raycastで設置位置を確定するので

余計なのにrayが当たらないようにちょっと設定を加える


Groundはrayを必ず当てたいので

layerを1つ追加、「Ground」

でそれをセット


今回のテストではHomeBaseはray当てたくないので

Ignore RayCastにlayerを設定

Institutionは

まずはrayを当てたくないので

Ignore RayCastにlayerを設定

また、後でクリックしたときに区別したいので

tagにBuildingを追加して、それをセット


続いて、スクリプト

InstitutionController

これは今回のテストでは、設置したものがそれぞれ、どんなステータスかと区別するだけなので、

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


public class InstitutionController : MonoBehaviour
{
public string _Name;

}

これだけ


GameControllerは

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameController : MonoBehaviour
{
private bool bMoodFlag = false;
public GameObject institutionObject;
Vector3 mouse;
Vector3 mouse3d;
public GameObject insobj;
InstitutionController iScript;
void Update()
{
if (bMoodFlag)
{
//建物設置モード
}
else
{
mouse = Input.mousePosition;
mouse.z = 10f;
mouse3d = Camera.main.ScreenToWorldPoint(mouse);
mouse3d.y = 1f;
if(Input.GetKeyUp (KeyCode.H))
{
bMoodFlag=true;
insobj = Instantiate(institutionObject,mouse3d,Quaternion.identity);
iScript = insobj.GetComponent<InstitutionController>();
iScript._Name = "House";
}
if(Input.GetKeyUp (KeyCode.B))
{
bMoodFlag=true;
insobj = Instantiate(institutionObject,mouse3d,Quaternion.identity);
iScript = insobj.GetComponent<InstitutionController>();
iScript._Name = "Barracks";
}
}
}
}

まずは、建築モードに入るところ、

建築モードフラグBmodeFlagのT/Fでアクションを変更する。

建築モードフラグFalse時に

キーHもしくはキーBを押すと

Prefabからinstitutionを生成する

また、そのinstitutionのスクリプトの_Nameにそれぞれのパラメータをセットする。

で、建築モードフラグをTrueにする


続いて、建築モードキャンセルアクション

void Update()
{
if (bMoodFlag)
{
//キャンセル
if(Input.GetKeyUp (KeyCode.Escape))
{
bMoodFlag=false;
insobj.SetActive (false);
}
}
else
{

建築モードTrue中にEscキーを押すとキャンセルになる。

キャンセルとは建築モードフラグをFalseにして、Prefabから作成したオブジェクトを非表示にする

※テストなので作り込まないが、Prefabから作成するとき、この非表示のオブジェクトが存在すれば、新規つくらず、そのオブジェクトを表示するようにする。


ここからが苦戦したところ、

1つ目がHome Baseから一定の距離にしかinstitutionを追従しないようにする

一定の距離離れた場合、ギリギリの距離で追いかける

if (bMoodFlag)
{
//建物設置モード
//マウス移動
Vector2 touchScreenPosition = Input.mousePosition;
touchPointToRay = gameCamera.ScreenPointToRay( touchScreenPosition );
touchScreenPosition.x = Mathf.Clamp( touchScreenPosition.x, 0.0f, Screen.width );
touchScreenPosition.y = Mathf.Clamp( touchScreenPosition.y, 0.0f, Screen.height );

Vector3 pos = PreObject.transform.position;

RaycastHit hitInfo = new RaycastHit();

if( Physics.Raycast( touchPointToRay, out hitInfo ,Mathf.Infinity,LayerMask) )
{
pos = hitInfo.point;
insobj.transform.position = pos;

まずは、距離関係なく、また、HomeBaseに被りながらもおいかけるようにする。

仕組みとしては

カメラからrayを飛ばしてGround上の座標を取得

あ、LayerMaskはPublicにして、インスペクターからGroundを設定しておきます。


そうすると、他のオブジェクトに当たらず床のカメラからみてクリックした座標がGetできます。

それで、institutionの位置を絶えず移動させれた追従します。

if( Physics.Raycast( touchPointToRay, out hitInfo ,Mathf.Infinity,LayerMask) )
{
if (Vector3.Distance(PreObject.transform.position,hitInfo.point)<InstallableDistance && Vector3.Distance(PreObject.transform.position,hitInfo.point)>1.2)
{
pos = hitInfo.point;
}
else
{
Vector3 dt = hitInfo.point - PreObject.transform.position;
float radians = Mathf.Atan2(dt.z,-dt.x);
float angle = radians * Mathf.Rad2Deg-90;
float radian = angle * Mathf.Deg2Rad;
if(Vector3.Distance(PreObject.transform.position,hitInfo.point)>=InstallableDistance)
{
pos.z = Mathf.Cos(radian) * InstallableDistance + PreObject.transform.position.z;
pos.x = Mathf.Sin(radian) * InstallableDistance + PreObject.transform.position.x;
}
else if(Vector3.Distance(PreObject.transform.position,hitInfo.point)<=1.2)
{
pos.z = Mathf.Cos(radian) * 1.4f + PreObject.transform.position.z;
pos.x = Mathf.Sin(radian) * 1.4f + PreObject.transform.position.x;
}
}
insobj.transform.position = pos;

続いて、一定距離以上離れない、HomeBaseには乗らないようにします。

マウスの位置とHomeBaseの距離を計測します。

if (Vector3.Distance(PreObject.transform.position,hitInfo.point)<InstallableDistance && Vector3.Distance(PreObject.transform.position,hitInfo.point)>1.2)

InstallableDistanceこれが設置可能距離

HomeBaseの距離は1.2直打ちです。ほんとはオブジェクトの半径とかやるんだろうけどTestなので・・

この条件にある場合だけ、移動にすれば、一定範囲のみ移動します。

ただ、その条件に外れた場合、そこでオブジェクトが止まってしまうので範囲内ギリギリで移動するようにします。

仕組みは

HomeBaseとマウスの座標を元に角度を取得

あとは、SinとかCosとか使って座標を求めます。

私は学がないので、ここら辺よくわかりません。



最後に

クリックした場所に何もなければ

施設を設置する。


何もないかどうかの判定は

//クリック時
if (Input.GetMouseButtonUp(0))
{
//他の建物がないか確認
RaycastHit hit;
// SphereCastのレイを飛ばしターゲットと接触しているか判定
if(Physics.SphereCast(touchPointToRay, 0.5f, out hit, 100f)) {
if (hit.transform.name == "Ground")
{
insobj.layer = 0;
bMoodFlag=false;
}
else{Debug.Log("設置できません");}
}
else{bMoodFlag=false;}
}

マウスクリックしたときに

またrayを飛ばします。

今度はsphercastという点ではなく、球体のrayを飛ばす感じです。

カメラからマウスの位置に半径0.5fの球体を飛ばしてヒットするか確認します。

ヒットした場合は、設置できない

他のものにぶつからずGroundがヒットした場合は設置可能として

オブジェクトを設置します。

設置する際に、そのオブジェクトが次に、この置けるか判定の時にちゃんとrayにぶつかるようにlayerをデフォルト(0)に変更

建設モードをfalseにセットで完了です。


と、思ったら、

これだとマウスが設置可能範囲内の場合はいいのですが、

上で考慮した、設置可能範囲外の場合、ガスガス設置できてしまう。

ので、ちょっと修正

Vector3 ispos = insobj.transform.position;
ispos.y += 10f;
if(Physics.SphereCast(ispos,0.5f,Vector3.down,out hit,100f)){

上で考慮した範囲外、オブジェクトが表示されている場所からレイを落としてみる

一応、10fほど高いところから真下にレイ発射に変更。


本当はRTSであれば

いきなり設置ではなく、建設中の状態にして、

その待ち時間完了後、設置完了なんでしょうけど、

それは別の記事で、待ち時間を検討してみます。



上で省略した変数も含めて全部はこうなりました。

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

public class GameController : MonoBehaviour
{
private float clickTime = 0;
private bool clickFlg = false;
private GameObject mainCamera;
private Vector3 dragStartPosision;
private float mouseDownTime = 0;
private bool bMoodFlag = false;
public GameObject institutionObject;
Vector3 mouse;
Vector3 mouse3d;
public GameObject insobj;
public GameObject PreObject;
public LayerMask LayerMask;
public float InstallableDistance=2;
private Camera gameCamera;
private Ray touchPointToRay;
InstitutionController iScript;
void Start()
{
gameCamera = Camera.main;
mainCamera = gameCamera.gameObject;
}
void Update()
{
if (bMoodFlag)
{
//建物設置モード
//マウス移動
Vector2 touchScreenPosition = Input.mousePosition;
touchPointToRay = gameCamera.ScreenPointToRay( touchScreenPosition );
touchScreenPosition.x = Mathf.Clamp( touchScreenPosition.x, 0.0f, Screen.width );
touchScreenPosition.y = Mathf.Clamp( touchScreenPosition.y, 0.0f, Screen.height );

Vector3 pos = PreObject.transform.position;
RaycastHit hitInfo = new RaycastHit();
if( Physics.Raycast( touchPointToRay, out hitInfo ,Mathf.Infinity,LayerMask) )
{
if (Vector3.Distance(PreObject.transform.position,hitInfo.point)<InstallableDistance && Vector3.Distance(PreObject.transform.position,hitInfo.point)>1.2)
{
pos = hitInfo.point;
}
else
{
Vector3 dt = hitInfo.point - PreObject.transform.position;
float radians = Mathf.Atan2(dt.z,-dt.x);
float angle = radians * Mathf.Rad2Deg-90;
float radian = angle * Mathf.Deg2Rad;
if(Vector3.Distance(PreObject.transform.position,hitInfo.point)>=InstallableDistance)
{
pos.z = Mathf.Cos(radian) * InstallableDistance + PreObject.transform.position.z;
pos.x = Mathf.Sin(radian) * InstallableDistance + PreObject.transform.position.x;
}
else if(Vector3.Distance(PreObject.transform.position,hitInfo.point)<=1.2)
{
pos.z = Mathf.Cos(radian) * 1.4f + PreObject.transform.position.z;
pos.x = Mathf.Sin(radian) * 1.4f + PreObject.transform.position.x;
}
}
insobj.transform.position = pos;
//クリック時
if (Input.GetMouseButtonUp(0))
{
//他の建物がないか確認
RaycastHit hit;
// SphereCastのレイを飛ばしターゲットと接触しているか判定
if(Physics.SphereCast(touchPointToRay, 0.5f, out hit, 100f)) {
if (hit.transform.name == "Ground")
{
insobj.layer = 0;
bMoodFlag=false;
}
else{Debug.Log("設置できません");}
}
else{bMoodFlag=false;}
}
//キャンセル
if(Input.GetKeyUp (KeyCode.Escape))
{
bMoodFlag=false;
insobj.SetActive (false);
}
}
else
{
mouse = Input.mousePosition;
mouse.z = 10f;
mouse3d = Camera.main.ScreenToWorldPoint(mouse);
mouse3d.y = 1f;
if(Input.GetKeyUp (KeyCode.H))
{
bMoodFlag=true;
insobj = Instantiate(institutionObject,mouse3d,Quaternion.identity);
iScript = insobj.GetComponent<InstitutionController>();
iScript._Name = "House";
}
if(Input.GetKeyUp (KeyCode.B))
{
bMoodFlag=true;
insobj = Instantiate(institutionObject,mouse3d,Quaternion.identity);
iScript = insobj.GetComponent<InstitutionController>();
iScript._Name = "Barracks";
}
}
}
}


参考にさせていただいたサイト:

https://www.urablog.xyz/entry/2017/04/28/213010

2021年7月29日木曜日

#6 ピンチアウトピンチイン、スクロールとかの実装


画面を広くすると

ドラッグしてがめんずらしたり、

スクロールボタンで画面を拡大縮小したいしたくなります。


Unityでダブルクリックとかドラッグとか

なんか関数があるのかと思ったら特にないみたいなので

自分で作成


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

public class MouseController : MonoBehaviour
{
private float clickTime = 0;
private bool clickFlg = false;
private GameObject mainCamera;
private Vector3 dragStartPosision;
private float mouseDownTime = 0;

void Start()
{
mainCamera = Camera.main.gameObject;
}
void Update()
{
if (Input.GetMouseButtonDown(0) && !clickFlg)//マウスを押した時
{
mouseDownTime=0;//長押しチェック用カウント初期化
dragStartPosision = Input.mousePosition;//ドラッグチェック用スタート地点
}
if(Input.GetMouseButton(0))//マウス押している間
{
mouseDownTime += Time.deltaTime; //長押しチェック用カウントアップ
}
if (Input.GetMouseButtonUp(0))
{
if (clickFlg)//一度クリックし、時間ないにもう一度クリック
{
doubleClickAction();//ダブルクリック
clickFlg=false;//クリックフラグ解除
}
else
{//クリックしていない状態
clickTime=0;//ダブルクリックチェック用カウンタ初期化
clickFlg=true;//クリックチェックフラグ
if(Vector3.Distance(dragStartPosision, Input.mousePosition) > 1)
{//ドラッグチェック、スタート地点から移動しているか?
MovePoisition();//ドラッグ
clickFlg=false;//クリックフラグ解除
}
else if(mouseDownTime>0.4)
{//長押し時間超えているか?
longClickAction();//長押し
clickFlg=false;//クリックフラグ解除
}
}
}
if(clickFlg)//クリックしてチェック
{
clickTime += Time.deltaTime;//ダブルクリックチェック用カウンタUP
if(clickTime > 0.3)//カウンタリミット
{
singleClickAction();//シングルクリック
clickFlg=false;//クリックフラグ解除
}
}
//ホイルスクロールで拡大縮小
float scroll = 0f;
scroll = Input.mouseScrollDelta.y;
mainCamera.transform.Translate(0, 0, scroll);
}

private void MovePoisition()
{
Debug.Log("ドラッグ");
}
void longClickAction()
{
Debug.Log("長押し");
}
void singleClickAction()
{
Debug.Log("シングル");
}
void doubleClickAction()
{
Debug.Log("ダブル");
}

}


マウスボタンの判定は

押した時、押してる時、離した時

これを利用して

ダブルクリックは1回目クリックを離した時からタイマーを動かし、

短い時間で2回目のクリック(ボタン離れた時)が発生したらダブルクリック

クリックフラグをつけておいて、時間がきたら解除、解除される前にクリックが発生するかを確認。

シングルクリックはダブルクリックにならなかったらシングルなので

時間が来たら解除、のところに解除されるってことはシングルクリック!

この時間が来たらの時間を長くするとシングルクリックの反応が遅くて気持ち悪い


ドラッグは

ボタン押した時に、押した場所を記録

離したときに、その場所からずれていたらドラッグとする


長押しは

ボタン押した時にタイマー初期化

ボタン押している間、タイマーを増やす

離した時に、一定以上押していたら長押しとする。

ただ、ドラッグの時も長押し状態なので、ドラッグと異なりマウスが移動していないことをじょうけんに加える


おまけに

スクロールボタンでカメラのズームとかも実装

 

参考

https://qiita.com/Nakatomo/items/7a1491de39a94fa176b0

2021年7月16日金曜日

#4 敵に見つかると追いかけれるようにする

こんにちは!ぴちおです。

前回敵キャラを徘徊させるようにしました。

今回は敵キャラがプレイヤーを見つけると追いかけてくる仕組みを作ります。


仕組みとしては

敵キャラからレイを飛ばして

プレイヤーを見つけたら、プレイヤーの場所にNavMeshで移動

視界から消えた場合、プレイヤーの場所に到着したら、徘徊モードに戻る。


まずは、ますは敵の探索範囲を作ります。

敵オブジェクト[enemy]の下に

空のオブジェクト[CollisionDetector]を作成

スフィアコライダーを追加、スクリプト「searchPlayer」を作成

中身を書いていきます。

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

public class SearchPlayer : MonoBehaviour
{
EnemyController script; //UnityChanScriptが入る変数
private RaycastHit hit;
// Start is called before the first frame update
void Start()
{
script = transform.parent.gameObject.GetComponent<EnemyController>();
}

private void OnTriggerStay(Collider other)
{
if (other.CompareTag("Player"))
{
GameObject Target = GameObject.Find("player");
var diff = Target.transform.position - transform.position;
var distance = diff.magnitude;
var direction = diff.normalized;
if(Physics.Raycast(transform.position, direction, out hit, distance))
{
if(hit.transform.gameObject == Target)
{
script.targetPlayer = Target;
}
}
}
}

private void OnTriggerExit(Collider other)
{
script.targetPlayer = null;
}
}

コライダーに接触したら、

タグを確認、プレイヤーであれば、

レイ発射!壁とかないのを確認して、

なければenemyのtargetPlayerにヒットしたプレイヤーをセット。

コライダーから外れたら、targetPlayerを空にする。


{
private float i=0;
private NavMeshAgent agent = null;
[SerializeField] private DestinationController destinationController;
private bool arvFlg = false;
private float waitMaxTime = 5f;
private float waitTime;
private float waitCount = 0f;
public GameObject targetPlayer;

GameObjectを宣言

void Update()
{
if(targetPlayer != null){
destinationController.SetDestination(targetPlayer.transform.position);
agent.SetDestination(destinationController.GetDestination());
}
else
{
if(Vector3.Distance(transform.position, destinationController.GetDestination()) < 1.5f)
{
・・・・

}
}
}

Update内にターゲットが決まっている場合そこを目的地に移動するロジックを追加


壁があると、ちゃんと避けたり、視界を遮ったりします。

あ、もちろん、BAKEし直しとか必要です。




参考にさせていただいたサイト:

 

2021年7月15日木曜日

#3 敵キャラを動かしてみる

こんにちは!ぴちおです。

前回プレイヤーを作成したので、

次は敵キャラを表示したいと思います。


まずは、ヒエラルキー→3Dオブジェクト→カプセル

位置をプレイヤーと被らないように

x:10,y:1,z:10に変更。

コンポーネント追加から

ナビメッシュエージェントと

リッジボディと

新しいスクリプト「enemyController」をセット

スクリプトはScriptフォルダに入れておく


あと、プレイヤーと敵がわかるように色をつけます。

プロジェクトの+からフォルダを作成、名前を「Material」とする

プロジェクトの+からマテリアルの作成

できたマテリアルをCtrl+Dで複製

それぞれ名前を「playerMaterial」「enemyMaterial」とする

わかりやすいようにplayerMaterialの色を青、enemyMaterialの色を赤にする



それぞれ、マテリアルをアタッチする(ドラッグ&ドロップ)

続いて、敵の動きをつけます。

とりあえず、初めは徘徊して、視界にプレイヤーが入ったら追っかけてくるようにします。


まずは徘徊の仕組み。

ランダムに移動可能な場所を取得。

そこまでNav Meshで移動。

到着したら決められた時間待機して、再びランダムな場所を取得して移動を繰り返す。

[NavMeshを使った巡回するNPCのつくりかた]を参考に作成。


クラス用に新規C#を作成「DestinationController」という名前にする。

それをダブルクリックしてスクリプトを作成していきます。

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

public class DestinationController : MonoBehaviour
{
//public float wanderRange;
//目的地
[SerializeField] private Vector3 destination;

public void CreateDestination(Vector3 pos,float wanderRange)
{
//pos:引数現在地
//wanderRange:ランダム範囲
//ランダムな場所を設定
SetDestination(new Vector3(Random.Range( pos.x - wanderRange, pos.x + wanderRange), 0, Random.Range( pos.z - wanderRange, pos.z + wanderRange)));
}

// 目的地の設定
public void SetDestination(Vector3 position)
{
destination = position;
}

// 目的地の取得
public Vector3 GetDestination()
{
return destination;
}
}

CreateDestinationは

posは現在地、要はenemyのtransform.positionです。

wanderRangeはどのくらいの範囲移動するかです。

続いて、enemyController側を作成。

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

[RequireComponent(typeof(NavMeshAgent))]
[RequireComponent(typeof(DestinationController))]

public class enemyController : MonoBehaviour
{
private float i=0;
private NavMeshAgent agent = null;
[SerializeField] private DestinationController destinationController;

void Start()
{
agent = GetComponent<NavMeshAgent>();
destinationController = GetComponent<DestinationController>();
destinationController.SetDestination(transform.position);//スタートを待ち状態から始める
}
void Update()
{
if(Vector3.Distance(transform.position, destinationController.GetDestination()) < 1.5f)
{
do
{
destinationController.CreateDestination(transform.position,10f);//ランダムな行き先設定
i++;
if(i>100){
break;
}//予防策
} while (!RandomWander());//ルートがあるかの確認
}
}

private bool RandomWander() {
//指定した目的地に障害物があるかどうか、そもそも到達可能なのかを確認して問題なければセットする。
//pathPending 経路探索の準備できているかどうか
var path = new NavMeshPath();
bool rFlg = false;
if (!agent.pathPending) {
if (agent.remainingDistance <= agent.stoppingDistance) {
//hasPath エージェントが経路を持っているかどうか
//agent.velocity.sqrMagnitudeはスピード
if (NavMesh.CalculatePath(transform.position, destinationController.GetDestination(), NavMesh.AllAreas, path))
{
agent.SetDestination(destinationController.GetDestination());
rFlg = true;
}
}
}
return rFlg;
}

}

using UnityEngine.AIは忘れないように!!

これから到着したら、ちょっと待機する機能を追加します。

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

[RequireComponent(typeof(NavMeshAgent))]
[RequireComponent(typeof(DestinationController))]

public class enemyController : MonoBehaviour
{
private float i=0;
private NavMeshAgent agent = null;
[SerializeField] private DestinationController destinationController;
private bool arvFlg = false;
private float waitMaxTime = 5f;
private float waitTime;
private float waitCount = 0f;

void Start()
{
agent = GetComponent<NavMeshAgent>();
destinationController = GetComponent<DestinationController>();
destinationController.SetDestination(transform.position);//スタートを待ち状態から始める

waitTime = Random.Range(1,waitMaxTime);//まちじかんをランダム
}
void Update()
{
if(Vector3.Distance(transform.position, destinationController.GetDestination()) < 1.5f)
{
//到着したら
if(arvFlg)
{
//待機時間過ぎたか?
if(waitCount > waitTime)
{
//過ぎた場合行き先セットしてタイマーとフラグクリア
do
{
destinationController.CreateDestination(transform.position,10f);//ランダムな行き先設定
i++;
if(i>100){
break;
}//予防策
} while (!RandomWander());//ルートがあるかの確認
arvFlg=false;
waitTime = Random.Range(1,waitMaxTime);
waitCount = 0;
}
else
{
//過ぎてない場合、カウント
waitCount += Time.deltaTime;
}
}
else
{
arvFlg=true;
}
}
}

private bool RandomWander() {
//指定した目的地に障害物があるかどうか、そもそも到達可能なのかを確認して問題なければセットする。
//pathPending 経路探索の準備できているかどうか
var path = new NavMeshPath();
bool rFlg = false;
if (!agent.pathPending) {
if (agent.remainingDistance <= agent.stoppingDistance) {
//hasPath エージェントが経路を持っているかどうか
//agent.velocity.sqrMagnitudeはスピード
if (NavMesh.CalculatePath(transform.position, destinationController.GetDestination(), NavMesh.AllAreas, path))
{
agent.SetDestination(destinationController.GetDestination());
rFlg = true;
}
}
}
return rFlg;
}

}

到着したら、到着フラグ立てる、到着フラグ立ってれば待ちカウントアップして、規定値になったら処理を行う。

destinationController.CreateDestination(transform.position,10f); 
ここの10fを長くすると長距離、短くすると短距離になります。
private float waitMaxTime = 5f;
ここの数値を長くすると待ち時間の最長時間が長くなります。
ソースないでランダムで書いてるところをそのまま数値にすると、固定の待ち時間になります。
 

これで、敵キャラがうろちょろします。




参考にさせていただいたサイト:


NavMeshを使った巡回するNPCのつくりかた


【Unity】徘徊する敵をNavigationで作る方法