Jan 19 2008

Scripting系統概論與Lua簡介

Lua Programming Language基於我很愛 Lua 這個 Scripting Language(劇本描述語言←有點彆扭的翻譯 Orz)的立場,不先來篇介紹實在說不過去啊。不過在介紹 Lua 出場前,要先把老大哥 Scripting Language 推出來暖暖場才行。

一般的程式語言,在程式碼撰寫完畢後都需要經過編譯 (Compile) 這個步驟,交由程式語言工具的編譯器 (Compiler) 進行語法驗證、程式碼連結與機器碼建立,最後才能產生出所謂的可執行檔 (Executable Files),也就是在 Windows 平台下滑鼠左鍵雙擊就會開始執行的檔案類型。而使用 Scripting Language 編寫好的程式碼,無須經過編譯的步驟就能夠被直譯 (Interpreted) 並且執行。使用 Scripting Language 有點像是使用一組預先定義好的指令集,在直譯器 (Interpreter) 解析到這些指令時,就能夠去執行預先定義好的行為與程式。所以相較於 C/C++ 屬於需要經過編譯才能執行的程式語言 (Compiled Language),Scripting Language 被稱為是一種直譯式的語言 (Interpreted Language)

有了基本的概念之後,首先,應該要問的問題是,為什麼要使用 Scripting Language?Scripting 系統與遊戲開發有什麼關連性?關於這兩個問題,這裡訪問到三位不願具名的受訪者:

  • 程式開發者A君:它可以幫助我們節省開發時間,不用每次做個小更動就要等待程式重新編譯連結,也會減少被企畫騷擾的時間。
  • 企畫設計者B先生:終於可以自由地測試各種想法與做法,而不用每天跑去問程式:請問~這個功能可不可以加一下了。(淚)
  • 美術設計者C小姐:聽說可以用來做 GUI(圖形化使用者介面)耶,不過我沒用過。

在一般遊戲開發的過程中,常見的情境是:程式開發者依據企畫設計者所訂定的文件規格,製作完成某功能後,再交由企畫檢視成果與預想的設計是否符合、是否有需要改進之處,然後再將設計交回程式開發者進行修改,修改完畢後再交由企畫設計者檢閱。以上程序會一直跳針,反覆反覆再反覆直到完成為止。設計本身是一種需要反覆迭代進行的程序,但是太頻繁的來往溝通,可能會殺死程式開發者的專注力與工作效率,也無法使企畫設計者的想法得到迅速的反饋。為了能讓程式開發者放下一點點肩上的擔子,將部分權責交由企畫設計者獨立處理,於是有了各種編輯器與 Scripting 系統的發明。

那麼,運用 Scripting 系統與一般的編輯器來開發遊戲有什麼不同?其實兩者各有所長。編輯器之類的工具,通常是一組程式設計者預設好的功能,讓使用者能夠以直覺化的方式去操作各種程序,例如場景、人物與特效編輯等等。而 Scripting 系統,則帶給使用者更大的權力與更多的可能性,可以提供使用者極大的彈性去調整與預覽製作的成果。要做出好學好用的編輯器,通常是相當曠日費時的工作,並且還需要持續地依照企畫設計者的需求增加功能與修補臭蟲。製作編輯器這項工作,可以說是沒有真正完整完成的時候。相較之下,使用 Scripting 系統需要企畫設計者更多的程式相關知識,但是卻能夠在耗費較少開發時間的情況下,達到最大的彈性與效益。

瞭解為什麼要使用 Scripting Language 之後,下一個問題是,在這麼多種類的 Scripting Language 中,為什麼要使用 Lua?它到底有什麼好處可以勝過其他競爭者?來聽聽官方的說法:

  • Lua 既小且快又不用錢。
  • Lua 是非常易學易用的的一種語言。
  • Lua 與 C/C++ 的整合性很好。
  • Lua 的可移植性極高。

Lua 的核心非常緊實且不佔空間,執行速度優於其他 Scripting Language,可擴充性極高。因為 Lua 語言本身是以 ANSI C 標準寫成,幾乎所有平台上都能夠執行,目前已經有相當多遊戲專案與其他應用程式的成功實例。我曾經在 LinuxMac OS X 平台上,測試 Windows 中寫好的 Lua 程式,在不修改任何 Script 程式碼的情況下,的確能夠順利執行無誤。

談到 Lua,就不能不提這位超級具份量的客戶:魔獸世界 (World of Warcraft)。在這款超級著名的多人線上遊戲中,也借助了許多 Lua 的威力。最為人所熟知的,就是遊戲允許玩家自行製作各式各樣的 UI(使用者介面);藉由 XML 負責定義外型配置,而 Lua 負責執行核心功能,我們可以看到世界各地玩家成千上萬的自製 UI 模組,很多的成果都不遜於官方原本製作的版本。因為這項讓玩家自製內容的開放功能,大幅增強了魔獸世界遊戲裡,以及遊戲外的社群互動。

另外,魔獸世界中的大型頭目怪物,總是擁有非常多樣化的攻擊模式,這是在其他多數 MMOG 中很少見的遊戲樂趣。我推論其中的怪物 AI,同樣也是透過 Lua 的編寫來達成這樣的功能(未證實)。假設,魔獸世界沒有使用 Lua 或其他 Scripting 系統的方式來開發這些 AI 行為,應該還有以下兩種方式,可以達成如此豐富多變的 AI 行為:

  • 交給程式開發者:每隻頭目都要寫出特定的程式碼,多少頭目就有多少特製化的程式碼,或是複製貼上複製貼上複製複製複製貼上的程式碼。
    程式開發者A君:………我要換工作(找離職單)。
  • 交給企畫設計者:需要一張超大的表格,定義所有可能發生的條件與行為,然後每次只取用其中一小部分的欄位使用。
    企畫設計者B先生:………幫我多拿一張。

回顧歷史,在不很久以前,那段晦暗不明的日子裡,許多開發者為了能得到 Scripting Language 這帖靈藥,於是自己動手寫出了各式各樣的 Scripting Language,程式碼的長相有可能類似於這樣:

IF player_hp < 100 THEN
    CAST_SPELL(1)
ELSE IF self_hp < 50 THEN
    RUNAWAY
ELSE
    MELEE_ATTACK
END

這種自家製造的 Scripting Language,往往陷入太難學習、效能太差與後續維護除蟲的無盡深淵中。終於,在 LuaPythonRuby 三者出現之後,遊戲界就像是現出了三道曙光一樣,再也不必投注人力時程開發不知會不會有問題的語言,也不必擔心開發者離職後的語言維護除錯問題。這三大 Scripting Language 在遊戲業界中都有各自的支持使用者與廣泛的應用;例如在 RPGMaker 這套著名的遊戲製作工具中,也能夠使用 Ruby 來撰寫進階的加強功能。

如果你有一種以上的程式語言學習經驗,對於 Lua 肯定能夠輕鬆上手。就算從來沒有學過任何程式語言,Lua 的學習也比其他語言來得容易許多。讀過官方網站幾個章節的參考手冊之後,就能夠很輕易地開始寫 Lua 程式了。如果對於 Lua 有進一步興趣的話,《Programming in Lua》是一本必看不可的好書。另外如果想要瞭解 Lua 如何運用在遊戲開發的各種功能上,我會推薦閱讀《Game Development with Lua》這本書。

最後,以場景編輯為例,舉個簡單的應用示範 Lua 其中一種使用方式:程式開發者需要先在 C++ 端撰寫好 Lua 端程式碼可呼叫使用的函式,然後在 Lua Script 中就可以自由呼叫使用。首先在 C++ 端的主程式中寫好:

// 在場景上增加一個物件
static int AddObject(lua_State* _pkState)
{
    string kObjectType;
    // 取出 script 傳來的第一個參數
    g_ScriptManager->GetValueAt(1, kObjectType);

    if (kObjectType == "monster") {
        // 取出後續的參數進行處理
    }
    else if (kObjectType == "light") {
       // 取出後續的參數進行處理
    }

    // 把物件交由場景相關的介面處理
    g_SceneManager->AddObject(kObjectType);
    return 0;
}

以上這樣的函式稱為 Glue Function,負責把 C++ 與 Lua 兩端膠黏起來以便於相互溝通。把這個函式註冊好之後,在 Lua 端裡就可以這樣使用:

-- 這是 Lua 中的註解

-- 增加一隻怪物在 (10, 20, 5) 的位置
AddObject("monster", 10, 20, 5)
-- 增加一個白色燈光在 (0, 50, 0) 的位置
AddObject("light", 0, 50, 0, 255, 255, 255)
-- 增加一個寶箱在 (-51, 512, 3) 的位置
AddObject("treasure", -51, 512, 3)

對於場景上各種物件的增加與刪減,從此不用透過 C++ 端程式碼的修改,能夠直接利用 Lua 端的 Script 做出更加動態與彈性的關卡設計。在下篇進階技術的文章中,會以小型商業遊戲中應用的實例,來看 Lua 真正使用在遊戲中的實做細節,敬請期待囉。

最後,讓我們一起大呼:葡萄牙月亮萬歲~! XD

再來一罐:

“Scripting系統概論與Lua簡介” 目前有 2 則迴響

  1. CQD

    Script比較常見的翻譯是「腳本」,這大概是對岸流傳過來的用語。

    雖然我覺得腳本這個翻譯也沒有好到哪裡去,不過實在想不到什麼精闢又好聽的詞彙可以拿來指script…

    半路:
    阿,腳本確實是比較常見的用語。不過「腳本語言」聽起來還是不太自然就是, XD
    所以一些專有術語和專業名詞,我還是會盡量保留中英文對照,這樣應該能減少一點閱讀上的困擾。

  2. Hua

    我用的script是python. 當script嵌入至C/C++時, 真正執行的API是C/C++,
    如果把script翻譯成腳本, 那麼真正在演戲的就是這些C/C++的API了.
    所以覺得用script/腳本來稱呼這種類型的語言, 好像有那麼點傳神.
    但是在單獨寫Python時, 就不會有寫script的感覺了.

    半路:
    Script 是電影的劇本,負責安排場景、燈光、人員以及台詞,
    而 C/C++ 是真正演戲的演員,要拍出好電影還是得靠他們的表現。
    以這個角度思考,的確是一個很不錯的比喻。

    我對 Python 不熟,不過我知道它能夠用來建構比較複雜的系統,
    寫起程式的感覺,應該就和 C/C++ 相當接近了。
    不過我們還是會習慣統稱 Lua/Python/Ruby 這些傢伙為 Scripting Language 就是。

    謝謝你的回應。 ^^

留下迴響