



摘要:該文通過對手機移動游戲研發技術的分析,提出了一種全新的開發游戲玩法邏輯的思路和框架設計,使用解釋型腳本編程語言Lua而非編譯型語言C++開發游戲邏輯,并且結合開發實踐經驗提出了游戲邏輯全部Lua化的可行方案。旨在降低移動游戲開發技術門檻,降低人工成本,降低更新和迭代開發成本,提高移動游戲開發效率。
關鍵詞:移動游戲;Lua;C++;腳本化;游戲引擎;libclang
doi:10.3969/J.ISSN.1672-7274.2024.05.017
中圖分類號:TP 311.52" " " " " 文獻標志碼:A" " " " " " 文章編碼:1672-7274(2024)05-00-03
Design of Mobile Game Engine Based on Lua
WANG Yuanming
(Zulong (Tianjin) Technology Co., Ltd. Beijing Branch, Beijing 100013, China)
Abstract: This article analyzes the development technology of mobile games on mobile phones and proposes a new idea and framework design for developing game gameplay logic. The game logic is developed using the interpreted script programming language Lua instead of the compiled language C++. Based on development experience, a feasible solution for fully Luanizing game logic is proposed. Intended to lower the technical threshold for mobile game development, lower labor costs, lower update and iterative development costs, and improve the efficiency of mobile game development.
Keywords: mobile games; Lua; C++; scriptization; game engine; lbclang
隨著智能手機硬件功能越來越強大,網絡流量和資費越來越低廉,移動游戲從一開始的輕度休閑類型,慢慢向大型重度全3D方向發展。畫面越來越精美,游戲類型更加多樣化,之前只有在PC上才能玩到的游戲在手機上也隨時可以體驗,極大地方便了玩家,提升了游戲體驗,也繁榮了游戲行業[1-2]。手機游戲蓬勃發展,給游戲開發者帶來了新的機遇和挑戰。如何降低開發難度,提高迭代開發速度,提高游戲運行效率,就成了在競爭中脫穎而出的關鍵所在。本文提出一種框架設計,使得游戲開發從使用難以掌握的C++語言,轉變為學習成本低、易于掌握且具備很多語言優勢比如內存自動管理、函數閉包等特性的腳本語言Lua[3]。
1" "總體方案設計
本方案主要分為C++引擎函數注入Lua、運行時框架模塊、C++引擎函數導出工具三部分,如圖1所示。方案首先通過C++引擎函數導出工具將游戲引擎所有的C++接口導出生成符合Lua要求的可注入Lua的C++函數(下文稱“包裹函數”),在游戲引擎初始化階段將所有可注入Lua的C++函數全部注入Lua虛擬機。然后進入到運行時框架模塊,該模塊由游戲引擎每幀的Loop驅動,每幀調用該模塊一次,在模塊內部會調用Lua的Update函數,在此函數中完成游戲所有邏輯的編寫工作,包括網絡處理、角色模型處理、界面邏輯處理、玩法處理等。
導出工具根據配置文件獲取需要導出哪些引擎C++接口,根據配置文件中的.h頭文件,利用libclang庫解析獲得類的信息,包括類名、接口及參數+返回值信息、成員變量名+類型信息,為每一個函數生成符合Lua要求的可注入包裹函數,為每個成員變量生成Get和Set注入包裹函數,這些函數寫入CPP文件中,供引擎初始化時統一一次性注入Lua虛擬機。
這些CPP文件會隨著游戲編譯到最終執行文件中,在游戲啟動初始化階段,會調用Register函數,將這些函數指針注入到Lua虛擬機中,在Lua中就可以創建這些對象,調用這些對象的成員函數,訪問他們的成員變量。就如同在C++中編寫游戲邏輯一樣。
初始化完成后進入游戲主邏輯循環,每次循環都觸發一次本方案運行時框架模塊,框架模塊主要任務是調用Lua腳本函數Update,在Lua腳本中編寫全部的游戲邏輯,處理網絡消息和用戶操作,完成資源的加載和卸載等。
2" "C++函數注入Lua
所謂的C++函數注入Lua指的是將游戲引擎中C++函數的函數指針交給Lua虛擬機并在虛擬機內部賦予該函數一個字符串名稱以便在Lua源碼中通過該名稱索引和調用該函數。Lua是一個使用C語言實現的腳本語言,當我們把全部的Lua源代碼集成并編譯到游戲引擎中后,我們就可以通過調用Lua的一套CAPI實現C++和Lua的數據傳遞和互相調用[4]。需要重點注意的是我們將每個C++類的成員函數和屬性訪問函數放入一個單獨的Lua表中,通過Lua的元表的__index元方法定制化有繼承關系的Lua表查找過程,實現類的繼承。使用Lua的userdata機制實現引擎中對象的表示物,一個引擎對象實例在Lua側就是一個userdata實例,userdata通過__index機制查找成員函數,模擬出類對象行為[5]。在引擎側維護著一個C++對象指針和userdata的映射關系表,從而可以把在Lua側的成員函數調用委派到正確的C++對象上,如圖2所示。
3" "自動導出工具的實現原理
首先,需要獲取將要注入的C++函數的信息,包括函數名、返回值和各個參數類型,是否是const,是否是引用類型,這就涉及到.h頭文件的解析。市面上解析C++語法用得比較多的PyParsing等庫,實現了較為簡單的C++語法解析,但是我們所面對的游戲引擎往往實現非常復雜,模板、重載等C++高級特性使用頻繁,本方案使用libclang這樣的編譯器級別的解析庫,將頭文件做靜態語義分析,獲得AST抽象語法樹,然后在遍歷語法樹的過程中刪繁就簡,獲取必要的元信息,從而得到所需的接口信息。
其次,在獲知了參數信息后,需要生成從Lua側獲取參數值到C++的代碼,Lua的CAPI提供了豐富的各類接口。可根據Lua側傳入的userdata實例通過查詢表得到對應的C++對象實例,隨后生成調用C++接口的代碼,如果函數有返回值,還需要生成將返回值傳遞到Lua側的代碼,至此一個完整的包裹函數生成完畢。
在將所有的成員函數的包裹函數生成完畢后,再生成最為重要的__index函數,它負責向父類查找繼承的成員函數,將所有這些函數的函數指針和對應的函數名稱放入Lua規定的一個數組中,生成將這些函數全部注入Lua虛擬機的代碼[6]。
4" "運行時框架模塊
4.1 Lua中面向對象編程的實現
Lua中有一個重要的“元表”概念,可以通過“元表”設置不同的“元方法”,為一個table類型的變量定制查找行為、賦值行為。通過元表可以將對table的查詢過程委派到元表的__index元函數中,將對table的賦值操作委派到元表的__newindex元函數中。在Lua中可以定義一個空table,里面設置好成員函數、__index和__newindex元方法,這樣一個類似C++里的“類”的對象就產生了,開發人員可以再定義一個空表作為“子類”,通過__index元方法查找類自身的成員函數,如果沒有找到就向其父類table查找,這完美模擬出了函數重載,查找到的函數在調用時可以依次檢查傳入的參數的個數和類型,發現與記錄的類型不符就報錯。查找成員變量時,如果自身沒有該成員變量,則向父類查找,完美模擬出了缺省值。通過__newindex賦值元方法在自身保存值,這就實現了C++中類的自定義值。從而完美模擬出了面向對象編程環境[7]。
4.2 游戲資源的更新
使用Lua開發全部的游戲邏輯的好處不僅僅是上手難度低,迭代速度快,另一個更為重要的因素是Lua代碼可以作為資源的一部分而不是執行文件的一部分。在手游時代,游戲的發布必須通過App Store,如果一款游戲采用C++開發,只要改動了C++則必須要重新編譯生成新的執行文件,執行文件在手機上是不能像PC那樣隨意修改的,它們都運行在自己的沙箱中,如果想更新執行文件則必須通過App Store更新整個游戲安裝包,這對于動輒幾個G大小的重度手游來說,對玩家的更新壓力會非常大,玩家會因為要過于頻繁地下載過大的游戲安裝包而流失。而Lua代碼是一種游戲資源文件而不是執行文件的一部分。這就要求游戲本身具有運行時下載更新資源的能力,否則如果更新資源也需要下載安裝游戲整包,那此前做的所有的事情都是徒勞的。拿蘋果平臺舉例,所有的初始游戲資源都位于游戲安裝包ipa文件內部,這個文件iPhone是不允許修改的,游戲的更新文件,包括美術資源和Lua腳本代碼被游戲下載到可寫的Documents目錄后,游戲的加載邏輯需要先在Documents目錄下查找文件,如果有則使用,如果沒有再向ipa文件內部查找。這樣可以使用最新的美術資源和運行到最新的Lua游戲邏輯代碼。
4.3 網絡協議的處理機制Lua化
游戲邏輯往往依靠網絡協議驅動,網絡協議是易變的,隨著游戲玩法的改變會添加和修改,網絡協議的內容由基本的數據類型和控制信息構成,只要把基本的數據類型的解析接口注入到Lua中,就可以在引擎收到網絡包的時候將網絡包直接傳遞給Lua,在Lua側解析協議ID、數據內容,同時完成相應邏輯處理,如圖4所示。
5" "結束語
基于Lua開發全部的游戲邏輯在當今手機游戲日益盛行、日趨復雜和多元化的時代顯得更加重要,不僅降低學習難度、易于調試、縮短開發周期和節約人力成本,也可以避免App Store漫長的審核周期,真正做到快速開發,快速發布,快速更新。所以將游戲引擎改造成為具備全Lua開發能力就顯得尤為重要。隨著VR、AR和元宇宙等多種新型游戲形式的出現,手機游戲多玩法、多平臺發布就成為了一個趨勢,使用Lua開發游戲更好地屏蔽了平臺的差異,真正做到了游戲邏輯一次編寫,多處可用。
參考文獻
[1] 李豪悅.洞察2023年游戲產業發展:全球化跨領域競爭加劇 中國游戲企業如何應對?[N].證券日報,2023-02-18 (B02).
[2] 許心怡,吳可仲.2022年游戲市場表現疲軟:老游衰退 新游不足[N].中國經營報,2023-01-09 (B16).
[3] 郭璇,徐欣怡.中國移動游戲“出海”的機遇和路徑[J].未來傳播,2022, 29 (5): 91-99.
[4] 鄧正陽,陳和平,蘇鵬.動態腳本語言Lua與C++交互方法的研究與實現[J].計算機系統應用,2020,19(5):198-201.
[5] 趙正旭,申躍杰,左宗成.腳本語言Lua與C++語言交互方法的研究[J].電腦知識與技術,2018(23):135-137.
[6] 陸喬.基于Lua的iOS動態化系統的設計與實現[D].武漢:華中科技大學,2020.
[7] 李中冬.一種C++與Lua自動綁定的方法[J].中國科技信息,2021(2):89-91.