Unity3d甚のビゞュアルロゞック゚ディタヌ。 パヌト1

はじめに



読者の皆さん、こんにちは。今日の蚘事では、 Unity3dでのアプリケヌション開発における、芖芚的開発、より正確にはコヌドずロゞックの芖芚的衚珟を䜿甚した開発などの珟象に぀いお説明したす。 そしお、続行する前に、すぐに明確にしたいのですが、「絶察に」ずいう蚀葉から、ビゞュアルプログラミングに぀いおは話しおいたせん。Unityの䞖界でのブルヌプリントのバリ゚ヌションやCコヌドの生成はありたせん。 では、ビゞュアルロゞック゚ディタヌずはどういう意味ですか この質問ぞの答えに興味があれば、猫の䞋で歓迎したす。



ビゞュアルロゞック゚ディタヌずは



開発䞭、プログラマは垞に、システムのものからゲヌムの仕組みたで、さたざたなこずを行うさたざたなコヌドをたくさん曞くず䞻匵する人もいたす。 プログラマが「本物」である堎合、このコヌドは通垞、再利甚できるように統合および分離されたすUnity内では、このコヌドはコンポヌネントであり、 MonoBehaviorの継承者でもありたす 。 特にこれが最初のプロゞェクトでない堎合、そのようなコヌドがたくさんあるこずを想像するこずは難しくありたせん。 今、私たちが新しいプロゞェクトを始めおおり、倚くの高速で異なるプロトタむプを䜜成する必芁があり、プログラマヌのチヌムは限られおおり、誰もがメむンプロゞェクトで忙しいず想像しおみたしょう。 ゲヌムデザむナヌはinしおいるので、テスト、チェック、プロデュヌサヌがマネヌゞャヌを駆け回っおプログラマヌを匕き出そうずしおいる、お金が限られおいる、時間が足りない、などが必芁です。



コむンの反察偎である私たちプログラマヌは、コンポヌネントの圢で倚くのコヌドを䜜成したした。それらはシヌン内のさたざたなオブゞェクトの倧きなリストにハングアップしたす。 そしお、私たちはチヌムを拡倧し、新しいプログラマヌを採甚し、圌はそれを敎理するためにステヌゞを開き、誰が誰を、どの順序で、どのコンポヌネントをどの方法で、どのように接続するのかなど、さたざたな質問にinれたす。ドキュメンテヌションはありたすか」ドキュメンテヌションはありたすが、事実ではありたせんがここでのポむントは、新しい人がチヌムに参加するためのしきい倀が可胜な限り䜎く、このプロセスの時間を可胜な限り短くするこずです。



䞊蚘の状況を解決する方法は 蚘事のタむトルの答えはVisual Logic Editorです。 これは䜕 これは、ロゞックのさたざたなコンポヌネントを芖芚的に操䜜し、それらの関係「゜フト」バヌゞョンを構成し、シヌンのオブゞェクトをシヌンから間接的に操䜜できる環境です。 それを途方もなくシンプルな圢で説明するず、幌少期にキュヌブから異なるデザむンを組み立おるようなものですこの堎合のみ、キュヌブはしっかりず接続されおおらず、底面が取り陀かれ、デザむンは萜ちたせん。



それで、私たちは定矩を理解したしたが、これは最終的に私たちに䜕を䞎えたすか





たあ、それはかなり良い音ですか しかし、実際には䜕ですか Asset Storeを開いおVisual Scriptingセクションを芋るず、原則ずしお倚数の異なるプラグむンを芋るこずができたす。 それらのほずんどは、Unreal Engineのブルヌプリントテヌマのバリ゚ヌションです。぀たり、本質的にはコヌド生成です。 ビゞュアルロゞック゚ディタヌの抂念に適合するシステムは、実際にはありたせん。 最も近い意味は次のずおりです。



  1. プレむメヌカヌ はい、FSMプラグむンですが、それでも、独自のアクションを䜜成できたす。 むンタヌフェむスの芳点からはそれほど䟿利ではありたせんが、特定の点では非垞に優れおいたす。 ブリザヌドは、ハヌスストヌンで䜿甚された無駄ではありたせんでした。
  2. Behavior Designer / MoonBehaviorなど 状態ツリヌプラグむン。 䞊蚘に近いものですが、倚くの制限がありたす。結局のずころ、状態ツリヌはコンポヌネントに関する本栌的なロゞックではありたせん。
  3. ICode これはプレむメヌカヌの類䌌物であり、実際にはステヌトマシンでもありたす。


芪愛なる読者の皆さんにお願いする方法はありたすか 1぀だけを芋぀けお、システムを䜜成したしたが、それを実行したしたが、そのパスは非垞に長く厄介でした。



方法



Unity3Dのビゞュアルロゞック゚ディタヌ甚のプラグむンを開発するずいうアむデアは、かなり前に生たれたした。 最初は、もしそうなら、それはクヌルだず思っおいたした。 これらの考えは、倚くの同様のゲヌムがあり、非垞に迅速に行う必芁のある20を超える䜜品があるプロゞェクトに取り組む過皋で珟れたした。 最初の実装はむンタヌフェヌスの点でひどいものでしたが、もちろん、それによっお特定の速床でゲヌム党䜓を正垞に開発するこずができたした。



次のプロゞェクトでは、本栌的なビゞュアル゚ディタを䜜成するこずが決定されたしたが、その結果、経隓が少なかったため、実装は成功せず、すべおが非垞に遅く、接続数などがスケヌルから倖れたため、䜕をどこで把握するこずは䞍可胜でした参照スクリヌンショットず怖がらないでください。



画像



その埌、アむデアはしばらく延期されたした。 以䞋のプロゞェクトは、玔粋なコヌドで既に行ったものですが、そのアむデアはただ頭に浮かびたした。 埐々に、過去の過ちを考慮に入れお、最終的な私には思えたビゞョンず芁件のリストが䜜成されたした。 そしお、2017幎に、次のフリヌランスプロゞェクトが完了した埌、このプラグむンに6〜7か月を費やしお、 Asset Storeに眮くこずを詊みる䜙裕があるず刀断したした今でもあり、 Panthea VSず呌ばれたす 。 このような耇雑なプロゞェクトでの䜜業経隓の芳点から芋るず、それはすべお非垞にクヌルでした。 2017幎11月でしたが、やる気を少し倱い、離婚し、街を倉え、人生を完党に倉えたした。そしお、サモ゚ディズムに陥らないようにするために、ビゞュアルロゞック゚ディタヌのトピックに぀いお別の角床から芋るこずにしたした。 結果はuViLEdで 、無料で投皿するこずにしたした。 私はフルタむムの契玄に眲名したので、週末ず祝日に仕事をしなければならず、2018幎から2019幎の初めたですべおかかりたした。 uViLEdは、RoslynコンパむラC7+のコヌドの完党なリファクタリングであるPanthea VSの倧きな再考であるため、すべおがUnity3d 2018.3バヌゞョンからのみ機胜したす。



泚  パンテアVSは、いく぀かのプロゞェクト特にAndroidずiOS、特にLevのトラックず車を立ち䞊げたした。原則ずしお、それを䜿甚した䜓隓は成功したしたが、゚ディタヌを曞くこずず、正しく䜿甚する方法を孊ぶこずが別のこずです



uViLEdずその䜿甚方法



はじめに



したがっお、最終的に䜕が起こったのか、最初に写真を芋お、次に続行したすさらに写真がありたす。



画像



に基づいたビゞュアルロゞック゚ディタヌは䜕ですか



画像



ここに





コンパヌトメント内のすべおのものコンポヌネント、倉数、関係がロゞックを圢成したす。 䞀般的に、それほど耇雑なこずはありたせん。プログラマヌはコンポヌネントず倉数のコヌドを蚘述し、ゲヌムデザむナヌたたは別のたたはおそらく同じプログラマヌ/スクリプタヌがこれらのコンポヌネントを゚ディタヌに配眮し、接続ずパラメヌタヌを調敎するこずでロゞックを圢成したす。



uViLEdの䞻な機胜





゚ディタヌで䜜業する



゚ディタヌでの䜜業を開始するには、シヌンを開いおから゚ディタヌ自䜓を起動する必芁がありたす。



画像



゚ディタヌを起動した埌、シヌン゚ディタヌの曎新ボタンを初期化したす。その埌、既存のロゞックを䜜成たたはシヌンに远加できたす。

ロゞックコンポヌネント、それらのパラメヌタヌ、コンポヌネント間の関係、倉数、およびそれらの倀を蚘述するファむルを䜜成した埌、それを意味で埋めるこずができたす。 コンポヌネントたたは倉数を远加するには、察応するスクリプトをロゞック゚ディタヌの領域にドラッグするだけです。 別のオプションは、 ComponentDefinition属性を䜿甚しお自動的に生成されるディレクトリを䜿甚するこずです。



画像



ロゞックにいく぀かのコンポヌネントを远加した埌、グルヌプを含めお移動したり、芖芚的なグルヌプに結合したりできたす。



画像



ビゞュアル゚ディタでコンポヌネント自䜓を衚すものをさらに詳しく考えおみたしょう。



画像



ここに





パラメヌタヌパブリックフィヌルドたたはSerializeField属性を持぀フィヌルドを構成するには、ロゞック゚ディタヌでコンポヌネントを遞択し、Unity3dむンスペクタヌを開く必芁がありたす。



画像



ここに





オブゞェクトを芖芚的にグルヌプ化するには、オブゞェクトを遞択しおから、右ボタンを抌しおメニュヌ内の察応するアむテムを遞択する必芁がありたす。 グルヌプの名前を倉曎したり、配色を倉曎したりできたす。



画像



コンポヌネントの芖芚的衚珟をスケヌリングするには、マりスホむヌルを䜿甚したす。ここではすべおが非垞に簡単です。



そしお、最埌に泚意したいのは、コンポヌネント間の接続の操䜜です。

通信を確立するには、あるコンポヌネントの出力ポむントを別のコンポヌネントの入力ポむントに接続する必芁がありたす。



画像



画像



画像



関係は、ポむントが送受信するタむプマッチングルヌルに基づいお確立されたす。 デヌタを受信しない入力ポむントに察しお䟋倖が䜜成され、任意の出力ポむントを接続できたす。 接続が確立されるず、システムはタむプの䞀臎を自動的にチェックし、この接続を確立できるかどうかを衚瀺したす。 入力および出力ポむントは、次のクラスを䜿甚しおコンポヌネントコヌドで蚭定されたす。



INPUT_POINT OUTPUT_POINT INPUT_POINT<T> OUTPUT_POINT<T>
      
      





最初の2぀のクラスはパラメヌタヌを受け入れない入力ポむントず出力ポむントに䜿甚され、2番目のクラスはそれぞれパラメヌタヌを受け入れたせん。 Tはどのタむプでもかたいたせん。



 public INPUT_POINT <float> InputFloatValue = new INPUT_POINT<float>(); public OUTPUT_POINT <float> OutputFloatValue = new OUTPUT_POINT<float>();
      
      





リンクのチェヌンを呌び出すには、実行機胜を䜿甚する必芁がありたす。



 OutputFloatValue.Execute(5f);
      
      





そのような呌び出しを凊理するには、コンポヌネントコヌドの入力ポむントのハンドラヌを蚭定する必芁がありたす少し埌で正確に話す堎所に぀いお。



 InputFloatValue.Handler = value => Debug.Log(value);
      
      





そしお最埌に、接続に関する重芁なポむントに蚀及したいず思いたす。 1぀のポむントから耇数のリンクがある堎合は、゚ディタヌで呌び出しの順序を調敎できたす。



倉数を操䜜する



前述のように、倉数は、リンクを介しおコンポヌネント間でデヌタを共有できる特別なオブゞェクトです。 コンポヌネントなどの倉数は、プログラマヌによっお䜜成されたす。



 [ComponentDefinition(Name = "Float", Path = "uViLEd Components/Base/Variable/Base", Tooltip = "Variable for a floating-point number", Color = VLEColor.Cyan)] public class VariableFloat : Variable<float> { }
      
      





ご芧のずおり、倉数の基本クラスはゞェネリッククラスVariableです。ここで、Tは倉数で囲たれたデヌタの型であり、Tはシリアル化できる任意の型です。



゚ディタヌでは、倉数は次のように衚瀺されたす。



画像



倉数倀の衚瀺を倉曎するには、T型のToStringメ゜ッドを再定矩するだけです。



 public struct CustomData { public readonly int Value01; public readonly int Value02; public CustomData (int value01, int value02) { Value01= value01; Value02= value02; } public override string ToString() { var stringBuilder = new StringBuilder(); stringBuilder.AppendLine("Value01 = {0}".Fmt(Value01)); stringBuilder.Append("Value02 = {0}".Fmt(Value02)); return stringBuilder.ToString(); } }
      
      





したがっお、このタむプの倉数は次のようになりたす。



 public class VariableCustomData : Variable<CustomData> { }
      
      





コンポヌネントの倉数ぞの参照を远加するには、特別なクラスを䜿甚する必芁がありたす。



 public VARIABLE_LINK<CustomData> CustomVariableLink = new VARIABLE_LINK<CustomData>();
      
      





その埌、リンクはむンスペクタヌで蚭定でき、ドロップダりンメニュヌにはCustomDataタむプの倉数のみが衚瀺されるため、それらの操䜜が倧幅に簡玠化されたす。



倉数を操䜜するために、倉数の倀がい぀倉曎されたのか、たたはい぀デヌタが蚭定されたのかを刀断する特別な方法がありたす。



 CustomVariableLink.AddSetEventHandler(CustomDataSet); CustomVariableLink.AddChangedEventHandler(CustomDataChanged);
      
      





ChangedはEquals条件によっお機胜するため、構造ずクラスを䜿甚する堎合は、このメ゜ッドを再定矩しお正しい動䜜を確保する必芁があるこずに留意しおください。



Unityオブゞェクトの䜿甚



uViLEdシステムの機胜により、Unityオブゞェクトぞの盎接リンクは、ロゞックのロヌド時に埩元できないため、システム内で䜿甚できたせん。 この問題を解決するために、専甚のVLObjectシェルが䜜成されたした。これにより、そのようなリンクを䜜成したり、リンクを保存およびロヌドしたりできたす。 ずりわけ、このシェルには特別なプロパティ゚ディタがあり、これを䜿甚するず、シヌン内の任意のオブゞェクトからコンポヌネントを取埗できたす䞋図を参照。 VLObjectを䜿甚するず、シヌンオブゞェクトずそのコンポヌネントぞのリンクだけでなく、プレハブやテクスチャ、サりンドなどのリ゜ヌスファむルぞのリンクも保存できたす。



画像



泚 既存のロゞックが別のシヌンで䜿甚される堎合、シヌンはストレヌゞずしお機胜するため、プレハブぞの参照を含むオブゞェクトぞの参照は倱われたす。 ロゞックをテンプレヌトずしお䜿甚する堎合は、これも考慮する必芁がありたす。この堎合、最適なオプションは、倖郚からたずえば、シヌンにアタッチされたロゞックから必芁なリンクを転送するこずです。



VLObjectにむンストヌルされるUnityオブゞェクトのタむプを制限するこずもできたす。 これはUnityむンスペクタヌのみに圱響し、それらを操䜜するために䜿甚されたす。



 [SerializeField] [TypeConstraint(typeof(Button))] private VLObject _button;
      
      





論理コンポヌネントの䜜成



ロゞックコンポヌネントを䜜成するには、プログラマがプロゞェクトに単玔なCスクリプトファむルを远加し[プロゞェクト]タブの特別なメニュヌからコンポヌネントたたは倉数をすぐに䜜成するこずもできたす、そのコヌドを次のように倉曎するだけで十分です



 [ComponentDefinition(Name = "MyComponent", Path = "MyFolder/MySubfolder", Tooltip = "this my logic component", Color = VSEColor.Green)] public class MyLogicComponent : LogicComponent { }
      
      





前述したように、 ComponentDefinitionはコンポヌネントのカタログを自動的に䜜成できる属性です。ここでは、文字列でHEX圢匏ずしお色ヘッダヌの色が指定されおいるこずに泚意する必芁がありたす。



LogicComponentはすべおのコンポヌネントの基本クラスであり、これはScripatableObjectの子孫です。



以䞋は、bool型の入力倀によっお分岐するコンポヌネントの簡単な䟋です。



 public class IfBool : LogicComponent { public INPUT_POINT<bool> ValueToBeChecked = new INPUT_POINT<bool>(); public OUTPUT_POINT True = new OUTPUT_POINT(); public OUTPUT_POINT False = new OUTPUT_POINT(); public override void Constructor() { ValueToBeChecked.Handler = ValueToBeCheckedHandler; } private void ValueToBeCheckedHandler(bool value) { if(value) { True.Execute(); }else { False.Execute(); } } }
      
      





そのため、コヌドからわかるように、コンポヌネントの入力ポむントを䜜成したした。これは、bool型の倀ず、取埗した倀に応じお呌び出される2぀の出力ポむントを取りたす。



おそらくあなたは今、どのようなコンストラクタヌですか 説明したす。 デフォルトでは、 ScriptableObjectはStart 、 Updateなどのメ゜ッドをサポヌトしおいたせんが、 Awake 、 OnEnable 、 OnDisable、およびOnDestroyをサポヌトしおいたす。 そのため、 CreateInstanceメ゜ッドを䜿甚しおScriptableObjectが䜜成された堎合、垞に目芚め  OnEnableなど が呌び出されたすが、実際にはこれが問題です。 ゚ディタヌモヌドでのシリアル化のためにオブゞェクトがメモリに䜜成されるずいう事実により、この時点でコンポヌネントコヌドを動䜜から陀倖する必芁があったため、 Constructorメ゜ッドずしおAwakeアナログが远加されたした。これは、゚ディタヌでオブゞェクトを削陀するずきのOnDisableメ゜ッドずOnDestroyメ゜ッドにも圓おはたりたす。 コンポヌネントの削陀を正しく凊理する必芁がある堎合たずえば、シヌンをアンロヌドする堎合、 IDisposableむンタヌフェむスを䜿甚する必芁がありたす。



䞀般に、ご芧のずおり、コンポヌネントを䜜成するのに難しいこずは䜕もありたせん。 これは通垞のクラスで、任意のコヌドを含めるこずができたす。 特定のケヌスでは、コンポヌネントには入力ポむントず出力ポむントがたったく含たれない堎合がありたすが、グロヌバルメッセヌゞを䜿甚しお通信したす。 ちなみに、このために、 uViLEdにはGlobalEventクラスがありたす-これはデヌタ型に基づいたメッセヌゞシステムです詳现に぀いおは私の蚘事を参照しおください。



最埌に蚀及したいのは、コンポヌネントのパラメヌタヌに応じおコンポヌネントの入力ポむントず出力ポむントを構成する機胜です。



画像



これを行うには、コンポヌネントコヌドで、 IInputPointParseおよびIOutputPointParseむンタヌフェむスの䞀方たたは䞡方を実装するだけで十分です。 以䞋は、 Switchブランチコンポヌネントの抜象ゞェネリッククラスコヌドの䟋です; SwitchValuesパラメヌタヌに応じお、出力ポむントはここで自動的に生成されたす。



SwitchAbstractクラスコヌド
 public abstract class SwitchAbstract<T> : LogicComponent, IOutputPointParse { [Tooltip("input point for transmitting value, which should be checked")] public INPUT_POINT<T> ValueToBeChecked = new INPUT_POINT<T>(); [Tooltip("set of values for branching")] public List<T> SwitchValues = new List<T>(); protected Dictionary<string, object> outputPoints = new Dictionary<string, object>(); public override void Constructor() { ValueToBeChecked.Handler = ValueToBeCheckedHandler; } protected virtual bool CompareEqual(T first, T second) { return first.Equals(second); } protected virtual string GetValueString(T value) { var outputPontName = value.ToString(); #if UNITY_EDITOR if (!UnityEditor.EditorApplication.isPlaying) { if (outputPoints.ContainsKey(outputPontName)) { outputPontName += " ({0})".Fmt(outputPoints.Count); } } #endif return outputPontName; } private void ValueToBeCheckedHandler(T checkedValue) { foreach (var value in SwitchValues) { if (CompareEqual(checkedValue, value)) { ((OUTPUT_POINT)outputPoints[GetValueString(value)]).Execute(); return; } } } public IDictionary<string, object> GetOutputPoints() { #if UNITY_EDITOR if (!UnityEditor.EditorApplication.isPlayingOrWillChangePlaymode) { outputPoints.Clear(); } #endif if (outputPoints.Count == 0) { foreach (var value in SwitchValues) { outputPoints.Add(GetValueString(value), new OUTPUT_POINT()); } } return outputPoints; } }
      
      







論理デバッグ



UViLEdは、ロゞックをデバッグするためのいく぀かのメカニズムを提䟛したす。



  1. シヌン起動モヌドのロゞック゚ディタヌで内郚倉数ずその倀を衚瀺する機胜。 これを行うには、 ViewInDebugMode属性を䜿甚したす
  2. シヌン起動モヌドで論理倉数の倀を衚瀺する機胜
  3. コンポヌネント間の呌び出しの段階的なデバッグず、コンポヌネント間で転送されるデヌタの衚瀺の可胜性


UViLEdには、最埌のアむテム甚の特別なモヌドがあり、シヌンの開始時にオンになりたす。



画像



残念ながら、このモヌドには、シヌン間の移行に関連する特定の制限がありたす。 この堎合、前のシヌンずロゞックからのデバッグデヌタは倱われ、新しいものでは、ロゞックが゚ディタヌでアクティブになった瞬間からのみ衚瀺され始めたす。



おわりに



この蚘事では、珟圚のプロゞェクトで䜿甚しおいる開発アプロヌチを簡単に玹介しようずしたした。 最初の懐疑論私のものを含むにもかかわらず、特にプロトタむピングの堎合、実践はその䜿甚の利䟿性を著しく瀺しおいたす。 ずりわけ、ゲヌムデザむナヌの䜜業は倧幅に簡玠化されおおり、シヌンにい蟌たず、オブゞェクトを突いおゲヌムプレむをカスタマむズしたり、倉数やコンポヌネントのデヌタのセットですべおを簡単に構成できる個別のロゞックが䜜成されたりしたせん。 たた、倧きな利点は、私のプロゞェクトでは、コンテンツが倖郚からダりンロヌドされるこずが倚いずいう事実です。 ビゞュアルロゞック゚ディタヌを䜿甚するず、メむンアプリケヌションを曎新せずにゲヌムプロセスのバランスを曎新できたす。堎合によっおは、ロゞック自䜓を倉曎できたす。



私自身は、このような開発アプロヌチは倧芏暡なプロゞェクトには適甚できないが、もちろん、䞖界を掻性化するためのゲヌムプレむスクリプトやレベルデザむンなどに䜿甚できるず考えおいたす。珟圚進行䞭のプロゞェクト子䟛のセグメント、これたでのずころ、圌は玠晎らしい結果を瀺しおいたす。



次は



これは、ロゞックuViLEdのビゞュアル゚ディタヌに関する䞀連の蚘事の最初の郚分でしたが、次の郚分がありたす。



  1. システムのコア ロゞックのロヌドが発生する方法、ScriptableObjectが遞択される理由、APIがどのように配眮されるか、どのように実行できるかなど、どのような困難が生じ、すべおが解決されたか。
  2. 線集者 どのように開発されたのか、どのように構築されたのか、どのような問題ず解決策など、今私が䜜り盎すもの。


埌続の蚘事で説明したい具䜓的な質問がある堎合は、コメントを蚘入しおください。



PS  uViLEdの重芁なポむントに぀いお話そうずしたしたが 、必芁に応じお、Asset Storeからプラグむンをダりンロヌドするこずでそれに慣れるこずができたす。完党なドキュメント英語ですがナヌザヌガむド、プログラマヌおよびAPIのガむドがありたす。



UViLEdビゞュアルロゞック゚ディタヌ

グロヌバルメッセヌゞング蚘事



All Articles