WECHAT

扫码添加微信

YoungFan 微信二维码
← 返回 UE5 笔记
UE5 日常笔记 (未整理) 封面
开发笔记研究中

UE5 日常笔记 (未整理)

UE C++ 标识符记录

UE5C++Blueprint

2026-10-13

UMG中有关PlayerState初始化操作,需要等待PlayerState复制完毕

多人模式下,UMG中进行PlayerState相关的初始化操作(例如:获取PlayerState上的某个组件),由于客户端(UMG只存在于客户端)的PlayerState是否从服务端复制到客户端,这是一个异步过程。因此在UMG的Construct或OnInitialized事件内不一定能获取到PlayerState,需要确定PlayerState复制完成了才能进行初始化。

可以通过在PlayerController的InitPlayerState()(适用Standalone和Listen Server主机)和OnRep_PlayerState()(适用纯客户端)内广播回调或事件,伪代码如下:

void APlayerController::InitPlayerState()
{
	Super::InitPlayerState();
	//Standalone、Listen Server主机初始化调用
	NotifyLocalPlayerStateReady();
}
void APlayerController::OnRep_PlayerState()
{
	Super::OnRep_PlayerState();
	//纯客户端等到PlayerState同步完毕后,调用
	NotifyLocalPlayerStateReady();
}
//通知本地客户端PlayerState就绪
void APlayerController::NotifyLocalPlayerStateReady()
{
	if(!IsLocalController())
	{
		return;
	}

    // ...

	//执行回调
	OnLocalPlayerStateAvailable.Broadcast();
	//广播全局事件
	UGameplayMessageSubsystem::Get(this).BroadcastMessage();
}

对于Listen Server模式,如果不想每次都判断是Host还是Client,直接走先监听再执行的固定流程。

2026-10-12

UMG内部,优先使用GetOwningPlayer

UMG内部如果当前本地玩家的相关的Actor或组件(如PlayerController、PlayerState),优先通过GetOwningPlayer()获取。

用GetPlayerController(0)不保证一定获取到的是本地主玩家Controller,其他GetPlayerXXX(0)类函数也一样。

可在APlayerController::PawnLeavingGame()处理里玩家掉线

在《Steal An Egg》这个项目如果玩家在偷蛋逃跑的过程中掉线,需要丢下正持有的蛋。

丢蛋在应该在服务器做(DS),所以选择重载APlayerController::PawnLeavingGame()并指向蛋的掉落逻辑。

而且在执行APlayerController::PawnLeavingGame()时Pawn还未销毁,刚好可以根据Pawn的位置计算掉落点。

GameMode::Logout()中的CleanupLeavingPlayers()虽然也适合做掉线逻辑,但对于依赖角色位置的丢蛋操作,时机偏晚了。

2026-10-10

是否使用UFCUNTION宏速查表

使用方式 是否需要 UFUNCTION
AddDynamic 需要
BindDynamic 需要
BindUFunction 需要
BlueprintCallable/Pure/Event 需要
Server/Client/NetMulticast RPC 需要
自己声明的 RepNotify 需要
AddUObject 不需要
CreateUObject 不需要
AddLambda 不需要
普通成员函数直接调用 不需要
普通虚函数 override 不需要
Enhanced Input 成员函数绑定 不需要

Development无法触发断点,换成DebugGame才行

DebugGame 和 Development 的主要区别是:游戏 C++ 代码是否优化,以及调试体验与运行性能的取舍。

配置 游戏代码 引擎代码 适用场景
DebugGame 通常关闭优化,方便调试 优化构建 查游戏逻辑、打断点、看变量
Development 开启大部分优化 优化构建 日常开发、运行和性能观察
Debug 调试构建 调试构建 深入调试引擎内部,开销更大

Development 也能打断点,并不是没有调试信息。但编译器优化可能会:

  • 把函数内联,导致调用栈与源码结构不同;
  • 删除或合并某些语句,断点自动移动;
  • 消除局部变量,调试器显示“变量已优化掉”;
  • 调整指令顺序,单步执行看起来跳行。 DebugGame 更容易按源码逐行执行,也更容易查看局部变量,代价是游戏代码运行得更慢

2026-10-9

问题1

蓝图中,用持有AbilitySystemComponent的PlayerState作为Target,通过Wait Gameplay Tag Add To Actor监听State.Carrying.StolenEgg加入事件,Added触发RefreshHUDState()。

RefreshHUDState()函数内通过HasMatchingGameplayTag()判断玩家是否拥有State.Carrying.StolenEgg时,应以AbilitySystemComponent对象为Target。之前用PlayerState作Target,始终返回false。

UGameplayMessageSubsystem::Get

EndAbility中使用UGameplayMessageSubsystem::Get(this)广播事件时,先判断UGameplayMessageSubsystem::HasInstance(this)是否有效。

20260928

Error: Using CommonUI without a CommonGameViewportClient derived game viewport client.

完整错误:LogUIActionRouter: Error: Using CommonUI without a CommonGameViewportClient derived game viewport client. CommonUI Input routing will not function correctly. To disable this warning set CommonUI.Debug.CheckGameViewportClientValid=0 under [SystemSettings] in your project’s DefaultEngine.ini

如果项目使用了CommonUI,那么需要指定GameViewportClientClassName为CommonUI的CommonGameViewportClient,否则会影响以下功能:

  • CommonActivatableWidget输入路由。
  • UI输入优先级和输入阻断。
  • Back/返回操作。
  • 手柄焦点与导航。
  • Common Action的绑定和分发。
  • 多个激活界面之间的输入切换。
  • 游戏输入与UI输入之间的协调。

在DefaultEngine.ini中添加:

[/Script/Engine.Engine] GameViewportClientClassName=/Script/CommonUI.CommonGameViewportClient

然后完整关闭并重启编辑器。

Discussion

留言讨论

无需注册账号
正在加载留言区…

发表留言时,评论服务会记录必要的 IP 与 User-Agent 信息,用于安全审核和防止滥用。