Unity11

Unity

NavMeshAgent

ステージの作成

1.CreateEmptyからStageを原点に作成する。
2.Stageの中にCubeからFloorを作成し表面材質を設定する。transformは以下
●Floor

3.Stageの中にCylinderを複数作成する。(複製しながら行うとよい)
●Cylinder

●Cylinder(1)

●Cylinder(2)

4.複製を繰り返し、下図のような感じにする。(だいたいでよい)

NavMeshの作成

敵の追跡ルートとなるNavMeshを作成する。
5.Stageの子要素をShiftキーを押しながらすべて選択する。

6.複数選択した状態でインスペクター右上隅にあるstaticからNavigation Staticを選択する。

7.Window->AI->Navigationを選択し、Bakeタブであることを確認し、下部のBakeボタンを押す。

8.下図のように探索できるルート(濃い青の部分)が焼き込まれる。

Playerの作成

9.CubeからPlayerを作成し、表面材質を設定する。transformは以下。

10.まずはもっとも単純に移動スクリプトを作るPlayerController1.csとして以下のように作成する。

01using System.Collections;
02using System.Collections.Generic;
03using UnityEngine;
04 
05public class PlayerController1 : MonoBehaviour {
06 
07  void Update () {
08    transform.Rotate (0, Input.GetAxis ("Horizontal"), 0);
09    transform.Translate (0,0,Input.GetAxis ("Vertical") * 5.0f*Time.deltaTime);
10  }
11}

11.Playerに付与して実行してみよう。Translateでの移動は最強といっていい。あらゆるものを無視して移動する。当然Cylinderをすり抜ける。

Enemyの作成

12.それでは追跡してくる敵を作成しよう。CapsuleからEnemyを作成し表面材質を設定する。Transformは以下。

13.AddComponentからNavigation->Nav Mesh Agent を付与する。
14.EnemyController.csを以下のように作成して、Enemyに付与する。(using UnityEngin.AIを忘れないこと)

01using System.Collections;
02using System.Collections.Generic;
03using UnityEngine;
04using UnityEngine.AI;
05 
06public class EnemyController : MonoBehaviour
07{
08    public Transform player;
09    //索敵範囲
10    public float traceDist = 10.0f;
11    NavMeshAgent nav;
12 
13    void Start()
14    {
15        nav = GetComponent<NavMeshAgent>();
16        //毎フレーム距離の計測をする必要はないのでコルーチンで行う。
17        StartCoroutine(CheckDist());
18    }
19 
20    IEnumerator CheckDist()
21    {
22        while (true)
23        {
24            //1秒間に5回距離を計測する。
25            yield return new WaitForSeconds(0.2f);
26            //プレイヤーとの距離を計測
27            float dist = Vector3.Distance(player.position, transform.position);
28            //索敵範囲に入ったか?
29            if (dist < traceDist)
30            {
31                //プレイヤーの位置を目的地に設定
32                nav.SetDestination(player.position);
33                //追跡再開
34                nav.isStopped=false;
35            }
36            else
37            {
38                //探索範囲から出たら追跡終了
39                nav.isStopped=true;
40            }
41        }
42    }
43}

15.インスペクターからplayerを登録し、実行してみよう。プレイヤーの距離に応じて追跡を開始すれば成功だ。

Playerの動き変更1

16.今のままではPlayerはステージ外にいっても落ちないし、Cylinderもすり抜ける。修正しよう。PlayerにCharacterControllerを付与する。
17.PlayerController1を無効にして、PlayerController2を以下のように作成し付与する。

01using System.Collections;
02using System.Collections.Generic;
03using UnityEngine;
04 
05public class PlayerController2 : MonoBehaviour {
06  private CharacterController cc;
07  void Start () {
08    cc = GetComponent<CharacterController> ();
09  }
10  void Update () {
11    transform.Rotate(Vector3.up*Input.GetAxis("Horizontal"));
12    cc.Move (transform.forward*Input.GetAxis("Vertical")*Time.deltaTime*5.0f);
13  }
14}

18.Move関数で動かすことにより、Sylinderをすり抜けられなくなった。その他にも坂があれば45度以下は登るし、30cmの段差なら無視して進むことができる。ただ、Move関数は自分で重力を実装しないと下方向の重力はない。(ステージ外に行っても落ちない)
19.さらに変更してみよう。以下のようにMoveからSimpleMoveでの移動に変更してみる。

01using System.Collections;
02using System.Collections.Generic;
03using UnityEngine;
04 
05public class PlayerController2 : MonoBehaviour {
06  private CharacterController cc;
07  // Use this for initialization
08  void Start () {
09    cc = GetComponent<CharacterController> ();
10  }
11   
12  // Update is called once per frame
13  void Update () {
14    transform.Rotate(Vector3.up*Input.GetAxis("Horizontal"));
15    //cc.Move (transform.forward*Input.GetAxis("Vertical")*Time.deltaTime*5.0f);
16    cc.SimpleMove (transform.forward*Input.GetAxis("Vertical")*Time.deltaTime*120.0f);
17  }
18}

20.SimpleMoveでは重力が与えらる。なので画面外に行った時に落下する。しかもEnemyと衝突したときに押し出されることも確認できる。ただし、スクリプトによって上方にジャンプパワーなどを与えることはできない。MoveとSimpleMoveはどちらも癖がある、どちらを使うかは吟味のしどころだ。

コメント

タイトルとURLをコピーしました