UNREAL 笔记

函数返回引用

  • 函数返回引用与返回指针本质一样都是返回地址, 否则函数将返回数据的拷贝
    ps: 不要将局部(函数中)创建的引用作为函数返回值
// 全局变量
int val = 10;

// 定义函数返回引用
int& RetValRef()
{
	return val;
}

// 将函数作为左值使用时(使用引用接收返回值),返回地址
// 本质上发生 int* const v1 = &val;
int& v1 = RetValRef(); 
// 引用 v1 作为左值可修改 val 的值
v1 = 20;

// 将函数作为右值使用时,返回该地址指向的值
// 本质上发生调用解引用 *val 对 v2 进行赋值
int v2 = RetValRef(); 
  • UFUNCTION 和 DELEGATE 在蓝图中返回 UStruct 只能使用返回引用或值
  • UFUNCTION 和 DELEGATE 在蓝图中返回 UClass 可以返回裸指针
  • 多播委托在返回结构体引用时, 必须加 const
// 返回 * 将报错, Inappropriate '*' on variable of type 'FLevelUpInfo'
UFUNCTION()
FUStructType* GetStructInfo(int32 XP); 

// 返回引用 OK
UFUNCTION()
FUStructType& GetStructInfo(int32 XP);

 // UClass 返回 * OK
UFUNCTION()
AActor* GetEnemyActor();

// NewValue 如果不加 const 要报错, 但 MyActor 返回 * OK
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FSomeDelegate, const FAttributeInfoData&, Data, AActor*, MyActor, const FVector&, NewValue);

函数参数是引用

  • 非 const 参数会在蓝图中作为输出 Pin
// 参数 TargetLocation 将作为输出 Pin
UFUNCTION(BlueprintCallable)
void SpawnProjectile(FVector& TargetLocation);
  • const 参数会在蓝图中作为输入 Pin
// 将 TargetLocation 定义为 const, 将作为输入 Pin, 但 TargetLocation 不能在函数体中修改
UFUNCTION(BlueprintCallable)
void SpawnProjectile(const FVector& TargetLocation);

// 或使用 UPARM(ref) 宏, 使用该宏可以在函数体中修改 TargetLocation
UFUNCTION(BlueprintCallable)
void SpawnProjectile(UPARM(ref) FVector& TargetLocation);

修改函数返回值 / 参数显示名称

  • 使用 UPARAM 宏可修改函数参数或返回值的显示名称
UPARAM(DisplayName = "People Name") FString GetName(UPARAM(DisplayName = "Identifier") float id);

关于 UPARAM 标识符的更多用途

  • 推荐使用引用参数作为函数返回值
// 在蓝图节点中输出 Pin 与函数返回值效果一样, 同时使用引用参数还可以返回多个返回值
UFUNCTION(BlueprintCallable)
void GetOverlapActors(TArray<AActor*>& OutActors);

虚幻中的指针

  • 对于智能指针 TSharedPtr, TWeakPtr, and TUniquePtr 不能用于 UObject (UCALSS) 类型, UObject 使用虚幻自己的反射系统管理
  • 什么时候用 raw pointer
    一般函数局部变量与函数返回值使用 raw pinter, 超出范围时局部变量本身自动销毁(不是指向的内存哈)
  • 什么时候用 TObjectPtr
    类的成员变量是 UObject 类型时可使用 TObjectPtr 替代 raw pointer, 注意:不管哪种指针必须标记 UPROPERTY 来让该指针被虚幻垃圾回收跟踪. 如果不想把变量标记为 UPROPERTY 可以使用 TWeakObjectPtr (不是 TWeakPtr), 它所指向的 UObject 被销毁时会置空而不会悬挂.
  • 什么时候用引用
    确定变量有值; 函数形参; 函数返回值; 这几种情况可偏向使用引用
  • 什么时候用智能指针
    不能是 UObject 类型. 所以 USTRUCT 很适合使用. USTRUCT 不属于 UObject 体系, 不由垃圾回收管理,但它可以使用智能指针提供的垃圾回收管理来防止 UObject 被销毁时产生的 USTRUCT 指针悬挂

引擎中的对象处理

  • 不再被引用或已被显式标记为销毁的 UObject 将被垃圾回收机制定期清除
  • 只有标记了 UProperty 的 AActor 或 UActorComponent 的指针变量以及容器中存储的指针,在清理时会自动赋空值 (= nullptr)
  • 对于未标记 UProperty 的原始指针,它引用的 UObject 被销毁时不会被赋空值,将出现悬挂指针.
  • UStruct 被当作数值类型处理并且不会垃圾回收, new 出来的 UStruct 可使用智能指针管理回收

IsValid

IsValid 既判断 nullptr 又判断是否准备被销毁(等待垃圾回收)

// Enemy 有可能会被销毁时使用 IsValid
if(IsValid(Enemy)) {...}
// 如果只是简单的 Proerty 等可使用
if(MaterialInstance) {...}

C++ 中定义接口

  • 对于无返回值的接口可以在 Event Graph 中实现 (类似 custom event),对于有返回值的接口需要通过 Override Function 来实现.
  • 在蓝图中调用接口时可像静态函数一样调用 (不需要Cast),如果 Target 未实现该函数则会略过该函数的调用
/**
 * 定义为 BlueprintImplementableEvent 的函数
 * 表明该方法将只能在蓝图中实现,不能在 C++ 中实现
 * 函数不能加 virtual,会导致编译报错
 * 使用 const 将引用参数变更为输入 PIN (否则会作为输出 PIN)
 * 接口中的 BlueprintCallable 表明该函数将作为静态函数可在蓝图中直接调用
 */
UFUNCTION(BlueprintImplementableEvent, BlueprintCallable)
void DoMotionWarp(const FVector& FacingTarget);

/**
 * 定义为 BlueprintNativeEvent 的函数
 * 表明即可在蓝图中实现, 也可在 C++ 中定义默认实现
 * 函数不能加 virtual,会导致编译报错
 * 在 C++ 中实现该函数需要加上 _Implementation
 */
UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
void SetCombatTarget(AActor* InCombatTarget);

在 C++ 中调用 BlueprintNativeEvent 接口,需要调用 Native C++ 实现的版本

// 判断是否实现接口
if (Actor->Implements<UCombatInterface>())
{
	// 调用 Native C++ 的实现
	if (!ICombatInterface::Execute_IsDead(Actor))
	{
		OutActors.AddUnique(Actor);
	}
}

在接口中使用 BlueprintNativeEvent 返回引用时发现报错(返回类型不匹配)

// 报错
UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
TArray<FTaggedMontage>& GetAttackMontages();

// 改这样实现
UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
void GetAttackTaggedMontages(TArray<FTaggedMontage>& OutTaggedMontages);

DELEGATE 小坑

  • DYNAMIC Delegate 参数需要加名称
/* DYNAMIC delegate 参数需要加名称 */
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnFloatValueChangedSignature, float, Value);
  • 非 DYNAMIC Delegate 参数不能加名称, 否则报错 ‘参数过多’
/* 推荐参考官方定义方式 */
DECLARE_MULTICAST_DELEGATE_OneParam(FOnFloatValueChangedNative, float /* NewValue */);

DYNAMIC Delegate 对绑定对象保持弱引用关系, 对象销毁后不再调用绑定的函数. 但注意发现在 UserWidget Remove from parent 后再次重新绑定会造成重复的累积绑定,原因可能是未被立即回收,需要手动调用 Unbind 函数

字符串

  • TEXT()宏(注意不是FText)是根据环境判断是否为字符串前面加 ‘L’, 如 TEXT(“AB”) 相当于 L"AB", 又叫宽字符串
  • 字符串前面加 ‘L’ 的意思是将字符串作为 Unicode 编码方式解析, 否则作为 ANSI 编码来解析. Unicode 每个字符占两个字节, ANSI 占一个且内容少容易乱码

常用 FunctionLibrary

// 创建 AudioComponent 并挂载到指定组件上, 跟随物体并持续发声
UGameplayStatics::SpawnSoundAttached
// 在指定位置播放声音, 一次性音效
UGameplayStatics::PlaySoundAtLocation
// 在指定位置创建 NiagaraComponent
UNiagaraFunctionLibrary::SpawnSystemAtLocation
// 额外的 DrawDebug 方法
UKismetSystemLibrary::DrawDebugArrow
// 各种物理检测函数
UKismetSystemLibrary::SphereTraceSingle

查看 Graph Node 源码

  • 材质节点源码
    UnrealEngine\Engine\Source\Runtime\Engine\Private\Materials\MaterialExpressions.cpp
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值