[Unity]ML-Agents「Hide / Escape - Avoidance of Pursuing Enemies」を動かすまで

#かくれんぼのやつが動かない
Unityの機械学習「ML-Agents」を使ったサンプル「[Hide](https://connect.unity.com/p/hide-escape-avoidance-of-pursuing-enemies?_ga=2.253341515.378515917.1581312195-206796369.1581312195)」これがエラーするわ動かないわで大変だった
[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/d9d7238b-330e-6bdd-b0b0-2bfab8533a4f.png)](https://www.youtube.com/watch?time_continue=101&v=3LEJ1eeoC1U&feature=emb_logo)

これが動くようになったので、そこまでの記録を残します
追記：動くまでの話であって、機械学習のところまで至ってません

#ダウンロード
##データセット
このサイトの下の方にあるGitHub
[Hide](https://connect.unity.com/p/hide-escape-avoidance-of-pursuing-enemies?_ga=2.253341515.378515917.1581312195-206796369.1581312195)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/c7f11838-35d6-97a8-717f-34f345d51caf.png)
この「いいね！」マークの上にあるリンクからダウンロードします↑

このページに飛びます↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/8768178b-dc3d-3843-8e0d-fce41dcfeb2e.png)
んでダウウンロード↓
「Clone or download」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/d64443cf-533e-72a0-6251-d19788738d94.png)

zipでお好みの場所に保存（どこでも）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/14a743d1-33dd-c694-c10f-fd3269a0ff31.png)

このセットの中に色々入ってますので
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/b9af227d-4662-3ecc-a5c9-7d09e1f81464.png)
ドキュメントなり普段unityプロジェクトを保存している場所なりに解凍してください

##Json.net
[JSON.net](https://github.com/JamesNK/Newtonsoft.Json/releases)
Newtonsoft.json（JSON使うためのもの）をダウンロードしていない人はこちらも後で必要になるので
↓一番上の「Json120r3.zip」だけで大丈夫です
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/4d11e6fb-d9b2-2188-f6e3-43fdd3c0e13d.png)
適当にダウンロードして適当に解凍してください
後で必要になります

#Unity
UnityHubを起動し、「リストに追加」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/5120dcf8-2cc7-bd34-bf11-021d6a6a5804.png)
先ほど解凍した
hide-escape-master　の中の　unity-environment　を選択
これで↓「フォルダの選択」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/91c4dac1-322c-9341-8f31-b6d9e2832231.png)

こうなる
![asdfjkdalfj.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/e8ec7490-b999-d37f-1047-d89698b2a861.png)
噂によるとバージョンは2018.4以上がいいそうなので
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/28be7d6c-cbc9-2412-156e-499e47ccb85b.png)2018.4.16をインストール

こんな感じで↓バージョン変更して開く
![asdfjkdalfj.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/df6f8ee3-7e30-b2b1-9834-f3216a78d4be.png)
ウィンドウ出ますが「確認」押してGO
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/2680522b-6800-ae64-b8e2-72b19fbeb5f9.png)
#例のブツをみてみよう
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/ba33e58b-4bea-8f67-978b-712619a91bc4.png)
↑の「Hide」というシーンを開く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/a215c8dd-cd73-b38a-ac52-1df94eb0c424.png)
これですよこれ　見たかったのは

#～ライティングをOFFにしておく～
本編に特別関係ないけど、何かあるたび光の当たり方を計算されるのはストレスなので、機能をオフにする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/9de8507e-ec28-5e0b-8d4c-1f54da44f1b1.png)
開いたウィンドウ↓の一番下にある「Auto Generate」のチェックを外し
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/eab937ef-f8fd-1a07-cb4c-3812b6aa2fa7.png)
「Genaerate Lighting」ボタンを押す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/5a47d8ba-3cba-e103-d34e-f5ab2bc8b8aa.png)


#とりあえずエラー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/56a4f14a-8ac2-08fb-4c29-bae90b9fa51e.png)
下2つはBlenderインストールしてれば何か違うのかもしれませんが、入ってないのでパス
左上の「Clear」押しても消えないエラーに対処していきます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/0edf75fc-5b10-d610-23db-53d5c933f654.png)

##Json.netをプラグインに入れる
ダウンロードした「Json120r3」の
Json120r3　→　Bin　→　net20　→　Newtonsoft.Json.dll　を以下の場所にコピペ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/130cb51a-e3dd-d284-d6e3-a8374fca88e3.png)
[参考文献](http://spi8823.hatenablog.com/entry/2016/04/16/001641)

するとエラーは3つ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/117f39e7-2201-3adb-0d36-db1a8427fd62.png)

##Unityでセットアップ
[参考文献](https://qiita.com/KazukiKawamura/items/e1d60ba2481c9b48b0a1)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/0278e5fd-1acc-74f2-dcc8-a7463839f54f.png)Project Settingの
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/440daf84-06a0-d483-6e32-d59d10e2ea0c.png)Playerの
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/cd227e7b-c986-ca20-2773-738f6b3cb796.png)other Settingを開き
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/40626ccb-84d5-32bb-7ee6-43454621e240.png)ちょっと下の方

この
「ENABLE_TENSORFLOW;UNITY_POST_PROCESSING_STACK_V1」
を
「ENABLE_TENSORFLOW」
に変更↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/707a04a3-bec8-8c1b-0e8c-b6ec6436d248.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/2686dc05-07d3-d4a1-20b6-a368cb9efb8d.png)
**しかしエラーは減らない**
んんんんんんんんんんんん
まあ必要な項目ではあったはずなので、エラーが消えるための設定ではなかっただけでしょう

#パッケージを入れませう
[なんか言ってた](https://github.com/Unity-Technologies/ml-agents/issues/1511)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/3dcb65a8-f871-1707-8418-adb34ada09d1.png)
適当なところにダウンロードし、「Import package」でダウンロードしたファイルを指定する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/caff3d14-f382-794b-e156-f639a97f1e27.png)
そしたらウインドウでるから、右下の「Import」ボタンをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/d363bc3b-aa54-8ae3-2591-c42924f95a86.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/a3594c49-6eb0-0f6e-eb09-4d59336371b0.png)
**驚きの白さ**

#なんだか様子が変です
「HideBrain」を選択すると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/38c7c4b2-c07c-5a5a-bc72-1647fc477c6a.png)![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/6c060757-ef98-4cf8-b8a5-dce2f57d8252.png)
なんか言ってる　ファイルがねぇ　と

なのでこの「Hide3-3M」を指定してあげます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/05a07e15-de5a-f728-5f5a-93456c225bb6.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/d5caa251-ed5b-0d56-c94a-0532faf48de2.png)

#これで動くぜ　ヒャッハー！
![ダウンロード.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/511b59ad-7be8-8318-1c76-bad3a37faddd.gif)
**赤おっっっっせぇぇぇぇ**
なんじゃあの移動速度はぁぁぁ一生追いつけんわぁぁぁ
##赤を早くさせる
「Academy」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/d81ef229-c023-c2ad-825a-6d4b4cb66e2c.png)![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/502efb0a-3d29-49fb-0cb3-d4bc2d576c8e.png)
「Value」の値を「3」とかにします（お好みで）
![ダウンロード.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/20140da7-1bde-f728-12ae-96b209eeb36c.gif)こんだけ早ければいいだr…

##いまUターンしなかった？
これで`盲目の追跡者`が完成しましたね✨（コナン君の映画のタイトルにありそう）
次は赤に視界を設けます
**※Blenderが入っていないために、視界のモデル（扇形↓）が生成できなかったと思われ**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/f3ec52e9-ced4-ee2b-1ecb-e2103b867bd9.png)

プログラム的には、
視線上にいる
→扇の当たり判定作動
→青を追いかける
ってなってるので、
扇の代わりを作ればおｋ

つまり、シーンにいる各9人に視界を設けるだけ！！
こんな時のためのプレハブ機能！！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/0aeccc76-baa9-73d0-10c3-5a026e9dd458.png)**※尚、プレハブではない**
**ど　う　し　て**

#視界を作る
仕方ないので方法は2通り
・先を見越して「Chaser」をプレハブに置き換える
・9人の「Chaser」に当たり判定を設ける

選ばれたのは後者でした

やり方は簡単
1. 全ての「fov-shape」を同時選択
2. 位置調整
3. メッシュとコライダーを設定

##1.全ての「fov-shape」を同時選択
「Ctrl」を押しながら、各fov-shapeをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/b334ea94-0c30-a273-eef7-f5f3f26b3873.png)

##2. 位置調整
以下のように値を調整
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/43544781-55ff-6660-37df-b4531b666298.png)**→**![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/c319650d-2512-21f5-39c4-5f4b1ec36f15.png)

##3. メッシュとコライダーを設定
Mesh Filter の「Mesh」に「Cube」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/95142c56-36ad-adc7-6dc8-1a439f2daedf.png)
Mesh Collider の「Mesh」に「Cube」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/31e0576c-2d28-f65f-3b9a-f245e3ca9ce4.png)

するとこうなる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/5c36e993-6c68-4478-6f7d-3b7d6ee488d6.png)

#できた
![AIi.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/77ee1cc4-e54a-49a1-c610-c12ae3e7180f.gif)

#仁王立ちの追跡者
赤の横を青がスルッと通りすぎると以下のように、到達点で停止するバグが判明
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/02ebbd9a-5a8c-48cf-f08f-b1c7e84dba14.png)

**プログラムに工夫が必要**
「HideChaser」を開き
グローバル変数を宣言

```HideChaser.cs
    float timer = 0;
    Vector3 pos;
```
Update()の中に以下を追加

```HideChaser.cs
        if(transform.position == pos)
        {
            timer += Time.deltaTime;
            if(timer > 5)
            {
                timer = 0;
                Debug.LogWarning("Stopped");
                agentInFOV = false;
                agentInLOS = false;
                chasingAgent = false;
                PickNextRoom();
            }
        }
        else
        {
            timer = 0;
        }
        pos = transform.position;
```
応急処置ですがこれでなんとかなります
一応全文載せておきます↓

```HideChaser.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

public class HideChaser : MonoBehaviour {

    public GameObject myAgent;
    public GameObject chaserHead;
    [HideInInspector]
    public HideAgent hideAgent;

    public GameObject[] seekLocations;
    private float positionDoneThreshold = 0.15f;

    public GameObject[] chaserInitialPositions;

    [HideInInspector]
    public NavMeshAgent navAgent;

    [HideInInspector]
    public GameObject currentTarget;
    public GameObject targetLocationIndicator;
    
    [HideInInspector]
    public bool agentInLOS = false;
    [HideInInspector]
    public bool agentInFOV = false;
    [HideInInspector]
    public bool chasingAgent = false;
    public bool showDebug = false;

    [HideInInspector]
    public Vector3 lastKnownAgentLocation;

    private Rigidbody chaserRigidbody;

    public HideAcademy hideAcademy;

    public GameObject winZone;

    float timer = 0;
    Vector3 pos;
    void Start ()
    {
        this.navAgent = this.GetComponent<NavMeshAgent>();
        this.chaserRigidbody = this.GetComponent<Rigidbody>();

        this.hideAgent = myAgent.GetComponent<HideAgent>();

        currentTarget = seekLocations[Random.Range(0, seekLocations.Length)];
        navAgent.SetDestination(currentTarget.transform.position);

        this.targetLocationIndicator.transform.parent = null;
        lastKnownAgentLocation = Vector3.zero;
        pos = transform.position;
    }
	
	void Update ()
    {
        PlaceTargetIndicator();
        MoveChaser();

        if(transform.position == pos)
        {
            timer += Time.deltaTime;
            if(timer > 5)
            {
                timer = 0;
                Debug.LogWarning("Stopped");
                agentInFOV = false;
                agentInLOS = false;
                chasingAgent = false;
                PickNextRoom();
            }
        }
        else
        {
            timer = 0;
        }
        pos = transform.position;
    }

    void MoveChaser()
    {
        // If Agent Has Not Been Seen
        // Pick next room upon reaching destination
        if (Mathf.Abs((currentTarget.transform.position - this.transform.position).magnitude) < positionDoneThreshold && (chasingAgent == false))
        {
            //Debug.Log("Chaser Arrived At Location: " + currentTarget);
            PickNextRoom();
        }

        // If Agent Has Been Seen
        // Pick next room upon reaching last known location
        if ((Mathf.Abs((lastKnownAgentLocation - this.transform.position).magnitude) < positionDoneThreshold) && (chasingAgent == true) && (agentInLOS == false))
        {
            //Debug.Log("Chaser Arrived At LastKnownAgentLocation");
            chasingAgent = false;
            PickNextRoom();
        }

        // If Agent is currently seen, chase
        if (chasingAgent == true)
        {
            //Debug.Log("Chase Agent");
            ChaseAgent();
        }
    }

    public void InLOS()
    {
        if (agentInFOV)
        {
            agentInLOS = true;
            chasingAgent = true;
            lastKnownAgentLocation = myAgent.transform.position;
        }
    }

    private void OnCollisionEnter(Collision collision)
    {
        if (collision.gameObject == myAgent.transform.gameObject)
        {
            HideAgent agent = myAgent.GetComponent<HideAgent>();
            agent.done = true;
            agent.reward -= 10f;
            agent.losses += 1;
        }
    }

    void PlaceTargetIndicator()
    {
        if (chasingAgent == false)
        {
            targetLocationIndicator.transform.position = currentTarget.transform.position;
        }
        else
        {
            targetLocationIndicator.transform.position = lastKnownAgentLocation;
        }
    }

    public void PickNextRoom()
    {
        GameObject tempCurrentTarget = seekLocations[Random.Range(0, seekLocations.Length)];
        while(tempCurrentTarget == currentTarget)
        {
            tempCurrentTarget = seekLocations[Random.Range(0, seekLocations.Length)];
        }
        if(tempCurrentTarget != currentTarget)
        {
            //Debug.Log("New target chosen: " + tempCurrentTarget + " Old target was: " + currentTarget);
            currentTarget = tempCurrentTarget;
            navAgent.SetDestination(currentTarget.transform.position);
            targetLocationIndicator.transform.position = currentTarget.transform.position;
        }
    }

    public void ChaseAgent()
    {
        currentTarget = myAgent;
        navAgent.SetDestination(lastKnownAgentLocation);
    }

    public void Reset()
    {
        // Get curriculum variables from academy
        float chaserSpeed = hideAcademy.GetComponent<HideAcademy>().chaserSpeed;

        // Set curriculum variables
        navAgent.speed = chaserSpeed;

        this.chaserRigidbody.isKinematic = true;

        GameObject chaserInitialPosition = chaserInitialPositions[Random.Range(0, chaserInitialPositions.Length)];

        this.transform.position = new Vector3(chaserInitialPosition.transform.position.x, this.transform.position.y, chaserInitialPosition.transform.position.z);
        this.transform.rotation = chaserInitialPosition.transform.rotation;

        if (hideAcademy.mode == HideAcademy.Mode.Escape)
        {
            if (winZone != null)
            {
                winZone.transform.position = new Vector3(chaserInitialPosition.transform.position.x, winZone.transform.position.y, chaserInitialPosition.transform.position.z);
            }
        }

        agentInLOS = false;
        chasingAgent = false;
        currentTarget = null;
        //lastKnownAgentLocation = Vector3.zero;
        this.chaserRigidbody.isKinematic = false;
        PickNextRoom();
    }
}

```

#モード変更
「Academy」オブジェクトの「Mode」を「Escape」にすると脱出口が現れるようになります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/057e6a18-4aa6-2219-23cb-cef1f8e6e3d3.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/5b47930a-e446-a2fb-d2cb-8a2053f63c25.png)黄色の四角いやつ

#あとはがんばって
動いたはいいけど、果たして機械学習しているのか　まだわかってない

追記：機械学習は十中八九至ってません。なぜならPythonとかの設定をした覚えがないからです。

それでは皆さん　よき機械学習を
![ダウンロード.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/585e85ec-93a1-1c65-c01e-40eed86829ad.gif)

#追記
色々なサイトを見てもML-Agentsのデータの「UnitySDK」を使うとか書いてあるけど、使用したデータにはなくて困ってた

んで見つけた
[Unity ML-Agents Toolkit v0.8：実際のゲームでより迅速なトレーニングが可能に](https://blogs.unity3d.com/jp/2019/04/15/unity-ml-agents-toolkit-v0-8-faster-training-on-real-games/)
「ML-Agents tool kit」とかで検索してたら違うデータが出てきた
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554244/671e6fdc-33a2-7350-b4b0-e37a091810bf.png)
UnitySDK入ってる別のデータ
[ここ](https://github.com/Unity-Technologies/ml-agents/tree/0.8.0)

これで機械学習始められる　のかな？