![見出し画像](https://assets.st-note.com/production/uploads/images/24159508/rectangle_large_type_2_fa775b58269cd58898b9ddc2d9e7f1de.png?width=1200)
【Unity】3Dローグライクゲームの作り方〜Step4-2〜
前回の記事はこちら。
前回はArray2Dクラスを実装し、PlayerMovementのメソッドを整理するところまでを行いました。
壁のオブジェクトを作成する
最初にUnityエディターで壁のオブジェクトを作成することから始めようと思います。
ヒエラルキータブ内で右クリック→「3D オブジェクト」→「キューブ」をクリックして、名前を「Wall」にして下さい。
それができたら、Wallの位置を全て0にしましょう。
ボックスコライダーコンポーネントは削除してもらって構いません。
下の画像のWallはサイズが「2」になっていますが、これも初期値で大丈夫です。
また、お好みでWallの色を変えてもいいと思います。
全て終わったら、プロジェクトタブ内のPrefabsフォルダにWallオブジェクトをドラッグアンドドロップして、ヒエラルキータブ内のWallは削除して下さい。
後、作成したWallを纏める空のオブジェクト「Walls」も作成しておくといいでしょう。Floor配下に置いて下さい。
Fieldクラスの実装その2
※2020/7/24追記(7/26更新)
Fieldクラスに以下のパラメーターを追加して下さい。
public GameObject floor;
public GameObject wall;
private Array2D map;
private const float oneTile = 2.0f;
private const float floorSize = 10.0f / oneTile;
(ご指摘頂くまで気付きませんでした......。本当に申し訳ないです!)
それではFieldクラスに新しいメソッドを追加しましょう。以下のコードをFieldクラスに加えて下さい。
ついでに、ToWorldX、ToWorldZ、ToGridX、ToGridZの「2」の値を「oneTile」に置き換えておくと後々便利になります。
/**
* マップデータの生成
*/
public void Create(Array2D mapdata)
{
map = mapdata;
float floorw = map.width / floorSize;
float floorh = map.height / floorSize;
floor.transform.localScale = new Vector3(floorw, 1, floorh);
for (int z = 0; z < map.height; z++)
{
for (int x = 0; x < map.width; x++)
{
if (map.Get(x, z) > 0)
{
GameObject block = Instantiate(wall);
float xblock = ToWorldX(x);
float zblock = ToWorldZ(z);
block.transform.localScale = new Vector3(oneTile, 2, oneTile);
block.transform.position = new Vector3(xblock, 1, zblock);
block.transform.SetParent(floor.transform.GetChild(0));
}
}
}
}
/**
* 生成したマップのリセット
*/
public void Reset()
{
Transform walls = floor.transform.GetChild(0);
for (int i = 0; i < walls.childCount; i++)
{
Destroy(walls.GetChild(i).gameObject);
}
}
/**
* 指定の座標が壁かどうかをチェック
*/
public bool IsCollide(int xgrid, int zgrid)
{
return map.Get(xgrid, zgrid) != 0;
}
Createメソッドは与えられたマップデータを元に床のサイズを変更し、壁を配置します。
Resetメソッドはマップをリセットします。現状は壁のみを削除します。
IsCollideメソッドは、指定した座標が壁(≠0)であるかを判定します。
テストしてみましょう。
Fieldオブジェクトにこのスクリプトをアタッチして、Floorパラメーターに階層下のFloorを、Wallパラメーターに先ほど作成したWallオブジェクトをドラッグ&ドロップします。
そして、Fieldクラスに以下のメソッドを書きます。
void Start()
{
Array2D mapdata = new Array2D(10, 10);
mapdata.Set(1, 1, 1);
Create(mapdata);
}
テストプレイをすると、以下のようになるはずです。
無事、壁が描画できました。しかし位置がおかしい気がします。
それは床も含めて全て中央揃えになっている為に起こっています。せめて床をずらしましょう。
public void Create(Array2D mapdata)
{
map = mapdata;
float floorw = map.width / floorSize;
float floorh = map.height / floorSize;
floor.transform.localScale = new Vector3(floorw, 1, floorh);
// 次の3行を追記
float floorx = (map.width - 1) / 2.0f * oneTile;
float floorz = (map.height - 1) / 2.0f * oneTile;
floor.transform.position = new Vector3(floorx, 0, floorz);
/* 省略 */
}
(オプション)角度の調整
もし、壁とユニティちゃんの位置関係もおかしい気がすると思ったら、それも調節します。DirUtilスクリプトを開いて下さい。
public static Quaternion DirToRotation(EDir d)
{
Quaternion r = Quaternion.Euler(0, 0, 0);
switch (d)
{
case EDir.Left:
r = Quaternion.Euler(0, 90, 0); break;
case EDir.Up:
r = Quaternion.Euler(0, 180, 0); break;
case EDir.Right:
r = Quaternion.Euler(0, 270, 0); break;
case EDir.Down:
r = Quaternion.Euler(0, 0, 0); break;
}
return r;
}
public static EDir RotationToDir(Quaternion r)
{
float y = r.eulerAngles.y;
if (y < 45)
{
return EDir.Down;
}
else if (y < 135)
{
return EDir.Left;
}
else if (y < 225)
{
return EDir.Up;
}
else if (y < 315)
{
return EDir.Right;
}
return EDir.Down;
}
public static Pos2D GetNewGrid(Pos2D position, EDir d)
{
Pos2D newP = new Pos2D();
newP.x = position.x;
newP.z = position.z;
switch (d)
{
case EDir.Left:
newP.x += 1; break;
case EDir.Up:
newP.z -= 1; break;
case EDir.Right:
newP.x -= 1; break;
case EDir.Down:
newP.z += 1; break;
}
return newP;
}
上記のように、左と右、上と下の値を逆にして下さい。
そして、カメラの位置を調節すると......
こんな感じになります。
ところで、気付いた方もいらっしゃると思いますが、今のままだとユニティちゃんが壁にめり込んでしまいます。明日はそれを修正したいと思います。
この記事が気に入ったらサポートをしてみませんか?