まるコットでメモ的な何か

ゲームのフラグ管理を考える

使い勝手のいいフラグ管理方法を考えたい。

要件

  • シングルトンでフラグを管理するクラス
  • インスペクタでフラグの状態がすぐに分かる
  • <enum, bool> なDictionary変数でフラグ情報の保持

やること

インスペクタでDictionaryを見るためにSerializableDictionary アセットをインポートする

このアセットの SerializableDictionary Exampleシーンを元にする。

追加するファイル

MyFlagManager.csを追加

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

public class MyFlagManager : MonoBehaviour
{
    private static MyFlagManager instance = null;
    public static MyFlagManager Instance
    {
        get
        {
            if (instance == null)
            {
                instance = FindObjectOfType<MyFlagManager>();

                if (instance == null)
                {
                    instance = new GameObject("MyFlagManager").AddComponent<MyFlagManager>();
                }
            }
            return instance;
        }
    }

    void Awake()
    {
        if (Instance == this)
        {
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            Destroy(gameObject);
        }
    }

    [SerializeField]
    FlagBoolDictionary m_enumBoolDictionary;
    public IDictionary<Flag, bool> EnumBoolDictionary
    {
        get { return m_enumBoolDictionary; }
        set { m_enumBoolDictionary.CopyFrom(value); }
    }

    private void Start()
    {
        ResetFlags();
    }

    void Reset()
    {
        ResetFlags();
    }

    void ResetFlags()
    {
        EnumBoolDictionary.Clear();
        foreach (var i in Enum.GetValues(typeof(Flag)).Cast<Flag>())
        {
            EnumBoolDictionary.Add(i, false);
        }
    }

    public enum Flag
    {
        Key1,
        Key2,
        Key3,
    }
}

InstanceとかAwakeとかはシングルトンのための設定。

Start()でEnumの要素でDictionaryを初期化しているけど無くても良さそう。(実行時にどんなフラグがあるかがインスペクタから一覧で見えて便利というだけ)

Enum Flagに管理したいフラグをどんどん追加していく。

MyExample.csを追加

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

public class MyExample : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        bool a = MyFlagManager.Instance.EnumBoolDictionary[MyFlagManager.Flag.Key1];
        Debug.Log(a);
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            MyFlagManager.Instance.EnumBoolDictionary[MyFlagManager.Flag.Key2] = true;
        }
    }
}

MyFlagManagerの動作確認用のスクリプト。

MyFlagManager.csとMyExample.csを適当なオブジェクトにアタッチ。

編集するファイル

UserSerializableDictionaries.csに以下の行を追加

[Serializable]
public class FlagBoolDictionary : SerializableDictionary<MyFlagManager.Flag, bool> {}

UserSerializableDictionaryPropertyDrawers.csに以下の行を追加

[CustomPropertyDrawer(typeof(FlagBoolDictionary))]

実行

スペースキーを押すとKey2がTrueに変わるはず。

file

補足

MyFlagManagerをアタッチした際になぜかDictionaryのsetterの部分でエラーが出る。

NullReferenceException: Object reference not set to an instance of an object
MyFlagManager.ResetFlags () (at Assets/SerializableDictionary/Example/MyFlagManager.cs:59)
MyFlagManager.Reset () (at Assets/SerializableDictionary/Example/MyFlagManager.cs:54)
UnityEditorInternal.InternalEditorUtility:HierarchyWindowDragByID(Int32, HierarchyDropMode, Transform, Boolean)
UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr, Boolean&)

そのためアタッチ時の Reset() によるインスペクタへの値の反映がうまく効かない。

ほぼ見た目の問題なので、気になるならアタッチしたオブジェクトのインスペクタからMyFlagManagerのResetを選択してDictionaryのリセットを掛ける。

file

参考:

One thought on “ゲームのフラグ管理を考える

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です