最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

Unity編輯器擴展:使用xNode制作自己的可視化工具(2)

2021-04-13 16:51 作者:皮皮關(guān)做游戲  | 我要投稿

(本文作者 @對馬騎馬使用炎拳 )

大家好,我是炎拳。

上一篇文章:皮皮關(guān):使用Xnode制作可視化劇本編輯插件(1),簡單的展示了我使用xNode 制作的小工具,這一篇就來分享下Xnode的用法,以及在開發(fā)過程中收獲的一些編輯器擴展的知識。

在使用xNode 開發(fā)前,還是需要略微了解一些Unity3D中的定制特性:例如當(dāng)你不想在面板上顯示你的公開字段,你可以在字段上添加[HideInInspector],它的功能是在Inspector面板中隱藏public屬性,沒有序列化的功能。

我簡單寫了一篇讀書筆記,給同樣是新手的朋友做個參考:

Unity3D 中的定制特性以及簡單的編輯器擴展案例blog.csdn.net

引用書中的一段話簡單解釋就是:“定制特性其實是一個類型的實例。Mono之所以能跨平臺原因便是其符合”公共語言規(guī)范(Common Language Specification (CLS))“的要求,根據(jù)公共語言規(guī)范定制特性類必須直接或者間接從公共抽象類System.Attribute派生?!?/p>

知道了C#中的特性是從System,Attribute 派生而來的一個類的實例。同樣,Unity中C#的游戲腳本也有派生自system.Attribute中的特性,Xnode 中的定制特性同樣如此。



1 xNode的用途和下載途徑

再簡單的介紹下xNode,它是一個完全開源的免費插件,官方文檔的介紹很吸引人:

  • xNode是超級用戶友好的,直觀的,它將幫助您快速了解節(jié)點圖。由于占用的空間很小,它非常適合作為自定義狀態(tài)機、對話系統(tǒng)、決策樹的基礎(chǔ)架構(gòu)。

xNode官方文檔也較為齊全,節(jié)省了我很多學(xué)習(xí)時間,在Github上獲取最新的xNode工程,扔到你的Unity工程下就可以使用了,地址在這:

https://github.com/Siccity/xNode

圖標(biāo)

2 ?xNode的核心概念

援引自官方文檔,一個xNode項目由這三個部分組成:

Graph:

每個xNode項目都從創(chuàng)建Graph開始,Graph可以看成是你圖形化界面的入口,新建一個自定義Graph也很簡單,以我的工具為例:

using XNode;?

//通過Unity菜單來創(chuàng)建自定義

Graph

?[CreateAssetMenu(fileName = "DialogueGraph")]

? ?public class DialogueGraph : NodeGraph

? ?{ ? ?}

然后通過菜單生成新的Graph,Graph中包含了項目中Node列表的信息,可以在面板上直接進行操作:

接著看看自定義Graph的父類NodeGraph,可以發(fā)現(xiàn)它也同樣是繼承了Unity ? ScriptableObject的抽象子類,并且提供了豐富的Node相關(guān)虛方法:

對ScriptableObject感興趣的朋友可以自行搜索資料,不懂也沒關(guān)系,你只要知道它的用法就好:在編輯器會話期間,將數(shù)據(jù)保存為項目中的資源,這樣方便在項目運行的時候使用。

Node:

自定義Graph繼承自NodeGraph,自定義的Node繼承自Node,一個標(biāo)準(zhǔn)的Node包含單個輸入端口和輸出端口,通過對任意公開字段添加[Input]或[Output]屬性生成:

public class SimpleNode : Node {

? ?[Input] public float value;

? ?[Output] public float result;

}

Node同樣是一個繼承自ScriptableObject的抽象類,從Node派生出的任何自定義Node子類,都是有效節(jié)點,同時會默認添加到Graph的上下文菜單中,如圖所示:

也可以自定義Node的樣式和名稱

?[CreateNodeMenu("SimpleNode1111111")]

? ?[NodeWidth(400)]

? ?[NodeTint(73, 236, 209)]//Node顏色

? ?public class SimpleNode : Node ? ?

????{ ? ? ? ?

????????[Input] public float value; ? ? ? ?

????????[Output] public float result;

? ?}

Port:

端口(port)是節(jié)點(Node)之間通信的大門,他們既可以是輸入,也可以是輸出。一個Node可以包含多個port。

一般只要Unity能序列化的類型都可以作為端口,當(dāng)然我們可能需要在Node上動態(tài)添加或者刪除端口,這里就需要去定義單獨Node上端口的渲染了,之后會詳細說。

這里放個端口的常見用法(在Node類中):獲取其連接的node

// Get the connected node.

NodePort otherPort = GetOutputPort("myOutput").Connection

if (otherPort != null) {

?MyNode nextNode = otherPort.node as MyNode;

}



介紹完基礎(chǔ)概念,接下來分享下制作這個劇本編輯插件的過程和一些有意思的問題:

首先,我的需求是能快速制作一段類似《星露谷物語》中過場演出,雖然玩家觸發(fā)劇情的時間和方式都比較隨機,但還是每段劇情本身還是遵循傳統(tǒng)的樹狀敘事結(jié)構(gòu),通過玩家的選擇來觸發(fā)劇情:

但在《星露谷物語》中,玩家和NPC對話的過程會時不時穿插一些人物的動作和表情,來豐富演出效果,伴隨的可能有對話UI短暫消失等待人物動畫播放完成,終止UI點擊事件等需求。所以我需要為每一段對話提供一些功能選項,方便快速配置這些功能。

如何定義每段對話也很重要,Xnode Graph所采用的渲染方法來自Unity的EditorWindow類,移動鼠標(biāo)時會強制調(diào)用OnGUI()進行刷新,所以Graph中的Node越多,刷新次數(shù)就越多,不少開發(fā)者也遇到了大量Node存在時刷新卡頓的問題。如果每段對話都使用一個Node,那200句話可能就要新建一個Graph,并且修改起來十分麻煩,所以最終我希望能在一個Node中盡可能的添加對話,所以對話Node應(yīng)該是這樣:

功能如下:對話依次向下播放,根據(jù)對話類型,對話框展示出不同的效果。如果一段對話過長或者遇到了選擇分支,也可以更改對話類型來主動生成一個輸出端口進行跳轉(zhuǎn)。

思路清晰了,但問題是怎么在Xnode上渲染出這樣的界面呢?xNode提供了解決方案,首先是更加深入的自定義Node外觀,官方提供了一個簡單的加法器案例:

// SimpleNode.cs

public class SimpleNode : Node{

? ?public int a;

? ?public int b;

? ?[Output] public int sum;

//獲取對應(yīng)端口的值

? ? public override object GetValue(NodePort port) {

? ? ? ?return GetSum();

? ?}

? ?public float GetSum() {

? ? ? ?return a + b;

? ?}

}


// Editor/SimpleNodeEditor.cs?

//用于關(guān)聯(lián)你需要自定義的Node

[CustomNodeEditor(typeof(SimpleNode))]

public class SimpleNodeEditor : NodeEditor {

? ?private SimpleNode simpleNode;

? ?public override void OnBodyGUI() {

? ? ? ?if (simpleNode == null) simpleNode = target as SimpleNode;

? ? ? ?// Update serialized object's representation

? ? ? ?serializedObject.Update();

????????NodeEditorGUILayout.PropertyField(serializedObject.FindProperty("a"));

????????NodeEditorGUILayout.PropertyField(serializedObject.FindProperty("b"));

????????UnityEditor.EditorGUILayout.LabelField("The value is " + simpleNode.GetSum());

????????NodeEditorGUILayout.PropertyField(serializedObject.FindProperty("sum"));

? ? ? ?// Apply property modifications

? ? ? ?serializedObject.ApplyModifiedProperties();

? ?}

}

自定義內(nèi)容的問題貌似解決了,照葫蘆畫瓢就好,但如何讓xNode根據(jù)一個對話列表來生成多個端口呢?官方也提供了一個實驗性質(zhì)的方法-Dynamic Port List:

public class SimpleNode : Node {

? ?[Output(dynamicPortList = true)] public float[] myArray;

}

看起來圖中的節(jié)點作為劇本中的選擇項不錯,但作為對話節(jié)點還是過于混亂了,我并不需要每個對話元素都顯示一個端口。

好在xNode 給我們提供了自定義繪制列表的方法,實際上最新版本的xNode中已經(jīng)集成了部分Odin的功能(不知道它怎么打通關(guān)節(jié)的哈哈),Odin同樣是一款繪制Unity界面非常好用的工具,比方說Unity和C#并未支持字典的序列化,在Odin的支持下我們可以很輕松的讓字典在Unity Inspector面板中顯示并修改:

在xNode的界面同樣支持Odin,但我對Odin的了解不多,還是沒法達成想要的效果,最終還是選擇使用Unity自身的編輯器拓展方法,原因也很簡單,xNode本身繪制列表的方法也是使用Unity ReorderableList(可重排序列表),其中元素可以自由拖動,非常方便,感興趣的朋友可以看看這篇文章:

https://blog.csdn.net/qq_26999509/article/details/77801852

最終我做出來的效果如下:

代碼還挺長的,感興趣的朋友可以直接去上一篇文章中下載工程看看,只提一點很重要的,xNode本身并未考慮到我這樣奇葩的需求,一開始我發(fā)現(xiàn)并不能通過修改類型自由生成Port,最后在老師的幫助下發(fā)現(xiàn)了原因,稍微改了下DynamicPortList這個方法,有需要的朋友可移步至知乎專欄原文中自?。?/p>

https://zhuanlan.zhihu.com/p/364501563/

對話列表中元素的類,自定義繪制List及其中元素的方法均可在原文中獲取到。



最后再聊聊程序?qū)崿F(xiàn)的思路,實際上和樹狀敘事一樣,首先得有一個StartNode,用于定位這段劇本從哪開始;再進入ChatNode或是OptionNode,根據(jù)每個元素的類型決定如何播放對話,之后在程序中獲取所有的Node,根據(jù)類型依次執(zhí)行就好了。

我在其中又增加了自由觸發(fā)方法的對話類型,只需要提前在面板上手動注冊過方法,就可以在對話過程中自由調(diào)用,通過這種方法和Unity Timeline的Signer配合使用,最后大致完成了想要的過場演出~


總結(jié)下來,實際上這個工具配合Timeline還是有很多不足,因為暫停和播放TimeLine都是由Graph中的數(shù)據(jù)控制的,實際上應(yīng)該由Timeline來主導(dǎo)這一切。這導(dǎo)致我對Timeline播放的時間無法直觀的控制,之后可能還會改進。

市面上已經(jīng)有不少完善強大的劇本編輯插件,但自己造輪子的過程確實收獲頗多,最后放個xNode文檔鏈接:

https://github.com/Siccity/xNode/wiki


(本文作者 @對馬騎馬使用炎拳 )

歡迎加入游戲開發(fā)群歡樂攪基:1082025059

對游戲開發(fā)感興趣的童鞋可戳這里進一步了解:http://www.levelpp.com/

我們的公眾號:“皮皮關(guān)"



Unity編輯器擴展:使用xNode制作自己的可視化工具(2)的評論 (共 條)

分享到微博請遵守國家法律
呼和浩特市| 上饶县| 凤城市| 蓬溪县| 韶山市| 芷江| 杭州市| 内丘县| 哈尔滨市| 梁平县| 隆昌县| 永新县| 镇远县| 滦平县| 隆子县| 扎囊县| 威远县| 漾濞| 福泉市| 绿春县| 健康| 沈阳市| 满洲里市| 呼图壁县| 嘉祥县| 布拖县| 四会市| 花莲县| 仙桃市| 弥渡县| 崇仁县| 沙雅县| 浪卡子县| 荣昌县| 独山县| 寿宁县| 明水县| 伊吾县| 巴东县| 长沙市| 湘潭市|