見出し画像

【Unity】3Dローグライクゲームの作り方〜Step4-2〜

前回の記事はこちら
前回はArray2Dクラスを実装し、PlayerMovementのメソッドを整理するところまでを行いました。

壁のオブジェクトを作成する

最初にUnityエディターで壁のオブジェクトを作成することから始めようと思います。
ヒエラルキータブ内で右クリック→「3D オブジェクト」→「キューブ」をクリックして、名前を「Wall」にして下さい。
それができたら、Wallの位置を全て0にしましょう。
ボックスコライダーコンポーネントは削除してもらって構いません。
下の画像のWallはサイズが「2」になっていますが、これも初期値で大丈夫です。

スクリーンショット 2020-04-28 16.32.13

また、お好みで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);
}

テストプレイをすると、以下のようになるはずです。

スクリーンショット 2020-04-28 17.59.11

無事、壁が描画できました。しかし位置がおかしい気がします。
それは床も含めて全て中央揃えになっている為に起こっています。せめて床をずらしましょう。

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;
}

上記のように、左と右、上と下の値を逆にして下さい。
そして、カメラの位置を調節すると......

スクリーンショット 2020-04-28 18.49.27

こんな感じになります。

ところで、気付いた方もいらっしゃると思いますが、今のままだとユニティちゃんが壁にめり込んでしまいます。明日はそれを修正したいと思います。

この記事が気に入ったらサポートをしてみませんか?