はじめに
今回はUI ToolkitのUxmlElement
とUxmlAttribute
について取り上げたいと思います。
docs.unity3d.com
docs.unity3d.com
昔Unity2023.2のTech Stream紹介ブログにて、Custom UI Elements
の実装を簡略化した改善が紹介されていました。
古いやり方についてはQualiArtsさんの技術記事を参照すると分かりやすいかと思います。
technote.qualiarts.jp
気づけば今はUnity6 Beta(6000.0)が出ていたので、実際にどうなっているのか試してみたいと思います。
やり方
最初の添付した画像の通り、VisualElement
を継承したクラスに[UxmlElement]
をつけ、partial
をつけます。(SourceGeneratorを利用していて、対応するUxmlSerializedDataがコンパイル時に生成されます)
あとはプロパティとして表示したい値に[UxmlAttribute]
をつけます。
using UnityEngine.UIElements; namespace ExampleUxmlSerializedData { // 以前はUI Builderで使用するためには対応する「UxmlFactory」を継承したクラスを作らなければならなかった // 以前はUI Builderでプロパティとして受け取った値の反映は「UxmlTraits」を継承したクラスが必要だった // それが[UxmlElement]&[UxmlAttribute]を利用するだけでOKになった!!! [UxmlElement] public partial class ExampleVisualElement : VisualElement { // 自動でSerializeされるようになる [UxmlAttribute] public string MyStringValue { get; set; } // nameを指定してあげることが可能 [UxmlAttribute("count")] public float Count { get; set; } public ExampleVisualElement() { var label = new Label(); var button = new Button(); button.clicked += () => { label.text = "myStringValue: " + MyStringValue; button.text = $"押してね({++Count})"; }; // UIに追加された段階で処理を行う(コンストラクタの時点で初期化しても、値が反映されないため) RegisterCallback<AttachToPanelEvent>(e => { // ここで初期化処理を行う label.text = "myStringValue: " + MyStringValue; button.text = $"押してね({Count})"; }); Add(label); Add(button); } } }
// 生成されたコード namespace ExampleUxmlSerializedData { public partial class ExampleVisualElement { [global::System.Runtime.CompilerServices.CompilerGenerated] [global::System.Serializable] public new class UxmlSerializedData : UnityEngine.UIElements.VisualElement.UxmlSerializedData { #pragma warning disable 649 [global::UnityEngine.SerializeField] string MyStringValue; [global::UnityEngine.SerializeField, global::UnityEngine.UIElements.UxmlIgnore, global::UnityEngine.HideInInspector] UnityEngine.UIElements.UxmlSerializedData.UxmlAttributeFlags MyStringValue_UxmlAttributeFlags; [UnityEngine.UIElements.UxmlAttributeAttribute("count")] [global::UnityEngine.SerializeField] float Count; [global::UnityEngine.SerializeField, global::UnityEngine.UIElements.UxmlIgnore, global::UnityEngine.HideInInspector] UnityEngine.UIElements.UxmlSerializedData.UxmlAttributeFlags Count_UxmlAttributeFlags; #pragma warning restore 649 public override object CreateInstance() => new ExampleVisualElement(); public override void Deserialize(object obj) { base.Deserialize(obj); var e = (ExampleVisualElement)obj; if (ShouldWriteAttributeValue(MyStringValue_UxmlAttributeFlags)) { e.MyStringValue = this.MyStringValue; } if (ShouldWriteAttributeValue(Count_UxmlAttributeFlags)) { e.Count = this.Count; } } } } }
注意点としてはRegisterCallback<AttachToPanelEvent>
を利用しないと、コンストラクタ時点ではデシリアライズ処理が走っておらず、値が設定されていないので初期化処理を遅らせる必要があります。
結果
実際にUI Builderを見てみると、ExampleVisualElement
がLibrary > Project > Custom Controls(C#)
の中にあるはずです。
ちゃんとプロパティも表示されていますね。