一看之下,竟然是這種奇異的寫法:
function OnGUI () {
if (GUI.Button (Rect (10,10,150,100), "I am a button")) {
print ("You clicked the button!");
}
}
其原理是,Unity 在一個 frame 裡會執行這個函式最多兩次,第一次 GUI.Button() 會渲染那個按鈕,第二次是處理輸入,如果GUI.Button()被按下,就傳回 true。後來再在網上找到了相關的討論及短片(我無看足全程),稱傳統的 GUI 系統為 Retained Mode (下簡稱RM),這種系統為 Immediate Mode (下簡稱IM)。
傳統的 RM 做法是建立 GUI 物件的 Hierarchy,之後當有輸入時就通知應用程式 (event-driven)。而 IM 就不需要建立物件,純粹以 procedural 的運行方式顯示及處理反饋。
乍看之下,IM 的函式非常簡單,亦不需要額外的記憶體,好像是一個很好的方案。但再想了一會,相對 RM 的做法好像沒有那麼好:
- 其實 IM 和 RM 都要用一定的內存。如果 RM 是用 Script 或描述檔案 (e.g. XML) 來產生 GUI 物件,那段 Script 或描述檔案 在產生 GUI 物件之後就可以釋放,而它所描述的訊息只是轉化為內存的物件吧。所以兩種方法也是包含同樣的資訊,只是形式不同。
- IM 的 GUI 是 Stateless 的。因此一些需要 state 的 GUI 物件需要由函式外傳入及取回,例如
textFieldString = GUI.TextField (Rect (25, 25, 100, 30), textFieldString); - IM 執行效率應比一般的 RM 低。渲染 GUI 是每個 frame 都要處理的,而發生輸入事件的頻率相對非常低。IM 需要每個 frame 運行 Script,而 RM 可以在 C++ 獨立處理 GUI Hierarchy 的渲染,並且處理輸入後才產生 event 通知 Script。但如果 IM 的代碼也是用 C++ 寫的話,情況可能會相反,因為所有 GUI call 都是 static binding,而一般 RM 的做法都需要 virtual function call (例如渲染的函式)。
- 要做 IM GUI 的編輯工具比較困難。可能要用 RM 的資料去生成 IM 的代碼,但這樣做的話,連 event handling 的代碼也要從 RM 的資料插進去 IM ,那麼,IM 就好像沒有意義了。這可能就是 Unity 沒有 GUI 編輯工具的原因。
- 和第 4 點相關,RM 把物件的狀態描述和行為分離,減低 coupling。而 IM 反而應為兩者結合在一起編程比較容易。這讓我想起用 C 寫 CGI 和用 XML/XSLT 做網頁的日子......
P.S. 今天無代碼上的進展......
2 則留言:
好高興有一點新的東西沖擊下哩.
訓身做 (正確 D 應該係 維護至真) 同一個 Project 太長時間無洗創意.
1) 很難說...VM 用的內存很難估計. 不過物件用的內存一定遠遠多過句 string.
2) 可以是好處, 因為唔洗另外同 application syn state. 不過像 ScrollBar 可以如何哩.
3) 如果 IM 是用 C++ 寫的話, memory locatitly 會很好, 令效率有可能勝過 RM.
4) 同意. 但 GUI 最終也要寫 Logic.
5) 同意, 有點 back to C from OOP, 旦不一定是壞事.
有個疑問: Radio button grouping 可以如何?
還有... 你知道什麼是 Pull XML parser 嗎? Luicd2 正使用它哩.
有了 Pull API, SAX 也可以輕易 build on top of it.
Radio button 和其他需要 hierarchy 的物件都可以用 grouping 來實現。例如:
BeginRadioButtonGroup()
r1 = RadioButton(pos1, "R1", r1)
r2 = RadioButton(pos2, "R2", r2)
EndRadioButtonGroup()
但 radio button 最簡單就是用一個control 放齊可選擇的 button,例如
sel = RadioButtonGroup(pos, { "R1", "R2" }, sel)
ScrollBar 只有一個 value state,和 textbox 一樣。
你告訴我才知道 Pull XML,好像比 event-driven 的 SAX 更有彈性。最少解決你之前要用 multi-thread 的 consumer-producer 形式來讀 XML。
但是,相對 SAX 有缺點嗎? 有沒有 C/C++ implementation?
P.S. 我這陣子也有想 serialization 的問題。想在 tools 用 C# 的 XML/binary serialization,之後轉作執行時期的版本。曾經有個想法是用 Lua 做執行時期的 serialization 版本。不過還未詳細研究。
發佈留言