0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

[Unity Visual Scripting] 型付き名前付きの引数を自由に追加できるユニットをつくる

Last updated at Posted at 2023-07-20

導入

文字列フォーマットとかで動的に名前付き入力や出力が欲しくなる場面がある。

実装

まずは、 InputValue に必要な値を持つクラスを作る。

[Serializable]
public class ArgsMetadata {
    public string Name { get; set; }
    public Type Type { get; set; }
}

定義した ArgsMetadata クラスのリストから InputValueOutputValue を生成する。

public class MyUnit : Unit {
    [DoNotSerialize] List<ValueInput> CustomInputsSource { get; } = new List<ValueInput>();
    [DoNotSerialize] List<ValueOutput> CustomsOutputsSource { get; } = new List<ValueOutput>();

    [DoNotSerialize] public ReadOnlyCollection<ValueInput> CustomInputs { get; }
    [DoNotSerialize] public ReadOnlyCollection<ValueOutput> CustomsOutputs { get; }

    [Inspectable, InspectorWide, InspectorLabel("Custom Inputs")]
    List<ArgsMetadata> CustomInputMetadata { get; }
    [Inspectable, InspectorWide, InspectorLabel("Custom Outputs")]
    List<ArgsMetadata> CustomOutputMetadata { get; }

    public MyUnit() {
        // ValueInput, ValueOuput を読み取り専用で公開する
        CustomInputs = new ReadOnlyCollection<ValueInput>(CustomInputsSource);
        CostomOutputs = new ReadOnlyCollection<ValueOutput>(CustomOutputsSource);
    }

    protected override void Definition() {
        CustomInputsSource.Clear();
        CustomsOutputsSource.Clear();

        // メタデータを元にポートを作成する
        if (CustomInputMetadata != null) {
            foreach (var c in CustomInputMetadata) {
                if (c.Type == null) continue;
                CustomInputsSource.Add(ValueInput(c.Type, c.Name));
            }
        }

        if (CustomOutputMetadata != null) {
            foreach (var c in CustomOutputMetadata) {
                if (c.Type == null) continue;
                CustomsOutputsSource.Add(ValueOutput(c.Type, c.Name));
            }
        }
        // フローや関連付けを適宜追加 //
    }
}

このままでは GraphInspector に ArgsMetadata のインスペクターが定義されていないと警告されてしまうため Inspector クラスを継承して自前で GUI を実装する。 InspectorAttribute 属性を付与するとインスペクターに設定できる。

[Inspector(typeof(ArgsMetadata))]
public class ArgsMetadataInspector : Inspector {
    private TypeFilter typeFilter;
    public ArgsMetadataInspector(Metadata metadata) : base(metadata) {
        typeFilter = metadata.Member("Type").GetAttribute<TypeFilter>() ?? TypeFilter.Any;
    }
    // GUIの高さを事前計算する
    protected override float GetHeight(float width, GUIContent label) {
        return EditorGUIUtility.singleLineHeight;
    }
    // GUIを描画する
    protected override void OnGUI(Rect position, GUIContent label) {
        var typeMetadata = metadata.Member("Type");
        var nameMetadata = metadata.Member("Name");
        // Type と Name で半々にする
        var typePosition = new Rect(position.x, position.y,
                                    position.width / 2, position.height);
        var namePosition = new Rect(typePosition.x + typePosition.width, typePosition.y, 
                                    typePosition.width, typePosition.height);
        // Type フィールド
        BeginBlock(typeMetadata, position);
        var newType = LudiqGUI.TypeField(typePosition, GUIContent.none,
                                         (Type)typeMetadata.value, GetOptions);
        if (EndBlock(typeMetadata)) {
            typeMetadata.RecordUndo();
            typeMetadata.value = newType;
        }
        // Name フィールド
        BeginBlock(nameMetadata, namePosition);
        var newNameValue = GUI.TextArea(namePosition, (string)nameMetadata.value);
        if (EndBlock(nameMetadata)) {
            nameMetadata.RecordUndo();
            nameMetadata.value = newNameValue;
        }
    }
    private IFuzzyOptionTree GetOptions() {
        return new TypeOptionTree(Codebase.GetTypeSetFromAttribute(metadata), typeFilter);
    }
}

LudiqGUI という Visual Scripting 向けの GUI ヘルパークラスがあるので利用するとよい。

結果

namedport.png
名前の重複は確認していないが ValueInput を追加した段階で重複があれば警告される。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?