Unity:ステージ作成と移動(ローグライクを自分なりの解釈で作ってみる)
完成画像
概要
- ローグライクで使えそうなステージを作り,ステージ内をPlayerで移動する.
- 移動は1マスずつ.
- マップは配列で作成する.
- 壁には移動できないようにすること
仕様
今回私が作るローグライクゲームでは複数のレイヤーを重ねてステージを作ります.
こうすることによってステージの床の上にトラップが仕掛けられていて,その上にアイテムが落ちていることを階層的に再現することが出来ます.
ステージレイヤーとプレイヤーレイヤーの生成
ステージレイヤーとプレイヤーレイヤーの2つの配列を作ってみます
ステージ配列
0:床 1:壁
// ステージ多次元配列 public int[,] stageArray = new int[10, 10]{ {1,1,1,1,1,1,1,1,1,1}, {1,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,1}, {1,1,1,1,1,1,1,1,1,1} };
プレイヤー配列
0:特になし 2:プレイヤー
public int[,] playerArray = new int[10, 10]{ {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,2,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0} };
この情報をもとにマップを生成してみます.
マップ生成コード
for (int i = 0; i < stageArray.GetLength(0); i++) { for (int j = 0; j < stageArray.GetLength(1); j++) { if (stageArray[i,j] == 0) { Instantiate(floorBlock, new Vector3(i, -1, j), Quaternion.identity); } else { Instantiate(wallBlock, new Vector3(i, 0, j), Quaternion.identity); } } }
それぞれの要素の場所自体がUnity内の座標とを同期させてあげています.
なのでStage配列の1-6番目の要素はX:6,Y:6のpositionということになります.
あとはその場所にCubeを生成してあげれば完了です
私がここで詰まったところ。
ものすごくお恥ずかしいのですが多次元配列の,要素数を取得する方法を知りませんでした. 純粋な配列の場合は
array.Length;
で問題ないのですが,多次元配列の場合は下記のように取得することが出来ます
array.GetLength(hoge);
こういう小さいことからちゃんとツメていきたいですね....
キャラクタの移動
ユーザーの入力に反応
今回はASDWKEYに対応して移動させます.
void Update(){ int moveX; int moveZ; // Keyによってプレイヤーが相対的に何処に移動するかを指定する if (Input.GetKeyDown(KeyCode.A)) { moveX = -1; moveZ = 0; UpdatePlayerPosition(moveX, moveZ); } else if (Input.GetKeyDown(KeyCode.D)) { moveX = 1; moveZ = 0; UpdatePlayerPosition(moveX, moveZ); } else if (Input.GetKeyDown(KeyCode.W)) { moveX = 0; moveZ = 1; UpdatePlayerPosition(moveX, moveZ); } else if (Input.GetKeyDown(KeyCode.S)) { moveX = 0; moveZ = -1; UpdatePlayerPosition(moveX, moveZ); } else{ moveX = 0; moveZ = 0; UpdatePlayerPosition(moveX, moveZ); } }
KeyDownを検知次第,Playerを相対的に何処に移動するかを決めます.
その後UpdatePlayerPositionに値を渡して移動を開始します
UpdatePlayerPosition
プレイヤーのポジション取得
プレイヤーがどこにいるかを配列から探してきます
int playerPositionX = 0; int playerPositionZ = 0; //プレイヤーの現在の一を取得する for (int i = 0; i < playerArray.GetLength(0); i++) { for (int j = 0; j < playerArray.GetLength(1); j++) { if (playerArray[i, j] == 2) { playerPositionX = i; playerPositionZ = j; } } }
壁判定と配列更新と移動
一気に3つ書くのはどうかと思いますがこれらは絡みまくってるので一気にまとめてかいちゃいます
// 移動先が壁だった場合はreturnそれ以外の場合はプレイヤーをitweenによって移動させ,配列を更新する. if (stageArray[playerPositionX + moveX, playerPositionZ + moveZ] == 1) { Debug.Log("壁"); return; } else { playerArray[playerPositionX, playerPositionZ] = 0; playerArray[playerPositionX + moveX, playerPositionZ + moveZ] = 2; Hashtable moveHash = new Hashtable(); Debug.Log(playerPositionX); moveHash.Add("position", new Vector3(playerPositionX, transform.position.y, playerPositionZ)); moveHash.Add("time", 0.4f); moveHash.Add("delay", 0.0f); iTween.MoveTo(player, moveHash); }
壁判定
if (stageArray[playerPositionX + moveX, playerPositionZ + moveZ] == 1) { Debug.Log("壁"); return; } else {
現在のプレイヤーPositionの周りに壁がないかStage配列から調べます.
プレイヤーの配列の更新
移動先の配列要素を2(プレイヤー)に変更して,移動前の配列要素を0にします
playerArray[playerPositionX, playerPositionZ] = 0; playerArray[playerPositionX + moveX, playerPositionZ + moveZ] = 2;
プレイヤーの移動
プレイヤーの移動にはiTweenを利用します
Hashtable moveHash = new Hashtable(); moveHash.Add("position", new Vector3(playerPositionX + moveX, transform.position.y, playerPositionZ+ moveZ)); moveHash.Add("time", 0.4f); moveHash.Add("delay", 0.0f); iTween.MoveTo(player, moveHash);
ざっと説明すると
moveHash.Add("position"......では実際に移動する先のpositionを入力します
moveHash.Add("time".....では移動にかかる時間を指定
moveHash.Add("delay"......では移動開始までにかかる時間を指定
最後のiTween.MoveTo(player,moveHash)により,プレイヤーを動作させます.