目录
- 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 = 10
if x > 0 then
print("x is positive")
elseif x < 0 then
print("x is negative")
else
print("x is zero")
end
循环语句
-- while 循环
local i = 1
while i <= 5 do
print(i)
i = i + 1
end
-- for 循环
for i = 1, 5 do
print(i)
end
-- 泛型 for 循环
local t = {10, 20, 30}
for index, value in ipairs(t) do
print(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
end
print(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)
end
return 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 then
print("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" then
return 30
else
return nil
end
end
}
-- 设置元表
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 = name
self.age = age
return 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 的交互。