這兩天,有關游戲引擎腳本系統的預研還在繼續。在google上找了一些資料來學習,目前網絡上這部分的資料是比較少的,主要還是在gamedev上有一些相關的主題。泡了兩天的鳥文論壇,做了一打的摘錄。現在整理一下思緒,感覺腳本系統的輪廓已經比較清晰了,但還有很多細節需要去了解,后續會對這些細節再慢慢研究道來。
腳本的基本特性
1、從語法的角度來說需要支持到順序、條件、循環,并且最好語法接近某種成熟語言(比如C),這樣有利于學習&使用;
2、性能,性能,性能。要在實時的游戲里面發揮作用,性能無異是貫穿始終的話題。
語法功能解決方案
1、可以選擇一門成熟語言作為借鑒;
2、刪掉不需要的Keyword,裁剪語言元素。特別對于C語言,完全去掉有關函數聲明等部分可以大大降低parse&excute的復雜性。
腳本庫
1、腳本語言的函數庫比腳本語言的語法更加重要,這個說法的出發點仍然是性能。在上一篇文章中,我有提到“冗余”的概念,就是這句話很好的體現。盡量將復雜的函數功能封裝在游戲引擎本身,而不要在腳本中編寫這些函數,甚至可以在腳本中不提供用戶自定義函數的功能。
2、提供給用戶(腳本編寫者)完善的庫函數集,從環境配置命令到信息查詢等等。用戶用這些函數來控制游戲環境,腳本語法只是提供分支&循環控制。
事件響應
1、上篇提到“事件”(event)指的是所有外設輸入的統稱,這種說法是不全面的。除了外設輸入,事件還可以由游戲引擎內部來觸發,比如timer事件,這里做一個小小的更正。
2、事件包含一些參數,參數的內容是“哪些Object要響應”&“事件類型”。
3、一個腳本可以調用其他腳本,實現腳本之間的通信。
4、事件,可作為腳本系統&游戲引擎的連接,也就是說,游戲引擎只有在處理事件的時候才會調用腳本系統,而腳本系統的唯一任務,就是響應事件。
5、再次強調一下,事件不是只能有游戲引擎內部的object來觸發,還有timer、startUp、sceneEnd等等。
腳本運行模型
1、每個腳本都可以“掛”到任何數量的object上去;
2、每個腳本都可以看作是獨立的虛擬機,擁有自己獨立的變量、堆棧&運行點(execution pointer),這一點我自己有保留的想法,出于性能原因,可能獨立虛擬機的概念難以實施,需要進一步尋找變通的方法。
訪問控制
1、上篇提到腳本需要能讀取&改變游戲引擎內部object的屬性,這里需要注意一個問題:讓腳本直接訪問object的屬性是很危險的事情,出于defensive coding的考慮,個人認為不應該讓腳本直接地來訪問內部數據,而應該提供庫函數,通過庫函數來對內部數據進行訪問,這樣做的好處是:將邊界檢查等等安全性工作加入了進來,并且讓腳本編寫者在編寫腳本的時候不用對安全性進行考慮;壞處是:肯定效率是有所降低的。(或者還有更好的辦法?想想。。。)
庫函數
1、庫函數的實質是C/C++(引擎編寫語言)的函數指針,對于腳本系統來說它們是可見的全局symbols。這里引入兩個小話題:一是在引擎初始化的時候,需要注意建立這些函數的入口地址表,讓引擎在需要調用的時候有表可查;二是,java呢?有沒有類似函數指針的東西?(這里屬于實現階段的問題,我只是提出,沒有去研究)
2、腳本運行的時候,如果遇到調用庫函數,則跳轉到native C/C++代碼去。這里存在運行環境切換的問題,從腳本語言的堆棧里彈出參數,傳給native C/C++函數來執行,執行結束以后,返回結果壓入腳本語言的堆棧中。如果把游戲引擎看做虛擬機,那么腳本系統就是嵌套在這個虛擬機里面的虛擬機,^_^,拗口哦,不知道您明白了沒有?
====================================================================================================
以上討論的,是運行與游戲引擎部分的腳本系統。以下的,是有關腳本本身的一些討論,這個應該歸屬于游戲制作工具的一部分。
====================================================================================================
編譯
1、當然,這個步驟叫“解釋”,與C語言一類編譯式語言有所區分的話更加準確。但由于在做法上跟C是類似的,所以也可以叫“編譯”。
2、兩個階段:一是把腳本源代碼拆成語言元素,token,不知道這個用哪個中文表達好,編譯原理學了都忘了;二是把所有token組織起來,組成基本命令序列。
3、什么“基本命令序列”?剛才不是說把腳本看過虛擬機嗎?這個“基本命令”就相當于這個虛擬機CPU的機器指令或匯編指令。也就是對于這個虛擬機來說的可執行代碼。
“匯編指令”
1、為了簡單,就把腳本這個虛擬機設計成單堆棧的吧。
2、基本的命令包括:push,pop,go,stop,callfunc,add,asign等等。
舉個小例子吧:比如寫了如下的腳本(語法上近C)
a = 1 + 2;
通過編譯,變化成如下的“可執行序列”:
push 1
push 2
pop // store 1
pop // store 2
add // store result
push 3 // push result
pop // store 3
pop // var name a
asign // a = 3
這里只是示意,可能與實際實現有出入。
這篇略顯枯燥了,聊點輕松的。一直在強調腳本語言的性能問題,來看看 各種語言性能比較 吧。LUA好像在腳本語言里面排名靠前呵,我正好也下載了它的源碼,并在VC上編譯好了。在Python&LUA之間猶豫了一下,還是選擇LUA吧,比較小,簡單,Python目前已經做得很復雜了。再說偶的腳本系統里面目前不需要提供自定義函數機制,也不需要OO滴,看看幾個月后能不能作出自己的腳本語言來?到時候再跟Python等等一較高低!:)
好戲在后頭哦,下期開始實際以LUA為例子研究腳本系統了。。
posted on 2007-06-01 22:35
tianlinux 閱讀(1175)
評論(2) 編輯 收藏 所屬分類:
腳本語言