見出し画像

(#03)UnityでタクティスRPGが作りたい!! - プレイヤー移動完結編 -

どうもみなさん!今回で、プレイヤー移動を終わらせます。
することは、移動可能範囲を設けて移動できるように制限をかけます。


Playerクラスの修正

プレイヤーの現在位置を記録していなかったので変数を作ります。
あとは、移動可能範囲を2次元ベクトルを使って設定します。

using UnityEngine;

public class Player : MonoBehaviour
{
    //スポーン位置
    public Vector3 SpawnPos;

    //移動可能範囲を設定
    public Vector2Int MovableDirection;  //付け足したのもの

    [HideInInspector] public Vector2Int CurrentPos; //付け足したもの

    private void Start()
    {
        CurrentPos.x = (int)SpawnPos.x; //付け足したもの
        CurrentPos.y = (int)SpawnPos.y; //付け足したもの
    }

    /// <summary>
    /// 指定した位置に移動
    /// </summary>
    /// <param name="pos"></param>
    public void MovePostion(Vector2Int pos)
    {
        transform.position = new Vector3Int(pos.x, pos.y, 0);
        CurrentPos.x = pos.x; //付け足したもの
        CurrentPos.y = pos.y; //付け足したもの
    }
}

Tileクラスの修正

ここでは、プレイヤーが移動可能タイルに印をつける関数を付け足しました。

using UnityEngine;

public class Tile : MonoBehaviour
{
    //移動可能判定用
    public bool IsMovable;

    //移動範囲内にいる判定用
    public bool PlayerMovable { get; private set; }  //付け足したもの
 
    //タイルのID (使うかわからん)
    public int ID;

    //タイルのタイプ
    public TILETYPE TileType;

    //タイルの座標
    [HideInInspector] public Vector2Int TilePos;  //付け足したもの

    //タイルにいるキャラクターの情報
    [HideInInspector] public Player PlayerInfo = null;

    //セレクト用タイル
    [SerializeField] private GameObject _selectTile;

    //セレクトタイルを表示
    public void ShowSelectTile()
    {
        _selectTile.SetActive(true);
    }
    //セレクトタイルを非表示
    public void HideSelectTile()
    {
        _selectTile.SetActive(false);
    }

  //付け足したもの
    /// <summary>
    /// プレイヤーが移動可能だった場合にタイルを移動可能にする
    /// </summary>
    public void SetMovableTile()
    {
        PlayerMovable = true;
        GetComponent<SpriteRenderer>().color = Color.red;
    }

  //付け足したもの
    /// <summary>
    /// 移動可能タイルをリセット
    /// </summary>
    public void ResetMovableTile()
    {
        PlayerMovable = false;
        GetComponent<SpriteRenderer>().color = Color.white;
    }
}

public enum TILETYPE
{
    MOVABLETILE,
    UNMOVABLETILE
}

PlayerManagerクラスの修正

前回のままだと、タイルがランダムに生成されるので、障害物タイルがプレイヤーとかぶってしまうことが起きます。なので、そこを修正します。

using UnityEngine;

public class PlayerManager : MonoBehaviour
{
    //タイルマネージャー
    private TileManager _tileManager;

    //プレイヤーを格納する配列
    [SerializeField] private Player[] players = new Player[3];

    //プレイヤーデータを格納する配列
    public Player[] PlayerDatas = new Player[3];

    /// <summary>
    /// 初期化処理
    /// </summary>
    public void Init()
    {
        _tileManager = GetComponent<TileManager>();

        for (int i = 0; i < players.Length; i++)
        {
            //プレイヤーをスポーン
            var player = Instantiate(players[i], players[i].SpawnPos, Quaternion.identity);
              
            //付け足したもの↓
            //プレイヤーの位置には移動可能タイルをセット
            Vector2Int playerPos = GameDirector.Instance.ConvertVector3ToVector2Int(player.SpawnPos);
            _tileManager.ChangeTile(playerPos);

            //プレイヤーの位置とタイルの位置が一致したタイルを取得
            var tile = _tileManager.GetTileInfoFromPosition(playerPos);

            //取得しタイルのPlayerInfoにプレイヤーを格納
            tile.PlayerInfo = player;

            //プレイヤーデータ配列に格納
            PlayerDatas[i] = player;

        }
    }
}

TileManagerクラスの修正

今回の本題と言っていいほど、たくさん書きました。
メインは移動システムですね。右方向、左方向、上方向、下方向
斜め方向と全8方向作りました。参考程度にご覧ください。

using UnityEngine;
using UnityEngine.UI;

public class TileManager : MonoBehaviour
{
    //タイル配列
    [SerializeField] private Tile[] tiles;
    //タイルの親オブジェクト
    [SerializeField] private Transform _tileParent;

    //タイルを格納する2次元配列
    [HideInInspector] public Tile[,] tileDatas;

    //タイルの横幅
    public const int WIDTH = 15;
    //タイルの縦幅
    public const int HEIGHT = 9;

    //現在選択されているタイル
    Tile SelectedTile = null;  //付け足したもの

    /// <summary>
    /// 初期処理
    /// </summary>
    public void Init()
    {
        //タイルデータ格納用配列の初期化
        tileDatas = new Tile[WIDTH, HEIGHT];
        for (int i = 0; i < WIDTH; i++)
        {
            for (int j = 0; j < HEIGHT; j++)
            {
                //タイルのスポーン位置を計算
                Vector3Int pos = new Vector3Int(i - WIDTH / 2, j - HEIGHT / 2, 0);

                //タイルをランダムに選択
                Tile SelectTile = GetRandomTile();

                //タイルをスポーン
                var tile = Instantiate(SelectTile, pos, Quaternion.identity, _tileParent);

                //タイルに現在の座標を記録
                tile.TilePos.x = pos.x;
                tile.TilePos.y = pos.y;

                //スポーンされたタイルを配列に格納
                tileDatas[i, j] = tile;

            }
        }
    }

  //付け足したもの↓
    /// <summary>
    /// タイルのプレイヤー情報を空にする
    /// </summary>
    public void ResetTilePlayerInfo()
    {
        for (int i = 0; i < WIDTH; i++)
        {
            for (int j = 0; j < HEIGHT; j++)
            {
                if (tileDatas[i, j].PlayerInfo != null) tileDatas[i, j].PlayerInfo = null;
            }
        }
    }

  //付け足したもの↓
    /// <summary>
    /// 移動範囲のリセット
    /// </summary>
    public void ResetMovableTile()
    {
        for(int i = 0; i < WIDTH; i++)
        {
            for (int j = 0; j < HEIGHT; j++)
            {
                if (tileDatas[i, j].PlayerMovable) tileDatas[i, j].ResetMovableTile();
            }
        }
    }

  //付け足したもの これが移動システム
    /// <summary>
    /// 移動可能タイルに印をつける
    /// </summary>
    /// <param name="playerPos"></param>
    /// <param name="moveDir"></param>
    public void MovableTile(Player target, Vector2Int moveDir)
    {
        Tile tempTile = null;
        for (int i = 0; i < WIDTH; i++)
        {
            for (int j = 0; j < HEIGHT; j++)
            {
                //プレイヤーを見つけたら
                if (tileDatas[i, j].TilePos == target.CurrentPos)
                {
                    //右方向の移動範囲
                    for (int k = 1; k < (moveDir.x + 1); k++)
                        if ((target.CurrentPos.x + k) <= (WIDTH / 2) && (tempTile = GetMovableTile(tileDatas[i + k, j]))) tempTile.SetMovableTile();
                        else break;

                    //右斜め上方向の移動範囲
                    for (int k = 1; k < (moveDir.x + 1); k++)
                        if ((target.CurrentPos.x + k) <= (WIDTH / 2) && (target.CurrentPos.y + k) <= (HEIGHT / 2) && (tempTile = GetMovableTile(tileDatas[i + k, j + k])))
                            tempTile.SetMovableTile();
                        else break;

                    //右斜め下方向の移動範囲
                    for (int k = -1; k > -(moveDir.x + 1); k--)
                        if ((target.CurrentPos.x - k) <= (WIDTH / 2) && (target.CurrentPos.y + k) >= -(HEIGHT / 2) && (tempTile = GetMovableTile(tileDatas[i - k, j + k])))
                            tempTile.SetMovableTile();
                        else break;

                    //左方向の移動範囲
                    for (int k = -1; k > -(moveDir.x + 1); k--)
                        if ((target.CurrentPos.x + k) >= -(WIDTH / 2) && (tempTile = GetMovableTile(tileDatas[i + k, j]))) tempTile.SetMovableTile();
                        else break;

                    //左斜め上方向の移動範囲
                    for (int k = -1; k > -(moveDir.x + 1); k--)
                        if (((target.CurrentPos.x + k) >= -(WIDTH / 2) && (target.CurrentPos.y - k) <= (HEIGHT / 2)) && (tempTile = GetMovableTile(tileDatas[i + k, j - k])))
                            tempTile.SetMovableTile();
                        else break;

                    //左斜め下方向の移動範囲
                    for (int k = -1; k > -(moveDir.x + 1); k--)
                        if ((target.CurrentPos.x + k) >= -(WIDTH / 2) && (target.CurrentPos.y + k) >= -(HEIGHT / 2) && (tempTile = GetMovableTile(tileDatas[i + k, j + k])))
                            tempTile.SetMovableTile();
                        else break;

                    //上方向の移動範囲
                    for (int k = 1; k < (moveDir.y + 1); k++)
                        if ((target.CurrentPos.y + k) <= (HEIGHT / 2) && (tempTile = GetMovableTile(tileDatas[i, j + k]))) tempTile.SetMovableTile();
                        else break;

                    //下方向の移動範囲
                    for (int k = -1; k > -(moveDir.y + 1); k--)
                        if ((target.CurrentPos.y + k) >= -(HEIGHT / 2) && (tempTile = GetMovableTile(tileDatas[i, j + k]))) tempTile.SetMovableTile();
                        else break;
                }
            }
        }
    }

  //付け足したもの↓
    /// <summary>
    /// そのタイルが移動可能か
    /// </summary>
    /// <param name="tile"></param>
    /// <returns></returns>
    public Tile GetMovableTile(Tile tile)
    {
        if(tile != null)
        {
            if (tile.IsMovable) return tile;
            else return null;
        }
        return null;
    }

  //付け足したもの↓
    /// <summary>
    /// 指定した座標を移動可能タイルに変更
    /// </summary>
    /// <param name="pos"></param>
    public void ChangeTile(Vector2 pos)
    {
        for (int i = 0; i < WIDTH; i++)
        {
            for (int j = 0; j < HEIGHT; j++)
            {
                if (tileDatas[i, j].TilePos == pos)
                {
                    Destroy(tileDatas[i, j].gameObject);

                    //タイルをスポーン
                    var tile = Instantiate(tiles[0], pos, Quaternion.identity, _tileParent);

                    //タイルに現在の座標を記録
                    tile.TilePos.x = (int)pos.x;
                    tile.TilePos.y = (int)pos.y;

                    //スポーンされたタイルを配列に格納
                    tileDatas[i, j] = tile;
                    break;
                }
            }
        }
    }

    /// <summary>
    /// 選択した座標のタイルを選択状態にする
    /// </summary>
    /// <param name="pos"></param>
    public void ShowSelectTileFromPosition(Vector2Int pos)
    {
        //すべてのセレクト状態を外す
        AllHideSelectTile();

        for (int i = 0; i < WIDTH; i++)
        {
            for (int j = 0; j < HEIGHT; j++)
            {
                if (tileDatas[i, j].TilePos == pos)
                {
                    tileDatas[i, j].ShowSelectTile();
                    SelectedTile = tileDatas[i, j];
                    break;
                }
            }
        }
    }

    /// <summary>
    /// すべてのセレクト状態を外す
    /// </summary>
    public void AllHideSelectTile()
    {
        if(SelectedTile != null)
        {
            SelectedTile.HideSelectTile();
            SelectedTile = null;
        }
    }

    /// <summary>
    /// 2次元座標からタイル情報取得
    /// </summary>
    /// <param name="pos"></param>
    /// <returns></returns>
    public Tile GetTileInfoFromPosition(Vector2Int pos)
    {
        for(int i = 0; i < WIDTH; i++)
        {
            for( int j = 0; j < HEIGHT; j++)
            {
                if (tileDatas[i,j].TilePos == pos) return tileDatas[i,j];
            }
        }
        return null;
    }

    /// <summary>
    /// TYPEからタイルデータを取得
    /// </summary>
    /// <param name="tileType"></param>
    /// <returns></returns>
    public Tile GetTileByType(TILETYPE tileType)
    {
        foreach(Tile tile in tiles)
        {
            if(tile.TileType == tileType) return tile;
        }
        return null;
    }

    /// <summary>
    /// ランダムにタイルを取得
    /// </summary>
    /// <returns></returns>
    private Tile GetRandomTile()
    {
        int rnd = Random.Range(0, 100);

        switch(rnd)
        {
            case < 10:
                return GetTileByType(TILETYPE.UNMOVABLETILE);
            case < 100:
                return GetTileByType(TILETYPE.MOVABLETILE);
        }
        return null;
    }
}

GameDirectorクラスの修正

後は、作ってきた関数たちをこのクラスで呼び出すだけです。

using UnityEngine;

public class GameDirector : MonoBehaviour
{
    //タイルマネージャー
    private TileManager _tileManager;
    //プレイヤーマネージャー
    private PlayerManager _playerManager;

    //選択中のキャラクター
    Player SelectedPlayer = null; //付け足したもの

    //移動前のタイル
    Tile oldTile; //付け足したもの

    //ゲームステート
    public enum GameState
    {
        PlayerTurn_Begin,
        PlayerTurn_MoveTileSelect,
        PlayerTurn_CommandSelect,
        PlayerTurn_Attack,
        PlayerTurn_End
    }
    GameState currentGameState = GameState.PlayerTurn_Begin;

    /// <summary>
    /// シングルトン
    /// </summary>
    public static GameDirector Instance { get; private set; }
    private void Awake()
    {
        if(Instance == null) Instance = this;
    }

    private void Start()
    {
        _tileManager = GetComponent<TileManager>();
        _playerManager = GetComponent<PlayerManager>();

        //** 初期化 **//
        //タイルを生成
        _tileManager.Init();

        //プレイヤーを配置
        _playerManager.Init();
    }

    private void Update()
    {
        //タイルがクリックされたら
        if(Input.GetMouseButtonDown(0))
        {
            //クリックした座標をワールド座標に変換
            Vector3 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
            //マウス座標をVector2Intに変換
            Vector2Int targetPos = ConvertVector3ToVector2Int(mousePos);

            //選択した場所のタイルを取得
            Tile tileInfo = _tileManager.GetTileInfoFromPosition(targetPos); //付け足したもの

            switch (currentGameState)
            {
                case GameState.PlayerTurn_Begin:

                    //タイルを選択状態にする
                    _tileManager.ShowSelectTileFromPosition(targetPos);

                    //タイルにプレイヤーがいるなら取得
                    SelectedPlayer = tileInfo.PlayerInfo; //付け足したもの

                    //選択しタイルにプレイヤーがいるなら
                    if (SelectedPlayer != null)
                    {
                        //タイル情報を一時的に格納
                        oldTile = tileInfo;  //付け足したもの

                        //ステート変更
                        ChangeState(GameState.PlayerTurn_MoveTileSelect);
                        _tileManager.MovableTile(SelectedPlayer, SelectedPlayer.MovableDirection);
                    }
                    break;
                case GameState.PlayerTurn_MoveTileSelect:

                    //選択した位置に移動
                    if(SelectedPlayer != null && tileInfo.PlayerMovable)
                    {
                        //セレクトタイルを外す
                        _tileManager.AllHideSelectTile();

                        //移動可能タイルをリセット
                        _tileManager.ResetMovableTile(); //付け足したもの

                        //移動
                        SelectedPlayer.MovePostion(targetPos);

                        //移動前のタイルのプレイヤー情報を消去
                        oldTile.PlayerInfo = null; //付け足したもの

                        //移動後のタイルにプレイヤー情報を記録
                        tileInfo.PlayerInfo = SelectedPlayer; //付け足したもの

                        //ステート変更
                        ChangeState(GameState.PlayerTurn_Begin);
                    }
                    break;
            }
        }
    }

    /// <summary>
    /// ゲームステートを変更
    /// </summary>
    /// <param name="state"></param>
    void ChangeState(GameState state)
    {
        currentGameState = state;
    }

    /// <summary>
    /// Vector3型からVector2Intに変換
    /// </summary>
    /// <param name="vector"></param>
    /// <returns></returns>
    public Vector2Int ConvertVector3ToVector2Int(Vector3 vector)
    {
        Vector2Int returnVector2 = new Vector2Int(0,0);
        returnVector2.x = Mathf.RoundToInt(vector.x);
        returnVector2.y = Mathf.RoundToInt(vector.y);

        return returnVector2;
    }
}

そうしたら、以下のように移動範囲内(赤色タイル)で移動できるようになります。

最後に

前回からまた、がっつり修正&改変しました。
コードも見づらくなっていると思います。
ですが、私がやりたかったことは、3Dのタクティスゲームなので
次回から、3Dで実践しますw(今までの奴は練習ですw)

いいなと思ったら応援しよう!