【Unity】RPG制作 その16-ステージ制作 プレイヤーの移動
前回はステージマップの見た目を作っていきました。今回はマップ上のプレイヤーの移動を実装していきます。
プレイヤーを移動させるためのボタンを以下のように配置します。
次にダンジョンの処理を制御するスクリプト、DangionControllerを作成し、DangionMapSystemに貼り付けます。DangionController.csは以下のように記述します。
クリックで展開
using System.Collections; using System.Collections.Generic; using UnityEngine; public class DangionController : MonoBehaviour { public GameObject DownArrowButton; public GameObject LeftArrowButton; public GameObject RIghtArrowButton; public GameObject UpArrowButton; public DangionMap dangionMap; public Vector2Int playerPos = new Vector2Int(2, 2); //プレーヤーの初期位置をマップ座標(2,2)の位置に public Sprite playerSprite; //マップ上でのプレイヤーの画像 public GameObject playerMapObject; //プレイヤーオブジェクトを保持する変数 public bool isSetDangeonMap = false; // マップをセットしたか(CancelButton押下時に) public enum DIRECTION{ Down, Left, Right, Up, } public void ActiveArrowButtons(bool isTrue) { DownArrowButton.SetActive(isTrue); LeftArrowButton.SetActive(isTrue); } public void ActiveOneArrowButton(DIRECTION direction, bool isTrue) { switch (direction) { case DIRECTION.Down: DownArrowButton.SetActive(isTrue); break; case DIRECTION.Left: LeftArrowButton.SetActive(isTrue); break; case DIRECTION.Right: RIghtArrowButton.SetActive(isTrue); break; case DIRECTION.Up: UpArrowButton.SetActive(isTrue); break; } } public void PlayerMoveDown() //プレイヤーの移動関数 New { playerPos.y++; UpdatePlayerPosition(); } public void PlayerMoveUp() //プレイヤーの移動関数 { playerPos.y--; UpdatePlayerPosition(); } public void PlayerMoveLeft() //プレイヤーの移動関数 { playerPos.x--; UpdatePlayerPosition(); } public void PlayerMoveRight() //プレイヤーの移動関数 { playerPos.x++; UpdatePlayerPosition(); } public void UpdatePlayerPosition() { Transform playerParent = dangionMap.transform.Find("Panel/player"); Vector3 playerOPos = playerParent.transform.position; Vector3 playerMapPos = new Vector3(); playerMapPos.x = (playerOPos.x - 200) + (playerPos.x * 100); playerMapPos.y = (playerOPos.y + 200) + (playerPos.y * -100); playerMapObject.transform.position = playerMapPos; } }
PlayerMoveDown,PlayerMoveUp,PlayerMoveLeft,PlayerMoveRightを先程作ったプレイヤー移動ボタン4方向にそれぞれ割り当てます。あとはプレイヤー画像をplayerSpriteに割り当てればとりあえず移動できるようになります。
(DangionMap.csも少し手を加えたので一応コードを載せておきます。)
クリックで展開
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class DangionMap : MonoBehaviour { public GameObject dangionMapSystem; DangionController dangionController; GameObject[,] roomImage = new GameObject[5,5]; //表示するroomImageの二次元配列 GameObject[,] eventIcons = new GameObject[5, 5]; //表示するイベントアイコンの二次元配列 int[,] structOfDangeon = new int[5,5]{ { 4, 1, 5, 4, 1 }, {14,12, 9,14,12 }, {14, 0, 0, 0,12 }, {14, 0, 0, 0,12 }, { 3,13, 0,13, 2 }, }; int[,] posOfEvent = new int[5, 5] { { -1,-1, 3,-1,-1 }, { 2,-1,-1,-1, 1 }, { 0,-1,-1,-1,-1 }, { -1,-1,-1, 2,-1 }, { -1,-1,-1,-1,-1 }, }; void Start() { this.gameObject.SetActive(false); dangionController = dangionMapSystem.GetComponent<DangionController>(); SetDangion(); SetEvent(); HideDangeonMap(); } public void ShowDangeonMap() { this.gameObject.SetActive(true); } public void HideDangeonMap() { this.gameObject.SetActive(false); //if (dangionController.isSetDangeonMap)//Dangeonがセットされていれば //{ // dangionController.isSetDangeonMap = false; //} } public void SetDangion() { dangionController.isSetDangeonMap = true; Transform parentRoomImage = transform.Find("Panel/roomImages"); Vector3 originPos = parentRoomImage.transform.position; Vector3 pos = new Vector3(originPos.x - 200, originPos.y - 200, 0); for(int j = 0; j < 5; j++) { for(int i = 0; i < 5; i++) { roomImage[j,i] = new GameObject("roomImage" + j + "_" +i); roomImage[j,i].transform.parent = parentRoomImage; Image image = roomImage[j, i].AddComponent<Image>(); image.sprite = dangionMapSystem.GetComponent<DangionData>().roomImages[structOfDangeon[j,i]]; pos.x = (originPos.x - 200) + (i * 100); pos.y = (originPos.y + 200) + (j * -100); roomImage[j, i].transform.position = pos; } } Transform playerParent = transform.Find("Panel/player"); Vector3 playerOPos = playerParent.transform.position; dangionController.playerMapObject = new GameObject("playerObj"); dangionController.playerMapObject.transform.parent = playerParent; Image playerimage = dangionController.playerMapObject.AddComponent<Image>(); playerimage.sprite = dangionController.playerSprite; playerimage.SetNativeSize(); Vector3 playerMapPos = new Vector3(); playerMapPos.x = (playerOPos.x - 200) + (dangionController.playerPos.x * 100); playerMapPos.y = (playerOPos.y + 200) + (dangionController.playerPos.y * -100); dangionController.playerMapObject.transform.position = playerMapPos; } public void DestroyMapInfo() { for (int j = 0; j < 5; j++) { for (int i = 0; i < 5; i++) { if(roomImage[j, i].gameObject != null) { Destroy( roomImage[j, i].gameObject); } if(eventIcons[j, i].gameObject != null) { Destroy(eventIcons[j, i].gameObject); } } } //Array.Clear(roomImage,0,roomImage.Length); //すべての要素をクリア } public void SetEvent() { Transform parentImageIcons = transform.Find("Panel/eventIcons"); Vector3 originPos = parentImageIcons.transform.position; Vector3 pos = new Vector3(originPos.x - 200, originPos.y - 200, 0); for (int j = 0; j < 5; j++) { for (int i = 0; i < 5; i++) { eventIcons[j, i] = new GameObject("eventIcon" + j + "_" + i); eventIcons[j, i].transform.parent = parentImageIcons; Image icon = eventIcons[j, i].AddComponent<Image>(); if(posOfEvent[j, i] != -1) { icon.sprite = dangionMapSystem.GetComponent<DangionData>().eventIcons[posOfEvent[j, i]]; icon.SetNativeSize(); } else { icon.color = new Color(1, 1, 1, 0); } pos.x = originPos.x - 200 + i * 100; pos.y = originPos.y + 200 + j * -100; eventIcons[j, i].transform.position = pos; } } } }
実行すると以下のようになります。
現状部屋の形状や範囲外でも関係なく動けてしまう状態です。現在の部屋から移動方向への移動が可能かどうかを判定する関数を作成します。最初にダンジョンの部屋数を定義しておきます
移動の可不可を判定する関数を以下のように定義します。
クリックで展開
public bool CheckCanMove(DIRECTION direction) { int beforemoveID = dangionMap.structOfDangeon[playerPos.y, playerPos.x]; //移動前の部屋の形状のID int aftermoveID; //移動後の部屋の形状のID bool a, b, c; //a:移動前の地形から移動可能か? //b:移動後の地形に移動可能か? //c:移動先が範囲外ではないか? //cを先に判定しないと配列の範囲外にアクセスしてしまう。 switch (direction) { case DIRECTION.Down: c = playerPos.y + 1 < dangion_height; if(!c)//範囲外なら { return false; //移動できない } aftermoveID = dangionMap.structOfDangeon[playerPos.y + 1, playerPos.x]; a = (beforemoveID == 0 || beforemoveID == 1 || beforemoveID == 4 || beforemoveID == 5 || beforemoveID == 9 || beforemoveID == 11 || beforemoveID == 12 || beforemoveID == 14); b = (aftermoveID == 0 || aftermoveID == 2 || aftermoveID == 3 || aftermoveID == 7 || aftermoveID == 9 || aftermoveID == 12 || aftermoveID == 13 || aftermoveID == 14); if (a && b) { return true; } else { return false; } case DIRECTION.Up: c = playerPos.y - 1 >= 0; if (!c)//範囲外なら { return false; //移動できない } aftermoveID = dangionMap.structOfDangeon[playerPos.y - 1, playerPos.x]; a = (beforemoveID == 0 || beforemoveID == 2 || beforemoveID == 3 || beforemoveID == 7 || beforemoveID == 9 || beforemoveID == 12 || beforemoveID == 13 || beforemoveID == 14); b = (aftermoveID == 0 || aftermoveID == 1 || aftermoveID == 4 || aftermoveID == 5 || aftermoveID == 9 || aftermoveID == 11 || aftermoveID == 12 || aftermoveID == 14); if (a && b) { return true; } else { return false; } case DIRECTION.Left: c = playerPos.x - 1 >= 0; if (!c)//範囲外なら { return false; //移動できない } aftermoveID = dangionMap.structOfDangeon[playerPos.y, playerPos.x - 1]; a = (beforemoveID == 0 || beforemoveID == 1 || beforemoveID == 2 || beforemoveID == 6 || beforemoveID == 10 || beforemoveID == 11 || beforemoveID == 12 || beforemoveID == 13); b = (aftermoveID == 0 || aftermoveID == 3 || aftermoveID == 4 || aftermoveID == 8 || aftermoveID == 10 || aftermoveID == 11 || aftermoveID == 13 || aftermoveID == 14); if (a && b) { return true; } else { return false; } case DIRECTION.Right: c = playerPos.x + 1 < dangion_width; if (!c)//範囲外なら { return false; //移動できない } aftermoveID = dangionMap.structOfDangeon[playerPos.y, playerPos.x + 1]; a = (beforemoveID == 0 || beforemoveID == 3 || beforemoveID == 4 || beforemoveID == 8 || beforemoveID == 10 || beforemoveID == 11 || beforemoveID == 13 || beforemoveID == 14); b = (aftermoveID == 0 || aftermoveID == 1 || aftermoveID == 2 || aftermoveID == 6 || aftermoveID == 10 || aftermoveID == 11 || aftermoveID == 12 || aftermoveID == 13); if (a && b) { return true; } else { return false; } default: return false; } }
この関数は移動前と移動後のプレイヤーの座標を使って、それぞれの部屋の形状を取得し、取得した部屋の形状が移動前から移動方向を通行できるか、移動後の部屋に移動方向から通行できるかをそれぞれ判定し、両方trueの場合にtrueを返すようになっています。ダンジョンの範囲外かどうかも判定しています。通行可能かどうかの判定方法はイカの画像のとおりです。
この処理を画像ごとに一つ一つ条件式にしていきます。あとはプレイヤーの移動の時にこの関数が返すbool値で実際に移動するかどうかを決めます。
クリックで展開
public void PlayerMoveDown() //プレイヤーの移動関数 New { bool canMove = CheckCanMove(DIRECTION.Down); if (canMove) { playerPos.y++; } else { SoundManager.instance.PlaySE(18); } UpdatePlayerPosition(); } public void PlayerMoveUp() //プレイヤーの移動関数 { bool canMove = CheckCanMove(DIRECTION.Up); if (canMove) { playerPos.y--; } else { SoundManager.instance.PlaySE(18); } UpdatePlayerPosition(); } public void PlayerMoveLeft() //プレイヤーの移動関数 { bool canMove = CheckCanMove(DIRECTION.Left); if (canMove) { playerPos.x--; } else { SoundManager.instance.PlaySE(18); } UpdatePlayerPosition(); } public void PlayerMoveRight() //プレイヤーの移動関数 { bool canMove = CheckCanMove(DIRECTION.Right); if (canMove) { playerPos.x++; } else { SoundManager.instance.PlaySE(18); } UpdatePlayerPosition(); }
これで実行すると以下のようになります。
これで部屋の形状に応じてプレイヤーの移動を制限することができました。次回は探索中のイベントを制作していきたいと思います。