using System; using System.Collections.Generic; using Cysharp.Threading.Tasks; using UnityEngine.AddressableAssets; using UnityEngine.ResourceManagement.AsyncOperations; using Object = UnityEngine.Object;
namespace Ruchi.Data.Repository { public static class AddressableRepository { private readonly struct AssetEntity { ///アドレス、ラベル public readonly string Path;
//参照カウンタ public readonly int RefCount;
//Addressable のロードハンドラ public readonly AsyncOperationHandle Handle;
public AssetEntity(string path, int refCount, AsyncOperationHandle handle) { Path = path; RefCount = refCount; Handle = handle; }
public AssetEntity IncreaseRefCount() { var refCount = checked(RefCount + 1); var entity = new AssetEntity(Path, refCount, Handle); return entity; }
public AssetEntity DecreaseRefCount() { if (RefCount == 0) { throw new Exception($"{nameof(RefCount)}は0以下にできません。"); } var entity = new AssetEntity(Path, RefCount - 1, Handle); return entity; } }
public static async UniTask<T> LoadAssetAsync<T>(string path) where T : Object { var contains = ContainsKey<T>(path);
// すでにロード済み if (contains) { var cachedEntity = GetEntity<T>(path); cachedEntity = cachedEntity.IncreaseRefCount(); SetEntity<T>(cachedEntity);
return cachedEntity.Handle.Result as T; }
var handle = Addressables.LoadAssetAsync<T>(path); await handle; if (handle.Status != AsyncOperationStatus.Succeeded) { throw new ArgumentNullException(handle.Status.ToString()); }
var entity = new AssetEntity(path, 1, handle); SetEntity<T>(entity);
return handle.Result; }
// アセットアンロード public static void Release<T>(string path) { if (ContainsKey<T>(path) == false) { return; }
var entity = GetEntity<T>(path); entity = entity.DecreaseRefCount(); if (entity.RefCount > 0) { return; }
//MyNode.cs using UnityEditor.Experimental.GraphView;
public class MyNode : Node {
}
そして、さっき作成したMyGraphViewに以下の内容を入力してください。
//MyGraphView.cs using UnityEditor.Experimental.GraphView;
public class MyGraphView : GraphView { public MyGraphView() : base() { AddElement(new MyNode()); } }
確認してみると、あれ?表示されない!!なんで...なんで..
そういう時はUIElements Debuggerを使いましょう。
やっぱり生成されています。なぜでしょうか。
しかし、理由は簡単です。高さが0になっていて生成されているのに見えていないのです。
GraphEditorWindowに以下の内容を入力してください。
//GraphEditorWindow.cs using UnityEditor; using UnityEngine;
public class GraphEditorWindow : EditorWindow { [MenuItem("Window/Open GraphView")] public static void Open() { GraphEditorWindow graphEditorWindow = CreateInstance<GraphEditorWindow>(); graphEditorWindow.Show(); graphEditorWindow.titleContent = new GUIContent("GraphEditor"); }
void OnEnable() { var graphView = new MyGraphView() { style = { flexGrow = 1 } }; rootVisualElement.Add(graphView); } }
無事、Nodeが作成されました。感動の瞬間です!
でもこれじゃただの箱ですw
Portを追加してNode同士をつなげられるようにしましょう。
MyNodeに以下の内容を入力してください。
//MyNode.cs using UnityEditor.Experimental.GraphView;
public class MyNode : Node { public MyNode() { title = "Sample"; var inputPort = Port.Create<Edge>(Orientation.Horizontal, Direction.Input,Port.Capacity.Single, typeof(Port)); inputContainer.Add(inputPort);
var outputPort = Port.Create<Edge>(Orientation.Horizontal, Direction.Output, Port.Capacity.Single, typeof(Port)); outputContainer.Add(outputPort); } }
これで確認してみると
お、NodeにPortがつきました!
でも思いませんか?NodeとNodeを繋ぎたいと、でも繋ぐNodeがないですね。
Nodeを量産できるようにしましょう。
MyGraphViewを以下のようにしてください。
//MyGraphView.cs using UnityEngine.UIElements;//AddManipulatorを使うために必要 using UnityEditor.Experimental.GraphView;
public class MyGraphView : GraphView { public MyGraphView() : base() { this.AddManipulator(new SelectionDragger());//移動できるように nodeCreationRequest += context => { AddElement(new MyNode()); }; } }
//MyGraphView.cs using UnityEngine; using UnityEngine.UIElements;//AddManipulatorを使うために必要 using System.Collections.Generic; using UnityEditor.Experimental.GraphView; public class MyGraphView : GraphView { public MyGraphView() : base() { styleSheets.Add(Resources.Load<StyleSheet>("BackGround")); GridBackground gridBackground = new GridBackground(); Insert(0, gridBackground); gridBackground.StretchToParentSize();
//MyGraphView.cs using UnityEngine; using UnityEngine.UIElements;//AddManipulatorを使うために必要 using System.Collections.Generic; using UnityEditor.Experimental.GraphView;
public class MyGraphView : GraphView { public RootNode root;
public MyGraphView() : base() { styleSheets.Add(Resources.Load<StyleSheet>("BackGround")); GridBackground gridBackground = new GridBackground(); Insert(0, gridBackground); gridBackground.StretchToParentSize();
//SearchWindowProvider.cs using System; using System.Collections.Generic; using UnityEngine; using UnityEditor.Experimental.GraphView;
public class SearchWindowProvider : ScriptableObject, ISearchWindowProvider { private MyGraphView graphView;
public void Initialize(MyGraphView graphView) { this.graphView = graphView; }
List<SearchTreeEntry> ISearchWindowProvider.CreateSearchTree(SearchWindowContext context) { var entries = new List<SearchTreeEntry>(); entries.Add(new SearchTreeGroupEntry(new GUIContent("Create Node")));
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) { foreach (var type in assembly.GetTypes()) { if (type.IsClass && !type.IsAbstract && type.IsSubclassOf(typeof(MyNode)) && type != typeof(RootNode)) { entries.Add(new SearchTreeEntry(new GUIContent(type.Name)){ level = 1, userData = type }); } } } return entries; }
bool ISearchWindowProvider.OnSelectEntry(SearchTreeEntry searchTreeEntry, SearchWindowContext context) { var type = searchTreeEntry.userData as Type; var node = Activator.CreateInstance(type) as MyNode; graphView.AddElement(node); return true; } }
そしたら検索できるようにMyGraphViewを次のようにします
//MyGraphView.cs using UnityEngine; using UnityEngine.UIElements;//AddManipulatorを使うために必要 using System.Collections.Generic; using UnityEditor.Experimental.GraphView;
Public class MyGraphView : GraphView { public RootNode root;
public MyGraphView() : base() { styleSheets.Add(Resources.Load<StyleSheet>("BackGround")); GridBackground gridBackground = new GridBackground(); Insert(0, gridBackground); gridBackground.StretchToParentSize();
//MyGraphView.cs using UnityEngine; using UnityEngine.UIElements;//AddManipulatorを使うために必要 using System.Collections.Generic; using UnityEditor.Experimental.GraphView;
public class MyGraphView : GraphView { public RootNode root;
public MyGraphView() : base() { styleSheets.Add(Resources.Load<StyleSheet>("BackGround")); GridBackground gridBackground = new GridBackground(); Insert(0, gridBackground); gridBackground.StretchToParentSize();
//MyGraphView.cs using UnityEngine; using UnityEngine.UIElements;//AddManipulatorを使うために必要 using System.Linq; using System.Collections.Generic; using UnityEditor.Experimental.GraphView;
public class MyGraphView : GraphView { public RootNode root;
public MyGraphView() : base() { styleSheets.Add(Resources.Load<StyleSheet>("BackGround")); GridBackground gridBackground = new GridBackground(); Insert(0, gridBackground); gridBackground.StretchToParentSize();
//EnumField.cs using System; using UnityEditor.UIElements; using UnityEditor.Experimental.GraphView;
public class EnumNode : MyNode { private EnumField enumField; public int Text { get { return Convert.ToInt32(enumField.value); } } public Jyanken jyanken;
//EnumField.cs using UnityEditor.UIElements; using UnityEditor.Experimental.GraphView;
public class EnumNode : MyNode { private EnumField enumField; public int Text { get { return (int)enumField.userData; } } public Jyanken jyanken;
public enum Jyanken { Gu, Tyoki, Pa, } public EnumNode() : base() { title = "Enum";
var outputPort = Port.Create<Edge>(Orientation.Horizontal, Direction.Output, Port.Capacity.Multi, typeof(int)); outputContainer.Add(outputPort);
enumField = new EnumField(); enumField.Init(jyanken); mainContainer.Add(enumField); } }
無事ドロップダウンを表示することができました!
Audio再生とかをしたい
Logを出す以外にもEnumFiledとかObjectFieldを使って何かやってみたいですよね?
そこで今回はAudioの再生をやってみます。
まずAudioClipをD&DするためのNodeを作ります。
//AudioClipNode.cs using UnityEngine; using UnityEditor.UIElements; using UnityEditor.Experimental.GraphView;
public class AudioClipNode : MyNode { private ObjectField audioClipField; public AudioClip value { get { return audioClipField.value as AudioClip; } }
public AudioClipNode() : base() { title = "AudioClip";
var outputPort = Port.Create<Edge>(Orientation.Horizontal, Direction.Output, Port.Capacity.Multi, typeof(AudioClip)); outputContainer.Add(outputPort);
audioClipField = new ObjectField(); audioClipField.objectType = typeof(AudioClip); mainContainer.Add(audioClipField); } }
次にAudioSourceをD&DするためのNodeを作ります
//AudioSourceNode.cs using UnityEngine; using UnityEditor.UIElements; using UnityEditor.Experimental.GraphView;
public class AudioSourceNode : MyNode { private ObjectField audioSourceField; public AudioSource value { get { return audioSourceField.value as AudioSource; } }
public AudioSourceNode() : base() { title = "AudioSource"; var outputPort = Port.Create<Edge>(Orientation.Horizontal, Direction.Output, Port.Capacity.Multi, typeof(AudioSource)); outputContainer.Add(outputPort);
audioSourceField = new ObjectField(); audioSourceField.objectType = typeof(AudioSource); mainContainer.Add(audioSourceField); } }