【UnityAsset】MVVM 4 uGUI – デモ

2015/11/07

【AssetStore】MVVM 4 uGUI
【UnityAsset】MVVM 4 uGUI – uGUIにMVVM(Model-View-ViewModel)パターンを導入
【GitHub】M4uDemo ←本記事のプロジェクト(※M4uをインポートしないとエラーが出ます)

ここではM4uの使用方法を説明します。
M4uがどんなAssetかは【UnityAsset】MVVM 4 uGUI – uGUIにMVVM(Model-View-ViewModel)パターンを導入をご覧下さい。

TextBinding(s)
ImageBinding
RawImageBinding
ActiveBinding
EnableBinding
TransformBinding、TransformLocalBinding
ColorBinding
CollectionBinding
EventBinding(s)
ToggleBinding
InputFieldBinding(s)
ScrollbarBinding
SliderBinding
SpecialBinding(s)

スポンサーリンク
  

はじめに

まずはuGUIにデータをバインドするための準備です。自分が普段行っているやり方を紹介します。

1. M4uContextの作成

M4uContextを継承したクラスを作成します。このクラスがルートオブジェクトなります(このクラスのデータをバインドオブジェクトが参照する)。
M4uContextは複数作ることも可能ですが、ルートオブジェクトが増えすぎると分かりづらくなるので、自分は基本この1クラスで管理しています。
MonoBehaviourを使用したい場合はM4uContextの代わりにM4uContextMonoBehaviourをご使用下さい。

namespace M4u.Demo
{
    public class App : M4uContext
    {
        public static readonly App Instance = new App();
    
        private App() { }
    }
}

2. Demoクラスの作成

シーン内で処理されるDemoクラスを作成し、Appクラスに参照させます。

using UnityEngine;

namespace M4u.Demo
{
	public class Demo : MonoBehaviour
	{
		void Awake()
		{
			App.Instance.Demo = this;
		}
	}
}
namespace M4u.Demo
{
    public class App : M4uContext
    {
        public static readonly App Instance = new App();

        public Demo Demo { get; set; }
    
        private App() { }
    }
}

3. M4uContextRootの設定

GameObjectを作成し、そこにDemoクラスと[Component/M4u/ContextRoot]を設定します。
M4uContextRootのContextプロパティにAppクラスを設定します。
M4uContextRootは複数作ることも可能です。

以上で、M4uContextRoot(Demo)配下のGameObjectに対して、Appクラスのデータを関連づけさせる準備が整いました。

using UnityEngine;

namespace M4u.Demo
{
	public class Demo : MonoBehaviour
	{
		void Awake()
		{
			App.Instance.Demo = this;
			GetComponent<M4uContextRoot>().Context = App.Instance;
		}
	}
}

4. Hierarchyアイコン

[Tools/M4u/Show Hierarchy Icon]を選択することで、Hierarchy上にバインドアイコンが表示されるようになります。バインドオブジェクトが増えていくと迷子になりがちなので設定しておくと便利です。

5. バインドフローエディタ

[Tools/M4u/Open BindFlow]を選択することで、現在のバインド状況が確認出来ます。

TextBinding(s)

Textへのバインディング
バインドイメージ)Text.text = string.Format (Format, Path);

 プロパティ
 Path M4uContextRoot.Context内にあるデータへのパス
型:string
 Format テキストフォーマット。string.Formatと同じ使い方。
using UnityEngine;

namespace M4u.Demo
{
	public class Demo : MonoBehaviour
	{
		M4uProperty<string> message = new M4uProperty<string>("");

		public string Message { get { return message.Value; } set { message.Value = value; } } 

		void Awake()
		{
			App.Instance.Demo = this;
			GetComponent<M4uContextRoot>().Context = App.Instance;
		}

		public void OnUpdate()
		{
            Message = Random.Range (1, 100).ToString();
		}
	}
}

・スクリプトを上記のように修正
・uGUIのButtonとTextを追加し、Button.onClickにDemo.OnUpdateを設定
・Textに[Component/M4u/TextBinding]を追加し、プロパティを動画のように設定

この状態で実行してみると、ボタンをクリックする度にテキストが更新されていることが分かると思います。
データの更新のみでUI(View)の値が自動的に変更されています。

末尾に s が付いているもの(TextBindings等)は複数データのバインド用です。出来ることは変わりません。

ImageBinding

Imageへのバインディング
バインドイメージ)Image.sprite = Path;

 プロパティ
 Path M4uContextRoot.Context内にあるデータへのパス
型:Sprite
using UnityEngine;

namespace M4u.Demo
{
	public class Demo : MonoBehaviour
	{
		public Sprite[] SpriteData;

		M4uProperty<Sprite> sprite = new M4uProperty<Sprite>();
		int spriteIdx;

		public Sprite Sprite { get { return sprite.Value; } set { sprite.Value = value; } }

		void Awake()
		{
			App.Instance.Demo = this;
			GetComponent<M4uContextRoot>().Context = App.Instance;
		}

		public void OnUpdate()
		{
			Sprite = SpriteData [spriteIdx++ % SpriteData.Length];
		}
	}
}

RawImageBinding

RawImageへのバインディング
バインドイメージ)RawImage.texture = Path;

 プロパティ
 Path M4uContextRoot.Context内にあるデータへのパス
型:Texture
using UnityEngine;

namespace M4u.Demo
{
	public class Demo : MonoBehaviour
	{
		public Texture[] TextureData;

		M4uProperty<Texture> texture = new M4uProperty<Texture>();
		int textureIdx;

		public Texture Texture { get { return texture.Value; } set { texture.Value = value; } }

		void Awake()
		{
			App.Instance.Demo = this;
			GetComponent<M4uContextRoot>().Context = App.Instance;
		}

		public void OnUpdate()
		{
			Texture = TextureData [textureIdx++ % TextureData.Length];
		}
	}
}

ActiveBinding

GameObjectのアクティブフラグへのバインディング。子要素のGameObjectに対しても適応される。
バインドイメージ)GameObject.SetActive (Path);

 プロパティ
 Path M4uContextRoot.Context内にあるデータへのパス
型:bool/double/string/enum
 CheckType Bool:bool、Equal:==、Greater:>、Less:<、Empty:空文字、String:文字列、Enum:enum
 CheckValue CheckTypeがEqual・Greater・Lessの場合に使用する数値
 CheckString CheckTypeがString・Enumの場合に使用する文字列
 Invert 判定結果を逆にする場合は true
using UnityEngine;

namespace M4u.Demo
{
	public class Demo : MonoBehaviour
	{
		M4uProperty<bool> isActive = new M4uProperty<bool> (true);

		public bool IsActive { get { return isActive.Value; } set { isActive.Value = value; } }

		void Awake()
		{
			App.Instance.Demo = this;
			GetComponent<M4uContextRoot>().Context = App.Instance;
		}

		public void OnUpdate()
		{
			IsActive = !IsActive;
		}
	}
}

EnableBinding

MonoBehaviourの有効フラグへのバインディング。子要素のGameObjectに対しても適応される。
バインドイメージ)MonoBehaviour.enabled = Path;

 プロパティ
 Path M4uContextRoot.Context内にあるデータへのパス
型:bool/double/string/enum
 CheckType Bool:bool、Equal:==、Greater:>、Less:<、Empty:空文字、String:文字列、Enum:enum
 CheckValue CheckTypeがEqual・Greater・Lessの場合に使用する数値
 CheckString CheckTypeがString・Enumの場合に使用する文字列
 Invert 判定結果を逆にする場合は true
using UnityEngine;

namespace M4u.Demo
{
	public class Demo : MonoBehaviour
	{
        public enum HeartAbility { Sun, Moon }

        M4uProperty<HeartAbility> ability = new M4uProperty<HeartAbility> ();

        public HeartAbility Ability { get { return ability.Value; } set { ability.Value = value; } }

		void Awake()
		{
			App.Instance.Demo = this;
			GetComponent<M4uContextRoot>().Context = App.Instance;
		}

		public void OnUpdate()
		{
            Ability = Ability == HeartAbility.Sun ? HeartAbility.Moon : HeartAbility.Sun;
		}
	}
}

TransformBinding、TransformLocalBinding

Transformへのバインディング。TransformBindingとTransformLocalBindingは設定方法が違うだけ。
バインドイメージ)Transform.localPosition = Path;

 プロパティ
 Path M4uContextRoot.Context内にあるデータへのパス
型:float/Vector3
 Type(TransformBinding) Px・Py・Pz:localPosition.x〜z
Rx・Ry・Rz:localRotation.x〜z
Sx・Sy・Sz:localScale.x〜z
 Type(TransformLocalBinding) Postion:localPosition
Rotation:localRotation
Scale:localScale
using UnityEngine;

namespace M4u.Demo
{
	public class Demo : MonoBehaviour
	{
		M4uProperty<float> x = new M4uProperty<float> ();
		M4uProperty<Vector3> scale = new M4uProperty<Vector3>(Vector3.one);

		public float X { get { return x.Value; } set { x.Value = value; } }
		public Vector3 Scale { get { return scale.Value; } set { scale.Value = value; } }

		void Awake()
		{
			App.Instance.Demo = this;
			GetComponent<M4uContextRoot>().Context = App.Instance;
		}

		public void OnUpdate()
		{
			X = Random.Range (-200f, 200f);
			Scale = new Vector3 (Random.Range (0.3f, 1f), Random.Range (0.3f, 1f), 0);
		}
	}
}

ColorBinding

Graphicのカラーへのバインディング。子要素のGameObjectに対しても適応される。
バインドイメージ)Graphic.color = Path;

 プロパティ
 Path M4uContextRoot.Context内にあるデータへのパス
型:Color
using UnityEngine;

namespace M4u.Demo
{
	public class Demo : MonoBehaviour
	{
		M4uProperty<Color> color = new M4uProperty<Color> (Color.white);

		public Color Color { get { return color.Value; } set { color.Value = value; } }

		void Awake()
		{
			App.Instance.Demo = this;
			GetComponent<M4uContextRoot>().Context = App.Instance;
		}

		public void OnUpdate()
		{
			Color = new Color (Random.Range (0f, 1f), Random.Range (0f, 1f), Random.Range (0f, 1f));
		}
	}
}

CollectionBinding

Collectionへのバインディング。Pathに設定されている要素数分Dataを生成する。主にScrollViewで使用する。
バインドイメージ)Collection = Path;

 プロパティ
 Path M4uContextRoot.Context内にあるデータへのパス
型:int/Array/ICollection
 Data 生成するデータ(Prefab)。M4uContextRootが存在し、PathデータがM4uContextを継承したクラスの場合、自動的にM4uContextRoot.Contextに値を設定する。
 SavePath ※省略可能 生成されたデータを保存するパス
型:IList(Value:GameObject)/IDictionary(Key:Path、Value:GameObject)
 OnChanged ※省略可能 データ変更後に呼ばれるコールバック
using UnityEngine;

namespace M4u.Demo
{
	public class Monster : M4uContext
	{
		M4uProperty<string> name = new M4uProperty<string> ();
		M4uProperty<Texture> texture = new M4uProperty<Texture> ();

		public string Name { get { return name.Value; } set { name.Value = value; } }
		public Texture Texture { get { return texture.Value; } set { texture.Value = value; } }
	}
}
using UnityEngine;
using System.Collections.Generic;

namespace M4u.Demo
{
	public class Demo : MonoBehaviour
	{
		public Texture MonsterTextureData;

		M4uProperty<List<Monster>> monsters = new M4uProperty<List<Monster>>(new List<Monster>());
		List<GameObject> monsterList = new List<GameObject>();

		public List<Monster> Monsters { get { return monsters.Value; } set { monsters.Value = value; } }
		public List<GameObject> MonsterList { get { return monsterList; } set { monsterList = value; } }

		void Awake()
		{
			App.Instance.Demo = this;
			GetComponent<M4uContextRoot>().Context = App.Instance;
		}

		public void OnUpdate()
		{
            Monsters.Clear ();
            int count = Random.Range (0, 6);
			for(int i = 0; i < count; i++)
			{
				var monster = new Monster();
                monster.Name = "Aruka" + Random.Range (1, 100);
                monster.Texture = MonsterTextureData;
				Monsters.Add(monster);
			}
		}

		void OnChangedMonsterList()
		{
			Debug.Log ("MonsterCount = " + MonsterList.Count);
		}
	}
}

EventBinding(s)

UnityEventへのバインディング
バインドイメージ)UnityEvent.AddListener(Path);

 プロパティ
 Path M4uContextRoot.Context内にあるデータへのパス
型:UnityAction
 Type ButtonClick、ToggleValueChanged、SliderValueChanged、ScrollbarValueChanged、DropdownValueChanged、InputFieldEndEdit、ScrollRectValueChanged、EventTrigger
 TriggerType TypeがEventTriggerの場合のトリガータイプ。UnityEngine.EventSystems.EventTriggerTypeと同じ
using UnityEngine;

namespace M4u.Demo
{
	public class Demo : MonoBehaviour
	{
		void Awake()
		{
			App.Instance.Demo = this;
			GetComponent<M4uContextRoot>().Context = App.Instance;
		}

		void OnClickEvent()
		{
			Debug.Log ("OnClickEvent");
		}
	}
}

ToggleBinding

Toggleへのバインディング
バインドイメージ)Toggle.isOn = Path;

 プロパティ
 Path M4uContextRoot.Context内にあるデータへのパス
型:bool/double/string/enum
 CheckType Bool:bool、Equal:==、Greater:>、Less:<、Empty:空文字、String:文字列、Enum:enum
 CheckValue CheckTypeがEqual・Greater・Lessの場合に使用する数値
 CheckString CheckTypeがString・Enumの場合に使用する文字列
 Invert 判定結果を逆にする場合は true
using UnityEngine;

namespace M4u.Demo
{
	public class Demo : MonoBehaviour
	{
		M4uProperty<bool> isActive = new M4uProperty<bool> (true);

		public bool IsActive { get { return isActive.Value; } set { isActive.Value = value; } }

		void Awake()
		{
			App.Instance.Demo = this;
			GetComponent<M4uContextRoot>().Context = App.Instance;
		}

		public void OnUpdate()
		{
			IsActive = !IsActive;
		}
	}
}

InputFieldBinding(s)

InputFieldへのバインディング
バインドイメージ)InputField.text = string.Format(Format, Path);

 プロパティ
 Path M4uContextRoot.Context内にあるデータへのパス
型:string
 Format テキストフォーマット。string.Formatと同じ使い方。
using UnityEngine;

namespace M4u.Demo
{
	public class Demo : MonoBehaviour
	{
		M4uProperty<string> message = new M4uProperty<string>("");

		public string Message { get { return message.Value; } set { message.Value = value; } } 

		void Awake()
		{
			App.Instance.Demo = this;
			GetComponent<M4uContextRoot>().Context = App.Instance;
		}

		public void OnUpdate()
		{
            Message = Random.Range (1, 100).ToString();
		}
	}
}

ScrollbarBinding

Scrollbarへのバインディング
バインドイメージ)Scrollbar.value = Path;

 プロパティ
 Path M4uContextRoot.Context内にあるデータへのパス
型:float
using UnityEngine;

namespace M4u.Demo
{
	public class Demo : MonoBehaviour
	{
        M4uProperty<float> progress = new M4uProperty<float>();

        public float Progress { get { return progress.Value; } set { progress.Value = value; } }

		void Awake()
		{
			App.Instance.Demo = this;
			GetComponent<M4uContextRoot>().Context = App.Instance;
		}

		public void OnUpdate()
		{
            Progress = Random.Range (0f, 1f);
		}
	}
}

SliderBinding

Sliderへのバインディング
バインドイメージ)Slider.value = Path;

 プロパティ
 Path M4uContextRoot.Context内にあるデータへのパス
型:float
using UnityEngine;

namespace M4u.Demo
{
	public class Demo : MonoBehaviour
	{
        M4uProperty<float> progress = new M4uProperty<float>();

        public float Progress { get { return progress.Value; } set { progress.Value = value; } }

		void Awake()
		{
			App.Instance.Demo = this;
			GetComponent<M4uContextRoot>().Context = App.Instance;
		}

		public void OnUpdate()
		{
            Progress = Random.Range (0f, 1f);
		}
	}
}

SpecialBinding(s)

スペシャルバインディング。どんなものでもバインド可能なスペシャルなバインド。バインドされているGameObjectのComponentデータへのパスを指定する。
バインドイメージ)TargetPath = Path;

 プロパティ
 Path M4uContextRoot.Context内にあるデータへのパス
型:TargetPathの型
 TargetPath ターゲットパス。[Component名.プロパティ名]のように記述。
using UnityEngine;

namespace M4u.Demo
{
	public class Demo : MonoBehaviour
	{
		public Sprite[] SpriteData;
		
		M4uProperty<Sprite> sprite = new M4uProperty<Sprite>();
		int spriteIdx;
		M4uProperty<Vector2> size = new M4uProperty<Vector2>(Vector2.one);

		public Sprite Sprite { get { return sprite.Value; } set { sprite.Value = value; } }
		public Vector2 Size { get { return size.Value; } set { size.Value = value; } }

		void Awake()
		{
			App.Instance.Demo = this;
			GetComponent<M4uContextRoot>().Context = App.Instance;
		}

		public void OnUpdate()
		{
			Sprite = SpriteData [spriteIdx++ % SpriteData.Length];
			Size = new Vector2 (Random.Range (64, 128), Random.Range (64, 128));
		}
	}
}

最後に

現在、M4u 1.2.0 を作成中。要望のあったパスを省略できるMasterPath機能と細かい改善を行う予定。
MVVM、みんなもっと使えばいいのになぁ。

スポンサーリンク