前言:
用regex做的,雖然它稱不是是個"語言",但我想不到更好的名詞了。
想起自己第一次做有對話系統的遊戲是3、4年前了,當時的方法蠢到用判斷行數去執行對應動作。
最近想有沒有更好的方法,更簡單,讓文本自己就能處理的方法,得出的結論就是"乾脆把文本當程式碼打"。
當然,對話系統的插件一定有很多種,也一定做得更好、更穩定。這次上來分享這個小拙作想看看各位有甚麼想法,或改善的建議。
基本概念:
demo 專案影片 (用之前參加game jam的美術圖):
說明:
整個專案除了玩家、攝影機移動之外都是用這個工具進行的,(例如對話、切換場景、劇情邏輯判斷)。
一開始選擇語言,第一個場景示範切換場景。
第二個主要遊戲場景中主要的劇情邏輯有:
還沒跟兒子對話前,跟村民的對話劇情是日常的閒聊話。
第一次跟兒子對話,他會要求媽媽拿玩具給他,這時候跟小朋友的對話內容改成要求玩具,拿完玩具再跟小朋友對話則變成閒聊話2。
玩具給兒子後,他要求媽媽找5顆糖果給他,在糖果沒收集齊全前,跟兒子的對話都會說"不夠,目前只有xx顆糖果"。其中xx是動態變數。村民的對話也變成要求糖果,拿完糖果後對話變成閒聊2。
每個可對話物件都是在自己1個文本裡判斷的。
範例 兒子的文本:
其他文本檔案在
專案下載與語法說明 連結
以下簡略說明一下語法,小屋有比較詳細的使用說明:
- 用<story> </story> 開頭、收尾。
- 非tag以外內容需要出現<>, 則加上 \ (跳脫符號) 在<>前。 (我regex能力的最限就是想出這個方法了
)
- 例如<l > \<color=red\> Red content text! \</color\> </l>
<l> </l>
"l" 代表每一個對話。
<if> </if>
達成條件才會進行裡面的內容。
<Select> </Select>
創建選單,只能搭配<opt></opt>的tag。
主要的tag就這些,接下來是參數。
animation(gameobjectName,clipName)
尋找場上的物件名稱為"gameobjectName"的物件,並播放動畫名稱為"clipName"的動畫。
audio(gameobjectName, [stop|play|pause])
尋找場上的物件名稱為"gameobjectName"的物件,並設定該AudioSource的狀態。
title ="name"
對話框的標題。
by="gameobjectName"
如果對話框是浮在物件上的風格,用by="物件名稱"找尋該物件。
img([left|middle|right] , path)
如果對話框是像galgame那樣固定畫面的,我預設有分左、中、右,3個image欄位。圖片要放在Resources資料夾下。 left/ middle/ right是在prefab裡面指定的。
set("variableName" = value)
設定變數。若是"temp_"開頭的,會放在暫存的字典裡,對話結束就清除,方便用來做一些無關緊要的選擇性對話。 反之變數會存在整個遊戲(static),但遊戲關掉就沒了,所以請記得處理RPGCore.cs 裡面的StoryRecord存讀取。可以用我這個存讀檔的腳本(字典不能存json,只能存bin)。
$[key]
讀取自訂變數。 例如 $[temp_a]。
enable / disable( obj1,obj2,obj3.....)
開啟或關閉物件。 用find找並加入紀錄中,所以一開始的物件應都設開啟狀態,透過一個開始的文本把物件關閉並記錄,之後才能再開啟。
例如demo有個文本單純就是玩家經過觸發隱藏物件,但因為沒有內容所以馬上結束。
<story disable(toy2)></story>
其他
- 想擴充自己的標記的話,請照著這個格式:functionName( arg1, arg2 ,arg3,arg4.......)在StoryReader.cs裡面的ReadArgs()方法裡有個標註 YOUR OWN SCRIPT FUNCTION 的地方處理。
- 一行內arg可用不只一個。
單純工具主要有RPGCore.cs , StoryReader.cs 和 OptionButton.cs。
- RPGCore主要放Regex和方法,不用實作。要新增語言請找到public enum Lang。然後在Resources資料夾下新增個對應名稱的資料夾。
- StoryReader 主要處理arg和tag解讀與和UI的互動,放在對話框prefab。用StartConversation()開始對話。
- OptionButton 放在選項按鈕prefab,單純回傳告知StoryReader 選擇了什麼。
- 多個StoryTrigger.cs是用來觸發對話的。
目前就這樣,還有些小bug和擴充的內容待加強。
(若執行對話時盪掉,請檢查是否每個tag都有對應的close tag)
簡單說來,regex拆出來的結果長這樣:
tag會按照順序列出,然後用迴圈找出對應的close tag:
感謝收看
