![見出し画像](https://assets.st-note.com/production/uploads/images/170888924/rectangle_large_type_2_9beb21b230df5ab702d3b448195e15f9.png?width=1200)
(#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;
}
}
そうしたら、以下のように移動範囲内(赤色タイル)で移動できるようになります。
![](https://assets.st-note.com/img/1737364076-U5RYBr98oVLKQFO1IvnSfW7M.png?width=1200)
最後に
前回からまた、がっつり修正&改変しました。
コードも見づらくなっていると思います。
ですが、私がやりたかったことは、3Dのタクティスゲームなので
次回から、3Dで実践しますw(今までの奴は練習ですw)