目錄
- 0 引言
- 1 基礎語法
- 1.1 變量和數據類型
- 1.2 注釋
- 1.3 控制結構
- 1.4 函數
- 1.5 表(Table)
- 1.6 元表(Metatable)
- 1.7 字符串操作
- 1.8 模塊和包
- 1.9 錯誤處理
- 2 數據結構 - 表
- 2.1 表(Table)
- 2.2 元表(Metatable)
- 2.3 `__index` 元方法
- 2.3.1 `__index` 作為表
- 2.3.2 `__index` 作為函數
- 2.4 表和元表的區別
- 3 面向對象范式
- 4 Lua與UE引擎的交互
- 4.1 使用第三方插件 UnLua
- 4.2 使用 LuaBridge
- 4.3 使用 Unreal Engine Lua Plugin
- 4.4 底層實現原理
- 4.4.1 嵌入 Lua 解釋器
- 4.4.2 綁定 C++ 和 Lua
- 4.4.3 腳本加載和執行
- 4.4.4 事件和回調機制
- 4.4.5 總結
- 🙋?♂? 作者:海碼007
- 📜 專欄:UE虛幻引擎專欄
- 💥 標題:【UE Lua】 快速入門
- ?? 寄語:書到用時方恨少,事非經過不知難!
- 🎈 最后:文章作者技術和水平有限,如果文中出現錯誤,希望大家能指正,同時有問題的話,歡迎大家留言討論。
0 引言
1 基礎語法
Lua 是一種輕量級的腳本語言,語法簡潔且易于學習。以下是 Lua 腳本的基礎語法,包括變量、數據類型、控制結構、函數、表、元表等。
1.1 變量和數據類型
Lua 是動態類型語言,變量不需要聲明類型。
-- 變量
local a = 10 -- 整數
local b = 3.14 -- 浮點數
local c = "Hello" -- 字符串
local d = true -- 布爾值
local e = nil -- 空值
1.2 注釋
Lua 支持單行注釋和多行注釋。
-- 單行注釋--[[
多行注釋
可以跨越多行
]]
1.3 控制結構
條件語句
local x = 10if x > 0 thenprint("x is positive")
elseif x < 0 thenprint("x is negative")
elseprint("x is zero")
end
循環語句
-- while 循環
local i = 1
while i <= 5 doprint(i)i = i + 1
end-- for 循環
for i = 1, 5 doprint(i)
end-- 泛型 for 循環
local t = {10, 20, 30}
for index, value in ipairs(t) doprint(index, value)
end
1.4 函數
-- 定義函數
function add(a, b)return a + b
end-- 調用函數
local result = add(3, 4)
print(result) -- 輸出 7-- 匿名函數
local multiply = function(a, b)return a * b
endprint(multiply(3, 4)) -- 輸出 12
1.5 表(Table)
表是 Lua 中唯一的數據結構,可以用來表示數組、字典、集合、對象等。
-- 創建一個空表
local t = {}-- 數組
local array = {1, 2, 3, 4, 5}
print(array[1]) -- 輸出 1-- 字典
local dict = {name = "Alice", age = 30}
print(dict["name"]) -- 輸出 "Alice"
print(dict.age) -- 輸出 30-- 嵌套表
local nested = {a = {b = {c = 10}}}
print(nested.a.b.c) -- 輸出 10
1.6 元表(Metatable)
元表用于改變表的行為,可以定義一些特殊的操作,如算術運算、比較運算、表訪問等。
-- 創建一個表
local myTable = {name = "Alice"}-- 創建一個元表
local myMetatable = {__index = {age = 30}
}-- 設置元表
setmetatable(myTable, myMetatable)-- 訪問表中的值
print(myTable.name) -- 輸出 "Alice"
print(myTable.age) -- 輸出 30 (從元表中獲取)
1.7 字符串操作
Lua 提供了一些常用的字符串操作函數。
local str = "Hello, World!"-- 獲取字符串長度
print(#str) -- 輸出 13-- 字符串連接
local str2 = str .. " Lua"
print(str2) -- 輸出 "Hello, World! Lua"-- 字符串查找
local start, finish = string.find(str, "World")
print(start, finish) -- 輸出 8 12-- 字符串替換
local newStr = string.gsub(str, "World", "Lua")
print(newStr) -- 輸出 "Hello, Lua!"
1.8 模塊和包
Lua 支持模塊和包,可以通過 require
函數加載模塊。
-- mymodule.lua
local mymodule = {}function mymodule.greet(name)print("Hello, " .. name)
endreturn mymodule-- main.lua
local mymodule = require("mymodule")
mymodule.greet("World") -- 輸出 "Hello, World"
1.9 錯誤處理
Lua 提供了 pcall
和 xpcall
函數用于錯誤處理。
-- 使用 pcall 進行錯誤處理
local status, err = pcall(function()error("An error occurred")
end)if not status thenprint("Error: " .. err)
end
2 數據結構 - 表
在 Lua 中,表(table)是最重要的數據結構,而元表(metatable)則是用于改變表行為的機制。以下是對表和元表的詳細解釋,以及 __index
元方法的作用。
2.1 表(Table)
表是 Lua 中唯一的數據結構,可以用來表示數組、字典、集合、對象等。表是動態的,可以根據需要添加或刪除鍵值對。
-- 創建一個空表
local myTable = {}-- 添加鍵值對
myTable["name"] = "Alice"
myTable["age"] = 30-- 訪問表中的值
print(myTable["name"]) -- 輸出 "Alice"
print(myTable["age"]) -- 輸出 30
2.2 元表(Metatable)
元表是一個特殊的表,可以用來改變另一個表的行為。通過設置元表,可以定義一些特殊的操作,如算術運算、比較運算、表訪問等。
-- 創建一個表
local myTable = {}-- 創建一個元表
local myMetatable = {}-- 設置元表
setmetatable(myTable, myMetatable)
2.3 __index
元方法
__index
是元表中的一個特殊字段,用于處理對表中不存在的鍵的訪問。當訪問一個表中不存在的鍵時,Lua 會查找該表的元表中的 __index
元方法。如果 __index
是一個表,Lua 會在這個表中查找鍵;如果 __index
是一個函數,Lua 會調用這個函數。
2.3.1 __index
作為表
-- 創建一個表
local myTable = {name = "Alice"}-- 創建一個元表
local myMetatable = {__index = {age = 30}
}-- 設置元表
setmetatable(myTable, myMetatable)-- 訪問表中的值
print(myTable.name) -- 輸出 "Alice"
print(myTable.age) -- 輸出 30 (從元表中獲取)
2.3.2 __index
作為函數
-- 創建一個表
local myTable = {name = "Alice"}-- 創建一個元表
local myMetatable = {__index = function(table, key)if key == "age" thenreturn 30elsereturn nilendend
}-- 設置元表
setmetatable(myTable, myMetatable)-- 訪問表中的值
print(myTable.name) -- 輸出 "Alice"
print(myTable.age) -- 輸出 30 (通過函數獲取)
2.4 表和元表的區別
-
表(Table):
- 表是 Lua 中的基本數據結構,用于存儲鍵值對。
- 表可以用來表示數組、字典、集合、對象等。
- 表是動態的,可以根據需要添加或刪除鍵值對。
-
元表(Metatable):
- 元表是一個特殊的表,用于改變另一個表的行為。
- 元表可以包含一些特殊的字段(如
__index
、__newindex
、__add
等),用于定義表的特殊操作。 - 元表通過
setmetatable
函數設置,getmetatable
函數獲取。
- 表(Table) 是 Lua 中的基本數據結構,用于存儲鍵值對。
- 元表(Metatable) 是一個特殊的表,用于改變另一個表的行為。
__index
元方法用于處理對表中不存在的鍵的訪問,可以是一個表或一個函數。
通過使用元表和 __index
元方法,可以實現更靈活和強大的表操作,滿足各種編程需求。
3 面向對象范式
雖然 Lua 本身沒有內置的面向對象編程支持,但可以通過元表(metatables)和表(tables)來實現面向對象編程。
-- 定義一個類
Person = {}
Person.__index = Person-- 構造函數
function Person:new(name, age)local self = setmetatable({}, Person)self.name = nameself.age = agereturn self
end-- 方法
function Person:greet()print("Hello, my name is " .. self.name .. " and I am " .. self.age .. " years old.")
end-- 創建對象
local person = Person:new("Alice", 30)
person:greet()
4 Lua與UE引擎的交互
Lua 與 Unreal Engine(UE)交互通常通過第三方插件或綁定庫來實現。這些插件和庫提供了在 UE 中嵌入 Lua 腳本的能力,使得開發者可以使用 Lua 編寫游戲邏輯、控制游戲對象等。以下是一些常見的方法和工具:
4.1 使用第三方插件 UnLua
UnLua 是一個專門為 Unreal Engine 設計的 Lua 插件,提供了深度集成和高性能。以下是使用 UnLua 的基本步驟:
-
安裝 UnLua:
- 下載并安裝 UnLua 插件。
- 將插件添加到你的 UE 項目中。
-
配置 UnLua:
- 在項目設置中啟用 UnLua 插件。
- 配置 Lua 腳本路徑等參數。
-
編寫 Lua 腳本:
-
創建 Lua 腳本文件,例如
MyScript.lua
。 -
編寫游戲邏輯,例如:
print("Hello from UnLua!")function OnBeginPlay()print("Game started") end
-
-
在 UE 中調用 Lua 腳本:
-
在 UE 藍圖或 C++ 代碼中加載并執行 Lua 腳本。
// 在 C++ 代碼中加載 Lua 腳本 UUnLuaManager* UnLuaManager = UUnLuaManager::Get(); UnLuaManager->RunFile("MyScript.lua");// 調用 Lua 函數 UnLuaManager->CallFunction("OnBeginPlay");
-
4.2 使用 LuaBridge
LuaBridge 是一個輕量級的 C++ 庫,用于將 Lua 嵌入到 C++ 應用程序中。以下是使用 LuaBridge 與 UE 交互的基本步驟:
-
安裝 LuaBridge:
- 下載并集成 LuaBridge 到你的 UE 項目中。
-
編寫 C++ 代碼:
-
在 UE 項目中編寫 C++ 代碼,加載并執行 Lua 腳本。
#include "LuaBridge/LuaBridge.h" #include "lua.hpp"void RunLuaScript() {lua_State* L = luaL_newstate();luaL_openlibs(L);// 加載并執行 Lua 腳本if (luaL_dofile(L, "MyScript.lua") != LUA_OK){const char* error = lua_tostring(L, -1);UE_LOG(LogTemp, Error, TEXT("Error: %s"), UTF8_TO_TCHAR(error));}// 調用 Lua 函數lua_getglobal(L, "OnBeginPlay");if (lua_pcall(L, 0, 0, 0) != LUA_OK){const char* error = lua_tostring(L, -1);UE_LOG(LogTemp, Error, TEXT("Error: %s"), UTF8_TO_TCHAR(error));}lua_close(L); }
-
4.3 使用 Unreal Engine Lua Plugin
Unreal Engine Lua Plugin 是一個流行的插件,允許在 UE 中嵌入 Lua 腳本。以下是使用該插件的一些基本步驟:
-
安裝插件:
- 下載并安裝 Unreal Engine Lua Plugin。
- 將插件添加到你的 UE 項目中。
-
配置插件:
- 在項目設置中啟用 Lua 插件。
- 配置 Lua 腳本路徑等參數。
-
編寫 Lua 腳本:
-
創建 Lua 腳本文件,例如
MyScript.lua
。 -
編寫游戲邏輯,例如:
print("Hello from Lua!")function OnBeginPlay()print("Game started") end
-
-
在 UE 中調用 Lua 腳本:
-
在 UE 藍圖或 C++ 代碼中加載并執行 Lua 腳本。
// 在 C++ 代碼中加載 Lua 腳本 ULuaState* LuaState = NewObject<ULuaState>(); LuaState->DoFile("MyScript.lua");// 調用 Lua 函數 LuaState->GetFunction("OnBeginPlay"); LuaState->Call(0, 0);
-
4.4 底層實現原理
Lua 與 Unreal Engine(UE)交互的底層實現原理主要涉及以下幾個方面:
-
嵌入 Lua 解釋器:
- 在 UE 中嵌入 Lua 解釋器,使得 Lua 腳本可以在 UE 的運行時環境中執行。
- 這通常通過在 C++ 代碼中包含 Lua 解釋器庫(如
lua.hpp
)并初始化 Lua 解釋器來實現。
-
綁定 C++ 和 Lua:
- 通過綁定機制,將 UE 的 C++ 類和函數暴露給 Lua,使得 Lua 腳本可以調用這些 C++ 函數。
- 綁定機制可以手動實現,也可以使用自動化工具或庫(如 LuaBridge、Sol2、UnLua 等)來簡化綁定過程。
-
腳本加載和執行:
- 提供加載和執行 Lua 腳本的功能,使得 Lua 腳本可以在特定的事件或條件下執行。
- 這通常通過在 C++ 代碼中調用 Lua 解釋器的 API 來實現,例如
luaL_dofile
用于加載和執行 Lua 腳本。
-
事件和回調機制:
- 實現事件和回調機制,使得 Lua 腳本可以響應 UE 中的事件(如游戲開始、對象碰撞等)。
- 這通常通過在 C++ 代碼中注冊 Lua 函數作為回調函數,并在特定事件發生時調用這些回調函數來實現。
以下是一些具體的實現細節,展示了如何在 C++ 代碼中嵌入 Lua 解釋器并實現與 Lua 的交互。
4.4.1 嵌入 Lua 解釋器
首先,需要在 C++ 代碼中包含 Lua 解釋器庫并初始化 Lua 解釋器:
#include "lua.hpp"lua_State* L = luaL_newstate(); // 創建一個新的 Lua 狀態
luaL_openlibs(L); // 打開 Lua 標準庫
4.4.2 綁定 C++ 和 Lua
可以使用 LuaBridge 或其他綁定庫來簡化綁定過程。以下是使用 LuaBridge 的示例:
#include "LuaBridge/LuaBridge.h"void HelloWorld()
{UE_LOG(LogTemp, Log, TEXT("Hello from C++"));
}void BindFunctions(lua_State* L)
{luabridge::getGlobalNamespace(L).addFunction("HelloWorld", HelloWorld);
}
在 Lua 腳本中,可以調用綁定的 C++ 函數:
HelloWorld() -- 調用 C++ 函數
4.4.3 腳本加載和執行
可以在 C++ 代碼中加載和執行 Lua 腳本:
if (luaL_dofile(L, "MyScript.lua") != LUA_OK)
{const char* error = lua_tostring(L, -1);UE_LOG(LogTemp, Error, TEXT("Error: %s"), UTF8_TO_TCHAR(error));
}
4.4.4 事件和回調機制
可以在 C++ 代碼中注冊 Lua 函數作為回調函數,并在特定事件發生時調用這些回調函數:
// 注冊 Lua 回調函數
lua_getglobal(L, "OnBeginPlay");
if (lua_isfunction(L, -1))
{lua_pcall(L, 0, 0, 0);
}
在 Lua 腳本中定義回調函數:
function OnBeginPlay()print("Game started")
end
4.4.5 總結
Lua 與 Unreal Engine 交互的底層實現原理主要涉及嵌入 Lua 解釋器、綁定 C++ 和 Lua、加載和執行 Lua 腳本以及實現事件和回調機制。通過這些機制,可以在 UE 中嵌入 Lua 腳本,實現靈活的游戲邏輯編寫和控制。使用第三方插件和庫(如 UnLua、LuaBridge 等)可以簡化這些過程,使得開發者更容易實現 Lua 與 UE 的交互。