【Unity3D】自動生成する不思議なダンジョンの作り方②「3Dマップ作成」

2022年8月26日

どうも、だらはです。
前回に引き続き、自動生成する不思議なダンジョンの作り方を紹介していきます。
今回は、3Dマップの作り方です!

スポンサーリンク

概要

記事が長くなると思うので先ずは完成図目次を示します。
目次の順番で自動生成する不思議なダンジョンを作成していきます。

◆完成図

◆目次

  1. 2Dマップを生成する。
  2. 2Dマップをもとに3Dマップを作成する。←今ココ!
  3. キャラクタやアイテムを初期配置する。
  4. 時間経過で敵を生成する。
  5. 現在位置マップを作成する。

②2Dマップをもとに3Dマップを作成する。

先ずは階層設定です。
以下の通りにGameObjectを作成し、適宜設定をしてください。
文字より画面キャプチャを見た方が早いかもしれません。

  1. [Hierarchy->3D Object->Terrain]よりTerrainを作成する。
    • Position(x,y,z)=(0,0,0)に(Width,Length)=(50, 50)の設定で作成。
  2. 空のGameObjectを作成してStageMakeと命名する。
    • [NavMeshSurface][ElementGenerator.cs](後述)をアタッチ。
    • [DungeonGenerator.cs]をアタッチし、(Width,Height,RoomSettings)=(50,50,10,10,2,5)と設定する。
  3. 空のGameObjectを作成してWallと命名する。
  4. 空のGameObjectを作成してPlayerと命名する。
    • TagPlayerに設定する。
  5. [Hierarchy->UI->Canvas]よりCanvasを作成する。
    • 子に空のGameObjectを作成してMap2Dと命名し、RectTransformをアタッチする。

◆参考となる画面キャプチャ

◆StageMakeにアタッチする[ElementGenerator.cs]

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.UI;

public class ElementGenerator : MonoBehaviour
{
    //リソース格納用 (階層またぎのセーブ/ロードで使用)
    Material material;                                              //壁のマテリアル
    GameObject objGoal;                                             //ゴール
    GameObject[] objMapTipList = new GameObject[1];                 //マップチップリスト

    //2Dマップ生成スクリプト用
    DungeonGenerator dungeonGenerator;
    int[,] map;

    //パス読み込み用
    GameObject objMap2D;                                            //Map2D

    //生成したマップチップ
    GameObject[,] objMapExist;                                      //フィールド用

    void Awake()
    {
        //リソース読み込み
        ReadResources();

        //壁を生成
        GenerateWall();

        //二次元マップ生成
        GenerateMap2D(map);
    }

    //リソース読み込み
    void ReadResources()
    {
        //壁のマテリアル
        material = (Material)Resources.Load("Material/StoneSurface_edit");

        //ゴール
        objGoal = (GameObject)Resources.Load("Prefab/Stage/Goal_Light");

        //2Dのマップチップ読み込み
        objMapTipList[0] = (GameObject)Resources.Load("Prefab/Map2D/MapTip");
    }

    //壁を生成
    void GenerateWall()
    {
        //ダンジョンマップ
        dungeonGenerator = GetComponent<DungeonGenerator>();

        //壁の高さ
        float blockHeight = 4f;

        //2Dマップ生成
        map = dungeonGenerator.Generate();

        //生成する壁の親となるGameObject
        GameObject objWall = GameObject.Find("Wall");

        //自動生成したマップにCubeを配置
        for (int i = 0; i < map.GetLength(0); i++)
        {
            for (int j = 0; j < map.GetLength(1); j++)
            {
                //壁をCubeで作成
                if (map[i, j] == 0)
                {
                    for (int k = 0; k < blockHeight; k++)
                    {
                        GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);

                        //Wall直下に階層を移動
                        cube.transform.parent = objWall.transform;
                        cube.GetComponent<Renderer>().material = material;
                        cube.transform.localScale = new Vector3(1, 1, 1);
                        cube.transform.position = new Vector3(i, k + 0.5f, j);
                    }
                }
            }
        }
        GetComponent<NavMeshSurface>().BuildNavMesh();
    }

    //二次元マップ生成
    void GenerateMap2D(int[,] map)
    {
        objMap2D = GameObject.Find("Map2D").gameObject;
        objMapExist = new GameObject[map.GetLength(0), map.GetLength(1)];

        //map[x,y]のパラメタ:0:壁、1:部屋、2:通路、10:プレイヤーが居る部屋
        for (int i = 0; i < 50; i++)
        {
            for (int j = 0; j < 50; j++)
            {
                objMapExist[i, j] = Instantiate(objMapTipList[0]);

                //Map2D直下に階層を移動
                objMapExist[i, j].transform.parent = objMap2D.transform;
                objMapExist[i, j].transform.localScale = new Vector3(1, 1, 1);

                //マップの位置調整 (MapTipの幅が5fのため)
                Vector2 vector2 = new Vector2(2.5f + 5f * i, 2.5f + 5f * j);
                objMapExist[i, j].GetComponent<RectTransform>().anchoredPosition = vector2;

                //初期状態では非表示
                Color color = objMapExist[i, j].GetComponent<Image>().color;
                color.a = 0;
                objMapExist[i, j].GetComponent<Image>().color = color;

                /*
                if ((map[i, j] == 1) || (map[i, j] == 2))
                {
                    //2Dマップ生成のデバッグ用
                    if ((map[i, j] == 1))
                    {
                        objMapExist[i, j].GetComponent<Image>().color = new Color(1, 0, 0, 0.5f);
                    }
                    else if ((map[i, j] == 2))
                    {
                        objMapExist[i, j].GetComponent<Image>().color = new Color(0, 1, 0, 0.5f);
                    }
                }
                */
            }
        }
    }
}

補足①「2Dマップ生成のデバッグ用」

「2Dマップ生成のデバッグ用」と記載がある部分のコメントアウトを外すと、Game画面にマップが表示されるようになります。
プレイヤーが部屋に入るとマップが表示される使用を想定しているため、マップはデフォルトでは非表示です。
表記の通り、デバッグにお使い頂けたらと思います。

補足②「Resources」

今回はMaterialやマップチップなどはResourcesから読み込む仕様にしています。
今回は私のプロジェクトのパス設定をそのまま記載してあるため、適宜書き換えてご利用ください。

補足③「マップチップの大きさ」

今回のスクリプトでは、マップチップの大きさ(Width, Height)を5と想定しています。
なので、GenerateMap2D()では上記サイズを考慮して位置調整を行っています。

補足④「NavMeshSurface」

本スクリプトではNavMeshAgentの経路を動的にベイクしています。
以下の記事でNavMeshSurfaceの使い方をまとめていますので、参考にして頂けたらと思います。

◆【Unity】NavMeshAgentの経路を動的にベイクする方法

最後に

いかがでしたでしょうか。
今回は、2Dマップをもとに3Dマップを作成してきました。
もし不明点等ありましたらお気軽にコメント頂けると嬉しいです。
シェアして頂けるともっと嬉しいです:)

◆次回「キャラやアイテムの初期配置」

以上、だらはでした。

スポンサーリンク

応用

Posted by daraha_gm