① lua腳本語言環境與全局環境以及錯誤處理的理解
2.2 – 環境與全局環境
後面在 §3.2 以及 §3.3.3 會討論, 引用一個叫 var 的自由名字(指在任何層級都未被聲明的名字) 在句法上都被翻譯為 _ENV.var 。 此外,每個被編譯的 Lua 代碼塊都會有一個外部的局部變數叫 _ENV (參見 §3.3.2), 因此,_ENV 這個名字永遠都不會成為一個代碼塊中的自由名字。
在轉譯那些自由名字時,_ENV 是否是那個外部的局部變數無所謂。 _ENV 和其它你可以使用的變數名沒有區別。 這里特別指出,你可以定義一個新變數或指定一個參數叫這個名字。 當編譯器在轉譯自由名字時所用到的 _ENV , 指的是你的程序在那個點上可見的那個名為 _ENV 的變數。 (Lua 的可見性規則參見 §3.5)
被 _ENV 用於值的那張表被稱為 環境。
Lua 保有一個被稱為 全局環境 特別環境。它被保存在 C 注冊表 (參見 §4.5)的一個特別索引下。 在 Lua 中,全局變數 _G 被初始化為這個值。 (_G 不被內部任何地方使用。)
當 Lua 載入一個代碼塊,_ENV 這個上值的默認值就是這個全局環境 (參見 load)。 因此,在默認情況下,Lua 代碼中提及的自由名字都指的全局環境中的相關項 (因此,它們也被稱為 全局變數 )。 此外,所有的標准庫都被載入入全局環境,一些函數也針對這個環境做操作。 你可以用 load (或 loadfile)載入代碼塊,並賦予它們不同的環境。 (在 C 里,當你載入一個代碼塊後,可以通過改變它的第一個上值來改變它的環境。)
2.3 – 錯誤處理
由於 Lua 是一門嵌入式擴展語言,其所有行為均源於宿主程序中 C 代碼對某個 Lua 庫函數的調用。 (單獨使用 Lua 時,lua 程序就是宿主程序。) 所以,在編譯或運行 Lua 代碼塊的過程中,無論何時發生錯誤, 控制權都返回給宿主,由宿主負責採取恰當的措施(比如列印錯誤消息)。
可以在 Lua 代碼中調用 error 函數來顯式地拋出一個錯誤。 如果你需要在 Lua 中捕獲這些錯誤, 可以使用 pcall 或 xpcall 在 保護模式 下調用一個函數。
無論何時出現錯誤,都會拋出一個攜帶錯誤信息的 錯誤對象 (錯誤消息)。 Lua 本身只會為錯誤生成字元串類型的錯誤對象, 但你的程序可以為錯誤生成任何類型的錯誤對象, 這就看你的 Lua 程序或宿主程序如何處理這些錯誤對象。
使用 xpcall 或 lua_pcall 時, 你應該提供一個 消息處理函數 用於錯誤拋出時調用。 該函數需接收原始的錯誤消息,並返回一個新的錯誤消息。 它在錯誤發生後棧尚未展開時調用, 因此可以利用棧來收集更多的信息, 比如通過探知棧來創建一組棧回溯信息。 同時,該處理函數也處於保護模式下,所以該函數內發生的錯誤會再次觸發它(遞歸)。 如果遞歸太深,Lua 會終止調用並返回一個合適的消息。
② 怎麼使用lua腳本
LUA腳本語言基本使用方法是本文要將介紹的內容,主要是來學習Lua腳本語言的使用方法,具體內容來看本文詳解。
先要把下邊這些語句加入到VC中的頭文件,一般是加到StdAfx.h中
extern "C" { #include "lua.h" #include "lualib.h" #include "lauxlib.h" #pragma comment(lib, "lualib.lib") #pragma comment(lib, "lua.lib") }
然後一般來說都使用一個全局的LUA庫定義的這個東西
lua_State* g_Lua;
並且在工程處初始化時也給LUA初始化
g_Lua = lua_open(); **加這句 /* load Lua base libraries */ 網上一些教材中這么寫的 lua_baselibopen(g_Lua); 不過我這簡單的例子中不用到這些也行 lua_tablibopen(g_Lua); lua_iolibopen(g_Lua); lua_strlibopen(g_Lua); lua_mathlibopen(g_Lua);
緊接著聲明介面函數,注冊上函數
lua_register(g_Lua, "Message", myMessage);
好,初始化部分完了,看看介面函數的寫法。
函數必須這樣的格式來寫
static int Func(lua_State *L) { 靜態型函數,而且必須帶參數為lua_State結構指針 返回的值是代表返回的數據個數,比如return 2;就可以代表 返回兩個整數啊,浮點數什麼的,象LUA的腳本編寫就可以這樣 i, j = Func() , 這樣就表示可以從Func介面函數中得到兩個返回值了 return 0; }
執行腳本語句可以讀文件,也可以直接讀函數名
注冊了
lua_register(g_Lua, "Message", myMessage); static int myMessage(lua_State *L) { OutputDebugString("OK"); return 0; } lua_dofile(g_Lua, strCurPath); //讀文件,必須給出完整的文件路徑名稱 lua_dostring(g_Lua, "Message()"); //直接讀函數
文件中只要寫上
Message()
就可以了。
③ 為什麼將lua作為游戲腳本
就我個人的理解來看,使用LUA作為腳本語言有三個好處:
1、輕量級
LUA只包括一個精簡的核心和最基本的庫。這使得LUA體積小、啟動速度快,從而適合嵌入在別的程序里。
2、可配置性、可擴展性
LUA並不象其它許多"大而全"的語言那樣,包括很多功能,比如網路通訊、圖形界面等。但是LUA可以很容易地被擴展:由宿主語言(通常是C或C++)提供這些功能,LUA可以使用它們,就像是本來就內置的功能一樣。
3、兼容性
LUA由標准C編寫而成,幾乎在所有操作系統和平台上都可以編譯,運行。
這些都是LUA本身所具備的一些特質。而這些特質正好就決定了LUA的廣泛使用:
1、輕量級
沒人希望自己的應用程序需要附加幾十M甚至幾百M的庫類文件才能運行。如果一個應用程序這么做了,那麼它很難做到Run Anywhere。當然,這個Run Anywhere只是這么一說。
2、可配置性、可擴展性
在游戲研發的過程中,修改是必不可少的過程。如果每次修改都需要從底層做起,那必定是一個非常繁瑣的過程。而LUA的可配置、擴展正好可以解決這一問題。
3、兼容性
游戲只是游戲,不能決定玩家的機器配置,更不能決定玩家的操作系統。如果因為游戲與用戶的操作系統不兼容導致游戲銷量下降,我想,這肯定是不被允許的。
所以,具備了以上三個特點的LUA,沒有不作為游戲腳本使用的理由。
④ 如何調試lua腳本
調試lua現有的幾種方案:
1)luaedit : 編輯斷點和斷點命中查看那些都讓習慣用vs的人感到親切,但是它只是在純lua環境下的編輯器,也就是說和期望程序運行中能借用它來調試腳本可能性不大(至少我沒有試驗出來),能用上的需要給lua腳本做個main腳本函數,並提供一系列偽的c api(由lua實現的函數,只提供製定值的返回)。由luaedit啟動腳本main函數進行調試
2)利用 lua debug 庫中的 hook ,然後記錄一張斷點位置表,設置行模式的 hook ,每次進入 hook 都檢查是否是斷點處,若是就停下來等待交互調試。這個方法有效,但是很消耗 cpu 。因為每進入一個新的代碼行,都需要回調一個函數。當這個函數本身又是用 lua 寫的時候,效率更低。
3)利用lua腳本函數實現,在lua腳本中封裝一個斷點函數,這種方式結合debug庫實現斷點和棧信息,然後利用lua環境下的表對函數調用信息進行記錄和列印,需要腳本使用者顯式提供斷點函數的調用。這個辦法的優點自己可以組合出適合自己項目的斷點調試方案。但缺點是相對繁瑣,而且斷點命中以後難以和現有方式融合