OverView
UnLua是针对UE4的功能丰富且经过高度优化的脚本解决方案。 开发人员可以使用Lua来开发游戏逻辑,并且可以使用Lua的热加载功能更快地迭代游戏逻辑。 本文档将介绍UnLua的主要功能和基本编程模式。
Lua&UE 绑定
Unlua提供了两种绑定方式,静态绑定和自定义绑定。
静态绑定
如果是C++里,类里面需要实现Unlua接口,写一个函数GetModuleName_Implementation,函数返回返回一个Lua文件路径
蓝图里就直接在类设置里添加Unlua接口,会自动添加GetModuleName接口,在里面填写lua文件名字即可。(文件前有时需要写对应的路径)
自定义绑定
自定义绑定适用于实时生成Actor和对象
比如说
local Proj = World:SpawnActor(ProjClass, Transform, ESpawnActorCollisionHandlingMethod.AlwaysSpawn, self, self.Instigator, "Weapon.BP_DefaultProjectile_C")
“Weapon.BP_DefaultProjectile_C” 是一个lua文件路径。
local ProxyObj = NewObject(ObjClass, nil, nil, "Objects.ProxyObject")
“Objects.ProxyObject”也是一个lua文件路径
Lua文件路径都是相对于Content/Scripts的相对路径
这里的实践使用暂时还没见过。
Lua调用引擎
UnLua提供了两种从Lua一侧访问引擎的方法:1.使用反射系统动态导出; 2.在反射系统之外静态导出类,成员变量,成员函数,全局函数和枚举。
使用反射系统导出可以使代码干净,直观,并且可以消除大量胶水代码。
获取UCLASS
local Widget = UWidgetBlueprintLibrary.Create(self, UClass.Load("/Game/Core/UI/UMG_Main"))
UWidgetBlueprintLibrary 是一个UCLASS,Lua中的类名字必须是PrefixCPP(类前缀加类型,如果是AActor,蓝图类,那么就是ABP,个人理解)+类名字+【_c】
获取UFUNCTION
Widget:AddToViewport(0)
如果UFUNCTION(有标签 'BlueprintCallable' or 'Exec'),有一个默认参数,那么在lua中可以不写这个默认参数。
返回值处理:返回值包括非常量引用和返回参数。这些值都可以分为原生类型(比如int bool string)和非原生类型(UE的自定义结构体。如下图
UFUNCTION()
void GetPlayerBaseInfo(int 32 &level,float &Health,FString &Name) const;
对于非常量引用的原生类型调用:Lua代码如下
local Level, Health, Name = self:GetPlayerBaseInfo()
对于非原生类型比如:
UFUNCTION()
void GetHitResult(FHitResult) const;
lua里有两种调用方法
local HitResult = FHitResult()
self:GetHitResult(HitResult)
或者
local HitResult = self:GetHitResult()
第一个调用函数有点类似于C++,如果多次调用,第一个函数比第二个函数会高效率很多
对于返回参数的调用(原生类型)如下
UFUNCTION()
float GetMeleeDamage() const;
原生类型lua代码调用如下
local MeleeDamage = self:GetMeleeDamage()
非原生类型
UFUNCTION()
FVector GetCurrentLocation() const
lua有三种调用方式
local Location = self:GetCurrentLocation()
Or
local Location = FVector()
self:GetCurrentLocation(Location)
Or
local Location = FVector()
local LocationCopy = self:GetCurrentLocation(Location)
第一个最直观,但是后面两个调用方式效率更高。
潜在功能
潜在功能允许开发者使用同步调用风格去调用异步逻辑。一个典型的潜在功能就是Delay
转存失败重新上传取消我们可以在lua协程里调用delay函数
coroutine.resume(coroutine.create(function(GameMode, Duration) UKismetSystemLibrary.Delay(GameMode, Duration) end), self, 5.0)
(这里的实践在代码中还未见过,待补充)
Unlua对UFUNCTION调用进行了一下几点优化
- 永恒的参数buffer
- 优化局部函数调用
- 优化函数传递
- 优化输出值处理
lua获取USTRUCT
local Position = FVector()
FVector是一个USTRUCT
获取UPROPERTY
local Position = FVector()
Position.X = 256.0
X就是FVector的一个UPROPERTY
Delegates(可以以通用的类型安全的方式在C ++对象上调用成员函数。 委托可以动态绑定到任意对象的成员函数,即使将来调用者不知道该对象的类型,也可以在将来对其进行调用。)
将Lua函数绑定到一个delegate上去
FloatTrack.InterpFunc:Bind(self, BP_PlayerCharacter_C.OnZoomInOutUpdate)
获取UENUM
在函数调用的时候直接通过“.”获取枚举即可
如果要增加新的枚举值
local ObjectTypes = TArray(EObjectTypeQuery)
ObjectTypes:Add(EObjectTypeQuery.Player)
ObjectTypes:Add(EObjectTypeQuery.Enemy)
ObjectTypes:Add(EObjectTypeQuery.Projectile)
先将枚举用数组获取,再调用add添加
手动导出库
出于性能考虑,Unlua手动导出了引擎库
Basic Classes
- UObject
- UClass
- UWorld
Common Containers
- TArray
- TSet
- TMap
local Indices = TArray(0)
Indices:Add(1)
Indices:Add(3)
Indices:Remove(0)
local NbIndices = Indices:Length()
local Vertices = TArray(FVector)
local Actors = TArray(AActor)
Math Libraries
- FVector
- FVector2D
- FVector4
- FQuat
- FRotator
- FTransform
- FColor
- FLinearColor
- FIntPoint
- FIntVector
总结
- 关于绑定,unlua提供了两种绑定,一种是通过复写unlua的getmodulename接口,还有一种动态绑定是在动态生成actor时和object时调用。
- 关于调用lua调用引擎(通过反射系统动态导出
- 调用UCLASS:直接通过反射来进行调用
- 调用UFUNCTION,USTRUCT,ENUM,UPROPERTY 只要在C++里被标记了的就可以直接调用
- 关于非常量引用参数,返回参数的执行方法
- 潜在功能(有待实践
- 执行Delegates(和onclicked绑定时类似的,不过只能绑定一个事件,是在蓝图里的delegate绑定了Lua里的回调函数)
- Unlua导出了一些通用库和类,可以直接在lua中调用(需要拿到全局的这些变量