unityで相対的な向きを表示する

# はじめに
前回はUnityでListの中身を表示する方法について解説しました。
[UnityでListの中身を表示する](https://qiita.com/Takahiro_MOTOYA/items/6a7ea4aea062506acf25)
今回はその続き(?)です。

#概要
　前回は矢印を押したら表示されるだけでしたが、今回は矢印を押したらその方向を向き、その方向に進む機能を実装します。
　ここでポイントなのが、常に上を基準として左右を決めるのではなく、**向いた方向を基準としてどう動くのか**ということです。例えば　→　→　と入力したのならば右に2進むのではなく、右を向いて1進み、さらにそこから右を向き1進みます。（つまり　→　↓　と動く）

|　矢印　  |座標　   |　向き　|
|:--------|--------:|:-----:|
|　なし　　|　0 , 0　|　↑　|
|　↑　　　 |　0 , 1　|　↑　|
|　→　　　 |　1 , 0　|　→　|
|　↓　　　 |　0 , -1　|　↓　|
|　←　　　 |　-1 , 0　|　←　|
|　↑　→　　|　1 , 1　|　→　|
|　↓　→　← |　-1 , -2　|　↓　|

＊ここで注意なのが特に　↓　をはさんだ時です。下を向いた状態のとき、左右は反転します。つまり　←　なら右、　→　なら左のほうへ向きます。
＊向きは相対的ですが、座標は絶対的です。

　すごくややこしいですが、今回はこれを実装していこうと思います。なお、初期座標は　( 0 , 0 )　、初期の向きは　↑　とし　6　×　6 のフィールド上のみ移動できるものとします。（一回の動作で1動く）

![MIRS_Test-SampleScene-PC_-Mac-_-Linux-Standalone-Unity-2019.2 (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520446/9c10f294-1a93-2dab-bd1d-42574699499d.gif)

Unity2019.2.0f1
Windows10 64bit

#作成手順
全体の流れは前回とあまり変わっていません。ポイントだけ押さえて説明していきます。

##1.仕組み
基本的にはその時の向きに応じて実行する処理を変更しています。現在の向きを取得し、その方向を基準とした前後左右に動く。そして、向きを更新するといっった流れになています。

##2.向き
向きを決める関数は以下のようになっています。

```c#:sample.cs
switch (i%4)
{
    case 0:     //上を向いている状態
        posy += 1;
        break;

    case 1:     //右を向いている状態
        posx += 1;
        break;

    case 2:     //下を向いている状態
        posy -= 1;
        break;

    case 3:     //左を向いている状態
        posx -= 1;
        break;
}
```
まず、変数iについて、上を0、右を1、下を2、左を3　と定めます。そのi(向き)の値によって前に進むという処理を場合分けしています。条件が　i%4　となっているのは処理が終わり、現在向いている方向を更新する際にiの値がどんどん加算されていくためです。

##3.座標
座標を決める関数は以下のようになっています(↑ボタン)

```c#:sample.cs
public void StraightButton()
{
    if ((posy < 6 && dir%4 == 0) || (posx < 6 && dir%4 == 1) 
        || (posy > 0 && dir%4 == 2) || (posx > 0 && dir%4 == 3))
    {
        Dirlist.Add(Direction.Straight);
        Dir(dir);
    }
    else 
    {
        Debug.Log("Error");
    }
}
```
まっすぐ前に進むときの条件としては次の4つです。
1.　上を向いているときy座標は5以下
2.　右を向いているときx座標は5以下
3.　下を向いているときy座標は1以上
4.　左を向いているときx座標は1以上

↑ボタンでは現在の向きで向きの関数を実行していますが、→ボタンでは+1、下ボタンでは+2、←ボタンでは+3した値で実行されます。↑ボタンを基準として同じ関数を向きを変えることでどの方向でも使用可能にしているためです。また、この関数が実行された後、現在の向きを→ボタンでは+1、下ボタンでは+2、←ボタンでは+3して更新します。↑ボタンではこの処理はありません。

##ソースコード
以下が全体のソースコードです。それぞれのボタンの関数を当てはめることで実際に動かすことができます。

```c#:sample.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading.Tasks;
using UnityEngine.UI;

public class sample : MonoBehaviour
{
    private List<Direction> Dirlist = new List<Direction>();     //Listの宣言

    int posx = 0, posy = 0;       //初期座標
    int dir = 0;        //初期方向
    string D = "↑";     //初期方向表示
    public Text position;       //座標表示
    public Text direction;      //MIRSの方向

    void Start()
    {
        position.text = "座標は（ 0 , 0 ）";
        direction.text = "方向は　↑";
    }

    void Update()
    {
        position.text = "座標は（ " + posx.ToString() + " , " + posy.ToString() + " ）";
        switch (dir%4)
        {
            case 0:
                D = "↑";
                break;

            case 1:
                D = "→";
                break;

            case 2:
                D = "↓";
                break;

            case 3:
                D = "←";
                break;
        }
        direction.text = "方向は　" + D;
    }

    void Dir(int i)
    {
        switch (i%4)
        {
            case 0:     //上を向いている状態
                posy += 1;
                break;

            case 1:     //右を向いている状態
                posx += 1;
                break;

            case 2:     //下を向いている状態
                posy -= 1;
                break;

            case 3:     //左を向いている状態
                posx -= 1;
                break;
        }
    }

    public enum Direction
    {      //enumの定義
        Straight,
        Back,
        Left,
        Right
    }

    public void StraightButton()
    {
        if ((posy < 6 && dir%4 == 0) || (posx < 6 && dir%4 == 1) 
            || (posy > 0 && dir%4 == 2) || (posx > 0 && dir%4 == 3))
        {
            Dirlist.Add(Direction.Straight);
            Dir(dir);
        }
        else 
        {
            Debug.Log("Error");
        }
    }

    public void BackButton()
    {
        if ((posy > 0 && dir % 4 == 0) || (posx > 0 && dir % 4 == 1) 
            || (posy < 6 && dir % 4 == 2) || (posx < 6 && dir % 4 == 3))
        {
            Dirlist.Add(Direction.Back);
            Dir(dir + 2);
            dir += 2;
        }
        else
        {
            Debug.Log("Error");
        }
    }

    public void RightButton()
    {
        if ((posx < 6 && dir % 4 == 0) || (posy > 0 && dir % 4 == 1) 
            || (posx > 0 && dir % 4 == 2) || (posy < 6 && dir % 4 == 3))
        {
            Dirlist.Add(Direction.Right);
            Dir(dir + 1);
            dir += 1;
        }
        else
        {
            Debug.Log("Error");
        }
    }

    public void LeftButton()
    {
        if ((posx > 0 && dir % 4 == 0) || (posy < 6 && dir % 4 == 1) 
            || (posx < 6 && dir % 4 == 2) || (posy > 0 && dir % 4 == 3))
        {
            Dirlist.Add(Direction.Left);
            Dir(dir - 1);
            dir += 3;
        }
        else
        {
            Debug.Log("Error");
        }
    }

    public void SearchButton()
    {
        Search();
    }

    async void Search()
    {
        foreach (Direction dir in Dirlist)
        {
            Debug.Log(dir.ToString());
            await Task.Delay(1000);
        }
    }

    public void clear()
    {
        Dirlist.Clear();
        posx = 0;
        posy = 0;
        dir = 0;
    }
}

```

#おわりに
いかがでしたでしょうか。説明が難しく、わかりづらくなってしまった部分もあったかもしれません。相対的な処理は使うユーザーにとってもややこしく使う場面は少ないかもしれません。ですが、使うような場面があればぜひ参考にしてもらえると幸いです。