サイトアイコン RのWeb制作

C#(Unity) 2D障害物ゲームのマップをインスペクタから作成・設定する例

知りたい方がいらっしゃったので書いてみました。
インスペクタから設定できると、データベース不要で簡単に複数マップを作成・管理できるところが良いところだと思います。

設定ファイルの作成

MapSetting.csとして、以下のファイルを作成します。

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// -----------------------------------------//
// マップ本体
// -----------------------------------------//
[Serializable]
public class MapData
{
    // -------------------------------------------//
    // 基礎
    // -------------------------------------------//
    [SerializeField] string id = ""; // マップID:同一のものは作らないこと
    public string Id{ get{ return id; } }
    [SerializeField] string name = "マップ名";
    public string Name{ get{ return name; } }
    [SerializeField] Sprite imageBackground; // 背景画像
    public Sprite ImageBackground{ get{ return imageBackground; } }
    [SerializeField] int pxWidth = 100; // マップの大きさ(横)
    public int PxWidth{ get{ return pxWidth; } }
    [SerializeField] int pxHeight = 200; // マップの大きさ(縦)
    public int PxHeight{ get{ return pxHeight; } }

    // -------------------------------------------//
    // スタート・ゴール・障害物関係
    // -------------------------------------------//
    // スタート位置
    [SerializeField] MapPositionData posStart;
    public MapPositionData PosStart{ get{ return posStart; } }
    // ゴール位置
    [SerializeField] MapPositionData posGoal;
    public MapPositionData PosGoal{ get{ return posGoal; } }
    // 障害物位置(障害物が1種類なら)
    [SerializeField] List<MapPositionData> listPosHurdle;
    public List<MapPositionData> ListPosHurdle{ get{ return listPosHurdle; } }

    // -------------------------------------------//
    // メソッド
    // -------------------------------------------//
}

// 位置データ(2D)
[Serializable]
public class MapPositionData
{
    [SerializeField] int posX = 0; // X座標
    public int PosX{ get{ return posX; } }
    [SerializeField] int posY = 0; // Y座標
    public int PosY{ get{ return posY; } }
}

// -----------------------------------------//
// 設定用ファイル
// -----------------------------------------//
[CreateAssetMenu()]
[Serializable]
public class MapSetting : ScriptableObject 
{
    [SerializeField] List<MapData> listData;
    // -----------------------------------------//
    // メソッド
    // -----------------------------------------//
    public List<MapData> GetData()
    {
        return listData;
    }
}
// -----------------------------------------//

Scriptable Objectの作成

プロジェクト画面から、右クリック > 作成 > MapSettingで作成します。

Scriptable Objectの調整

Scriptable Objectを選択すると、以下のように設定ができるようになります。
マップを増やすのは+/-で調整可能です。

マップデータ呼び出し用ファイルの作成

マップデータを呼び出す例となるファイルを作成します。
実際に使う場合はインスペクタから、mapSettingにMapSettingファイル(上記で設定したもの)や各種GameObjectをアタッチしてください。
唐突にオブジェクトプールやPrefabという概念が出てきます。そちらは自分で調べるかChatGPTに聞いてみるとよいでしょう。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MapRead : MonoBehaviour
{
    // マップデータ
    [SerializeField] MapSetting mapSetting;
    List<MapData> listMapData;

    // オブジェクト(各々アタッチが必要。これらのObjectは開始時・マップ変更時は非アクティブに設定。)
    [SerializeField] GameObject objPlayer; // キャラクター
    [SerializeField] GameObject objGoal; // ゴール
    [SerializeField] List<GameObject> listObjHurdle; // 障害物(オブジェクトプールのように使用)
    [SerializeField] GameObject prfHurdle; // 障害物のPrefabをアタッチ(新規にGameObjectを生成するために使用)

    // ロード
    void Awake()
    {
        listMapData = mapSetting.GetData();
    }

    // 初期設定
    void Start()
    {
        ReadMapData();
    }

    // マップデータ読み込み
    void ReadMapData()
    {
        MapData mapData = listMapData.Find(x => x.Id == "マップID");

        // マップの大きさ設定
        // SetMapSize(mapData.PxWidth, mapData.PxHeight); // 同様に設定してみてください

        // スタート・ゴール位置の設定
        SetMapStart(mapData.PosStart);
        SetMapGoal(mapData.PosGoal);

        // 障害物を設置
        // SetMapHurdle(mapData.ListPosHurdle); // スタート・ゴールを設定できたら、コメントアウトを外して試してみてください
    }

    // 開始位置設定
    void SetMapStart(MapPositionData mapPos)
    {
        objPlayer.transform.position = new Vector3(mapPos.PosX, mapPos.PosY, 0f);
        // 表示ON
        objPlayer.SetActive(true);
    }

    // ゴール位置設定
    void SetMapGoal(MapPositionData mapPos)
    {
        objGoal.transform.position = new Vector3(mapPos.PosX, mapPos.PosY, 0f);
        // 表示ON
        objGoal.SetActive(true);
    }

    // 障害物設定
    void SetMapHurdle(List<MapPositionData> listMapPos)
    {
        // 現状のObjを全て非表示にする
        foreach(GameObject objHurdle in listObjHurdle) objHurdle.SetActive(false);

        // 表示するオブジェクト・位置を設定
        for(int i=0; i<listMapPos.Count; i++)
        {
            // 一時Obj
            GameObject objTemp = null;

            // listObjHurdleの個数を把握
            if(listObjHurdle.Count <= i) // 不足する場合
            {
                objTemp = Instantiate(prfHurdle); // prfHurdleを元にオブジェクトを新規生成
                objTemp.SetActive(false); // とりあえず非表示にしておく
                listObjHurdle.Add(objTemp); // オブジェクトプールリストに追加
            }
            else // 充足している場合
            {
                objTemp = listObjHurdle[i];
            }

            // 配置・表示
            MapPositionData mapPos = listMapPos[i];
            objTemp.transform.position = new Vector3(mapPos.PosX, mapPos.PosY, 0f);
            objTemp.SetActive(true);
        }
    }
}

コメント

マップを複数に増やすには、データ作成→管理用UI作成→マップ作成→…と、非常に面倒だったので、管理用UIを作成せずに楽に作れるよう設計しました。
もし「こうした方がいいよ」というのがあれば教えてください。

モバイルバージョンを終了