Lua 學(xué)習(xí)筆記
使用該專欄
本專欄是筆者基于唐老獅的免費(fèi)公開Lua課程所寫的筆記以及拓展了一點(diǎn)其他內(nèi)容,主要用途是便于筆者自己隨時(shí)隨地復(fù)習(xí),同時(shí)希望能幫助到有需要的人。
Lua是一種輕量級(jí)的腳本語言,由標(biāo)準(zhǔn)C語言編寫并以源代碼形式開放。它的設(shè)計(jì)目的是為了嵌入應(yīng)用程序中,從而為應(yīng)用程序提供靈活的擴(kuò)展和定制功能。
Lua具有以下特性:
輕量級(jí):它用標(biāo)準(zhǔn)C語言編寫并以源代碼形式開放,編譯后僅僅一百余K,可以很方便地嵌入別的程序里。
可擴(kuò)展:Lua提供了非常易于使用的擴(kuò)展接口和機(jī)制:由宿主語言 (通常是C或C++)提供這些功能,Lua可以使用它們,就像是本來就內(nèi)置的功能一樣。
其他特性:支持面向過程 (procedure-oriented)編程和函數(shù)式編程 (functional programming);自動(dòng)內(nèi)存管理;只提供了一種通用類型的表(table),用它可以實(shí)現(xiàn)數(shù)組,哈希表,集合,對象; 語言內(nèi)置模式匹配;閉包 (closure);函數(shù)也可以看做一個(gè)值;提供多線程(協(xié)同進(jìn)程,并非操作系統(tǒng)所支持的線程)支持; 通過閉包和table可以很方便地支持面向?qū)ο缶幊趟枰囊恍╆P(guān)鍵機(jī)制,比如數(shù)據(jù)抽象,虛函數(shù),繼承和重載等。
在Unity開發(fā)中,Lua一般會(huì)被使用于熱更新和熱重載。
Lua
基本語法
;分號(hào)是可以省略的,建議不寫

注釋
單行注釋 ?兩個(gè)減號(hào)是單行注釋:
多行注釋

全局變量
在默認(rèn)情況下,變量總是認(rèn)為是全局的。
全局變量不需要聲明,給一個(gè)變量賦值后即創(chuàng)建了這個(gè)全局變量,訪問一個(gè)沒有初始化的全局變量也不會(huì)出錯(cuò),只不過得到的結(jié)果是:nil。
如果你想刪除一個(gè)全局變量,只需要將變量賦值為nil。

數(shù)據(jù)類型
Lua 是動(dòng)態(tài)類型語言,變量不要類型定義,只需要為變量賦值。 值可以存儲(chǔ)在變量中,作為參數(shù)傳遞或結(jié)果返回。
Lua 中有 8 個(gè)基本類型分別為:nil、boolean、number、string、userdata、function、thread 和 table。
數(shù)據(jù)類型描述nil這個(gè)最簡單,只有值nil屬于該類,表示一個(gè)無效值(在條件表達(dá)式中相當(dāng)于false)有點(diǎn)類似C#中的null。boolean包含兩個(gè)值:false和true。number表示雙精度類型的實(shí)浮點(diǎn)數(shù)string字符串由一對雙引號(hào)或單引號(hào)來表示function由 C 或 Lua 編寫的函數(shù)userdata表示任意存儲(chǔ)在變量中的C數(shù)據(jù)結(jié)構(gòu)thread表示執(zhí)行的獨(dú)立線路,用于執(zhí)行協(xié)同程序tableLua 中的表(table)其實(shí)是一個(gè)"關(guān)聯(lián)數(shù)組"(associative arrays),數(shù)組的索引可以是數(shù)字、字符串或表類型。在 Lua 里,table 的創(chuàng)建是通過"構(gòu)造表達(dá)式"來完成,最簡單構(gòu)造表達(dá)式是{},用來創(chuàng)建一個(gè)空表。
簡單變量類型
nil, number, string, boolean
復(fù)雜數(shù)據(jù)類型
函數(shù) function
表 table
數(shù)據(jù)結(jié)構(gòu) userdata:
userdata 是一種用戶自定義數(shù)據(jù),用于表示一種由應(yīng)用程序或 C/C++ 語言庫所創(chuàng)建的類型,可以將任意 C/C++ 的任意數(shù)據(jù)類型的數(shù)據(jù)(通常是 struct 和 指針)存儲(chǔ)到 Lua 變量中調(diào)用。
協(xié)同程序 thread:
在 Lua 里,最主要的線程是協(xié)同程序(coroutine)。它跟線程(thread)差不多,擁有自己獨(dú)立的棧、局部變量和指令指針,可以跟其他協(xié)同程序共享全局變量和其他大部分東西。
線程跟協(xié)程的區(qū)別:線程可以同時(shí)多個(gè)運(yùn)行,而協(xié)程任意時(shí)刻只能運(yùn)行一個(gè),并且處于運(yùn)行狀態(tài)的協(xié)程只有被掛起(suspend)時(shí)才會(huì)暫停。
變量聲明
lua中所有的變量聲明 都不需要申明變量類型,它會(huì)自動(dòng)判斷變量類型,類似C#中的 var
lua中的一個(gè)變量 可以隨便賦值,自動(dòng)識(shí)別類型
我們可以使用 type 函數(shù)測試給定變量或者值的類型:
nil 類型表示一種沒有任何有效值,它只有一個(gè)值 -- nil,例如打印一個(gè)沒有賦值的變量,便會(huì)輸出一個(gè) nil 值:
對于全局變量和 table,nil 還有一個(gè)"刪除"作用,給全局變量或者 table 表里的變量賦一個(gè) nil 值,等同于把它們刪掉,執(zhí)行下面代碼就知:
nil 作比較時(shí)應(yīng)該加上雙引號(hào) ":
type(X)==nil 結(jié)果為 false 的原因是 type(X) 實(shí)質(zhì)是返回的 "nil" 字符串,是一個(gè) string 類型:

字符串
字符串的聲明,使用單引號(hào)或者雙引號(hào)包裹,lua里沒有char
獲取字符串的長度
字符串多行打印
字符串拼接
別的類型轉(zhuǎn)成字符串
字符串提供的公共方法,大部分方法不會(huì)對原字符串造成影響

運(yùn)算符
算數(shù)運(yùn)算符
+-*/% ?在lua中沒有自增自減 ++ --;沒有復(fù)合運(yùn)算符 += -= /= *= %=
條件運(yùn)算符
邏輯運(yùn)算符
位運(yùn)算符
-- & | 不支持位運(yùn)算符 需要我們自己實(shí)現(xiàn)
三目運(yùn)算符
-- ? : lua中 也不支持三目運(yùn)算

條件分支語句
循環(huán)語句

函數(shù)
無參數(shù)無返回值
有參數(shù)
有返回值
函數(shù)的類型
函數(shù)的重載
變長參數(shù)
函數(shù)嵌套
閉包

復(fù)雜數(shù)據(jù)類型——表
所有的復(fù)雜類型都是table(表)
數(shù)組的遍歷
二維數(shù)組
二維數(shù)組的遍歷
自定義索引

迭代器遍歷
迭代器遍歷,主要是用來遍歷表的
#得到的長度并不準(zhǔn)確,所以一般不要用#來遍歷表

復(fù)雜數(shù)據(jù)類型——表2
字典
字典的本質(zhì)還是表
字典的聲明
字典是由鍵值對構(gòu)成的
字典的遍歷

類和結(jié)構(gòu)體
Lua中是默認(rèn)沒有面向?qū)ο蟮?,需要我們自己來?shí)現(xiàn)
表的公共操作

多Lua腳本執(zhí)行
全局變量與本地變量
多腳本執(zhí)行
腳本卸載
大G表

特殊用法
多變量賦值
多返回值
and or

協(xié)同程序
協(xié)程的創(chuàng)建
協(xié)程的運(yùn)行
協(xié)程的掛起
協(xié)程的狀態(tài)

元表
元表概念
任何表變量都可以作為另一個(gè)表變量的元表
任何表變量都可以有自己的元表(爸爸)
當(dāng)我們子表中進(jìn)行一些特定操作時(shí) 會(huì)執(zhí)行元表中的內(nèi)容
設(shè)置元表
特定操作
特定操作 - __tostring
特定操作 - __call
特定操作 - 運(yùn)算符重載
特定操作 - __ index和 __ newIndex

面向?qū)ο?/h1>封裝
繼承
多態(tài)

Lua自帶庫
時(shí)間
數(shù)學(xué)運(yùn)算
路徑

Lua垃圾回收

如何在游戲中執(zhí)行用戶輸入的代碼
在游戲中執(zhí)行用戶輸入的代碼需要謹(jǐn)慎,因?yàn)檫@可能會(huì)帶來安全風(fēng)險(xiǎn)。如果您確實(shí)想要實(shí)現(xiàn)這個(gè)功能,您可以考慮在游戲中嵌入一個(gè)腳本引擎,例如Lua或Python。這樣,您可以在運(yùn)行時(shí)執(zhí)行用戶輸入的腳本代碼。
首先,您需要在游戲中創(chuàng)建一個(gè)文本輸入框,讓用戶可以輸入代碼。然后,您可以使用腳本引擎提供的API來執(zhí)行用戶輸入的代碼。例如,在Unity中使用xLua插件,您可以使用DoString
方法來執(zhí)行用戶輸入的Lua代碼。
什么是XLua
xLua是一個(gè)在Unity中使用Lua語言的插件。它提供了一種簡單的方法來在Unity項(xiàng)目中嵌入Lua腳本,并在運(yùn)行時(shí)執(zhí)行這些腳本。
xLua具有許多優(yōu)點(diǎn),包括簡單易用、性能高效和跨平臺(tái)支持。它還支持熱更新,可以讓您在不重新編譯和發(fā)布游戲的情況下更新游戲邏輯。
使用xLua,您可以將游戲邏輯和界面邏輯分離,使用Lua腳本來實(shí)現(xiàn)游戲邏輯。這樣,您可以更快地迭代游戲邏輯,并且可以在運(yùn)行時(shí)動(dòng)態(tài)更新游戲邏輯。
xLua提供了豐富的文檔和示例,可以幫助您快速入門。如果您想要在Unity項(xiàng)目中使用Lua語言,那么xLua是一個(gè)不錯(cuò)的選擇。
要使用xLua編寫游戲邏輯,您需要先在Unity項(xiàng)目中安裝xLua插件。安裝完成后,您可以在Unity項(xiàng)目中創(chuàng)建Lua腳本文件,并使用Lua語言編寫游戲邏輯。
xLua提供了一組API,可以讓您在Lua腳本中訪問Unity的功能。例如,您可以使用
命名空間來訪問Unity的類和方法。您還可以使用
方法來熱更新C#代碼。
下面是一個(gè)簡單的示例,演示如何使用xLua編寫游戲邏輯:
在這個(gè)示例中,我們定義了一個(gè)move
函數(shù),用于移動(dòng)游戲物體。然后,在update
函數(shù)中調(diào)用move
函數(shù),使物體每幀都移動(dòng)一定距離。
如何安裝XLua
要在Unity中安裝和使用xLua,您可以按照以下步驟操作:
訪問xLua的GitHub頁面(https://github.com/Tencent/xLua),并下載最新版本的xLua插件。
將下載的xLua插件解壓縮到您的Unity項(xiàng)目的Assets文件夾中。
在Unity編輯器中,打開您的項(xiàng)目,并確保xLua插件已經(jīng)導(dǎo)入到項(xiàng)目中。
在Unity項(xiàng)目中創(chuàng)建一個(gè)C#腳本,用于初始化xLua環(huán)境。例如:
在這個(gè)示例中,我們創(chuàng)建了一個(gè)XLuaManager
類,用于管理xLua環(huán)境。在Start
方法中,我們創(chuàng)建了一個(gè)LuaEnv
實(shí)例,并執(zhí)行了一個(gè)名為main
的Lua腳本。在Update
方法中,我們調(diào)用了luaEnv.Tick
方法來更新xLua環(huán)境。最后,在OnDestroy
方法中,我們釋放了xLua環(huán)境。
在Unity項(xiàng)目中創(chuàng)建一個(gè)名為
main.lua
的文件,并使用Lua語言編寫游戲邏輯。例如:
在這個(gè)示例中,我們創(chuàng)建了一個(gè)簡單的Lua腳本,用于輸出一條消息。
運(yùn)行您的Unity項(xiàng)目,并檢查控制臺(tái)輸出。如果一切正常,您應(yīng)該能看到來自Lua腳本的輸出。
如何在Lua中訪問Unity的功能
在使用xLua的Unity項(xiàng)目中,您可以在Lua腳本中訪問Unity的類和方法。xLua提供了一個(gè)全局的CS
表,用于訪問C#的命名空間和類型。
例如,要在Lua腳本中訪問Unity的Vector3
類,您可以使用以下代碼:
在這個(gè)示例中,我們使用CS.UnityEngine.Vector3
來訪問Unity的Vector3
類,并將其賦值給一個(gè)局部變量。然后,我們就可以在Lua腳本中使用這個(gè)局部變量來創(chuàng)建和操作Vector3
對象。
除了訪問Unity的類和方法外,您還可以在Lua腳本中訪問Unity的組件和游戲?qū)ο蟆@?,要在Lua腳本中訪問當(dāng)前游戲?qū)ο蟮腡ransform組件,您可以使用以下代碼:
在這個(gè)示例中,我們使用self.transform
來訪問當(dāng)前游戲?qū)ο蟮腡ransform組件,并將其賦值給一個(gè)局部變量。然后,我們就可以在Lua腳本中使用這個(gè)局部變量來操作Transform組件。
如何在Lua中處理輸入事件
在使用xLua的Unity項(xiàng)目中,您可以在Lua腳本中處理輸入事件。要做到這一點(diǎn),您需要在C#腳本中監(jiān)聽輸入事件,并將它們傳遞給Lua腳本。
例如,要在Lua腳本中處理鼠標(biāo)點(diǎn)擊事件,您可以在C#腳本中監(jiān)聽鼠標(biāo)點(diǎn)擊事件,并調(diào)用Lua腳本中定義的函數(shù)來處理這些事件。下面是一個(gè)簡單的示例:
在這個(gè)示例中,我們定義了一個(gè)InputManager
類,用于管理輸入事件。在Update
方法中,我們監(jiān)聽鼠標(biāo)點(diǎn)擊事件,并調(diào)用Lua腳本中定義的onMouseDown
函數(shù)來處理這些事件。
在這個(gè)示例中,我們獲取了InputManager
類的實(shí)例,并為其onMouseDown
屬性賦值了一個(gè)函數(shù)。當(dāng)鼠標(biāo)點(diǎn)擊事件發(fā)生時(shí),這個(gè)函數(shù)將被調(diào)用,并輸出一條消息。
這就是在Lua腳本中處理輸入事件的基本方法。您可以根據(jù)需要擴(kuò)展這個(gè)方法,以支持更多類型的輸入事件。