【Unity2D】0からのローグライク作成記録その1～ターン制移動Scriptの思案～

![1.gif](https://qiita-image-store.s3.amazonaws.com/0/370076/30b8952e-f3af-0b23-40b7-a576b26d5b03.gif)
プレイヤーが一歩移動したらplayersTurnという変数がFalseになって敵のターンに移行。敵のターン処理が終わったらTrueにすれば延々とターンが回せるはず。
ローグライクにおいては自分ターン→敵ターンの繰り返しになるので、自分なりに色々考えて書いてみました。
ふわっとした知識で書いてあるので、参考にする際はお気を付けください。

2019年3月10日
このコードだと色々と不都合があったので、変更版をその2としてまた投稿します。

#プレイヤー側の処理

```ruby:Player.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class Player : MovingObject
{
    public Rigidbody2D rb;
    public SpriteRenderer Spr; // 表示スプライト
    public Animator anm; // アニメーションコンポーネント


    void Update()
    {
        int horizontal = 0; //水平方向
        int vertical = 0;　//垂直方向
        horizontal = (int)(Input.GetAxisRaw("Horizontal"));
        vertical = (int)(Input.GetAxisRaw("Vertical"));

        if (horizontal != 0 || vertical != 0)
        {
            AttemptMove(horizontal, vertical);
        }
    }

    //継承クラスMovingObjectのプレイヤー移動処理を実行
    protected override void AttemptMove(int xDir, int yDir)
    {
        base.AttemptMove(xDir, yDir);
        GameManager.instance.playersTurn = false; //プレイヤーが移動できないように＝敵のターン
    }


}
```
水平もしくは垂直方向の入力があれば、それを継承クラスであるMovingObjectに処理してもらう形です。継承クラスだと後々導入する敵の動きとかにも流用できるはずなので取り敢えず入れています。


```ruby:MovingObject.cs
using System.Collections;
using UnityEngine;

public abstract class MovingObject : MonoBehaviour
{
    private Rigidbody2D rb;
    private BoxCollider2D boxCollider;

    protected virtual void Start()
    {
        this.rb = GetComponent<Rigidbody2D>();
        this.boxCollider = GetComponent<BoxCollider2D>();
    }

    protected virtual void AttemptMove(int xDir, int yDir)
    {
        if (GameManager.instance.playersTurn == true) { //プレイヤーターンのみ移動可能にする
            Vector2 EndPosition = transform.position;
            EndPosition.x += xDir;
            EndPosition.y += yDir;
            StartCoroutine(Movement(EndPosition));
        }
    }

    protected IEnumerator Movement(Vector2 EndPosition)
    {
        //プレイヤーが移動先の座標に移動
        rb.MovePosition(EndPosition);
        yield return new WaitForSeconds(1.0f);
    }
}
```
継承クラスなのでObjectにはアタッチしていません。MonoBehaviourの代わりに使うものだから実体が無くても大丈夫ということなのかな？
AttemptMoveでもしplayersTurnがTrueならばプレイヤーの移動処理がされる形です。もしFalseならば敵のターンということです。IEnumeratorはコルーチン処理というもの。フレームごとの処理だけではなく、この処理が終わったら一秒待つなどが入れられる便利なものです。


#ゲーム全体でのフラグ管理（誰のターンなのか）

```ruby:GameManager.cs
using System.Collections;
using UnityEngine;

public class GameManager : MonoBehaviour
{
    public static GameManager instance;
    public bool playersTurn = true; //trueならプレイヤー移動可能

    void Awake()
    {
        if (instance == null)
        {
            instance = this;
        }
        else if (instance != this)
        {
            Destroy(gameObject);
        }
        DontDestroyOnLoad(gameObject);
    }
}
```
void AwaketはStartメソッドよりも前に実行されるらしいので、このGameManagerが破棄されないオブジェクトにされないようなコードを入れています。どこの記事でも入れているので何となく入れています。
今のところではplayersTurnの入れ物でしか無いが、ゲーム全体のフラグを管理する場所として活用できるはず。

#ローグライクなScriptについて
実は公式でローグライクのサンプルレッスンがあるので、そちらの方が参考になります。自分も読んだのですが、正直いまいち分からなかったので自分なりに噛み砕いた簡略版を載せています。

#座標管理について
プレイヤーの初期位置は（0,0）に設定してあります。そのままだと背景とオブジェクトとズレが生じるので背景とかに使っているタイルマップ自体の起点の座標を（0.5 , 0.5）にするとズレません。こっちのほうが良いはず。