移动/游戏
用 UE Gameplay Framework…
在 Unreal Engine 中实现 GameMode、GameState、PlayerController、PlayerState、Pawn、Character、GameInstance 等玩法框架类时,按机器存在性与复制规则正确选型与实现。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 60/100 ×0.15
适用场景
用 UE Gameplay Framew特定
解决思路
- 先阅读 `.agents/ue-project-context.md`,确认游戏类型(单人、合作、竞技多人、专用服务器还是 listen server),再决定子类化哪些类以及采用哪些复制模式。
- 按机器存在性划分职责:AGameModeBase/AGameMode 仅存在于服务器与 standalone,绝不在客户端实例化;AGameStateBase/AGameState 在所有机器上存在并完全复制;APlayerController 在服务器上每个玩家一个、客户端只持有自己的;APlayerState 在服务器与所有客户端存在且始终相关;APawn/ACharacter 在服务器与所有客户端存在并复制;UGameInstance 每个进程一个,跨所有关卡加载存活。
- 用 AGameModeBase 处理大厅/简单游戏,用 AGameMode 处理完整比赛流程状态机(EnteringMap → WaitingToStart → InProgress → WaitingPostMatch → LeavingMap,失败时 Aborted),并实现 ReadyToStartMatch 与 ReadyToEndMatch 钩子。
- 在 GameMode 构造函数中设置类指派:DefaultPawnClass、GameStateClass、PlayerControllerClass、PlayerStateClass、HUDClass,以及 bUseSeamlessTravel。
- 按服务器加入生命周期实现 GameMode 回调:InitGame(玩家加入前的地图规则初始化)、PreLogin(在此拒绝:服务器满、封禁)、Login(创建 PlayerController、分配 UniqueId)、PostLogin(第一个可安全发服务器→客户端 RPC 的点,在此分配队伍;DispatchPostLogin 在 5.6 已弃用,直接重写 PostLogin)、Logout、HandleStartingNewPlayer。
- 按生成管线实现玩家生成:HandleStartingNewPlayer → RestartPlayer → FindPlayerStart → SpawnDefaultPawnFor → Possess。
- 把客户端需要的全局数据(分数、比赛计时、阶段)放进 GameState 的复制属性,因为客户端读不到 GameMode;用 PlayerArray 在所有机器上访问全部 APlayerState。
- 自定义 GameState 复制数据时,在 GetLifetimeReplicatedProps 中用 DOREPLIFETIME 注册属性,并对需要回调的属性使用 ReplicatedUsing。
- 在 PlayerController 中处理非 Pawn 输入(观战、UI 快捷键、跨附身持久的全局按键),重写 SetupInputComponent;Pawn 专属输入则重写 APawn::SetupPlayerInputComponent。
- Enhanced Input 在 PlayerController::BeginPlay 中通过 ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem> 调用 AddMappingContext,并用 SetInputMode 设置 FInputModeGameOnly/UIOnly/GameAndUI。
- RPC 模式:客户端→服务器用 UFUNCTION(Server, Reliable, WithValidation);服务器→客户端用 UFUNCTION(Client, Reliable)。
- 附身与解除附身必须在服务器执行:PlayerController->Possess(NewPawn) 与 PlayerController->UnPossess()。
- 在 listen server 上,主机的 PlayerController 同时是 ROLE_Authority 且本地控制,用 IsLocalController() 守卫双重角色逻辑,避免把「权威即非本地」的假设写进代码。
- 用 PlayerController->ClientTravel 把当前客户端连接到其他服务器;用 GetWorld()->ServerTravel 在服务器上把所有玩家移动到新地图。
- 用 APlayerState 保存跨 Pawn 死亡存活的累计数据(Kills、Deaths、TeamIndex),通过 MyPawn->GetPlayerState()、MyPC->PlayerState 或 GameState 的 PlayerArray 访问。
- 非人形实体(载具、炮塔、无人机)或需要完全自定义移动组件时使用 APawn;ADefaultPawn 是引擎内置的浮动移动 Pawn,用作 DefaultPawnClass 占位。
- 行走人形使用 ACharacter,在构造函数中配置 CapsuleComponent、Mesh 相对位置与旋转、CharacterMovement 的 MaxWalkSpeed、JumpZVelocity、GravityScale、AirControl、NavAgentProps.bCanCrouch。
- 使用 ACharacter 的 Jump/StopJumping/CanJump、JumpMaxHoldTime(可变跳跃高度)、JumpMaxCount(二段跳)、LaunchCharacter、Crouch/UnCrouch,以及 GetCharacterMovement()->SetMovementMode 切换 MOVE_Walking/MOVE_Falling/MOVE_Swimming/MOVE_Flying/MOVE_Custom。
- 自定义移动模式:设置 MOVE_Custom 并在 UCharacterMovementComponent 子类中重写 PhysCustom(float DeltaTime, int32 Iterations),用 CustomMovementMode 字节区分多个自定义模式,最后调用 Super::PhysCustom。
- 移动复制由引擎自动完成(客户端发 ServerMovePacked,服务器回 ClientMoveResponsePacked),不要手动调用这些 RPC。
- 用 UGameInstance 保存跨关卡存活的数据:重写 Init(启动时一次,子系统初始化、读存档)、OnStart、Shutdown;通过 GetWorld()->GetGameInstance<UMyGameInstance>() 或 GetGameInstance()->GetSubsystem<>() 访问。
- 会话管理通过 GameInstance 访问 Online Subsystem:IOnlineSubsystem::Get()->GetSessionInterface(),用 CreateSession 创建会话(设置 bIsLANMatch、NumPublicConnections、bShouldAdvertise),用 FindSessions 查找,用 JoinSession 加入,并绑定对应的完成委托;在 Build.cs 中加入 "OnlineSubsystem" 与 "OnlineSubsystemUtils" 依赖;加入后用 GetResolvedConnectString 取连接串并调用 ClientTravel。
- 选择旅行模式:非无缝 ServerTravel 会断开客户端并重建 GameMode/GameState,适合干净切换地图;bUseSeamlessTravel=true 的无缝旅行不断开客户端,适合大厅→游戏、回合切换。
- 无缝旅行中始终存活:UGameInstance、APlayerController、APlayerState;从不存活:AGameMode、AGameState、关卡 Actor;可选存活:在 GetSeamlessTravelActorList() 中加入的 Actor。
- 避免常见错误:不要在客户端调用 GetAuthGameMode(会返回 nullptr),先用 HasAuthority() 守卫;分数给所有客户端看用 APlayerState 而非 APlayerController;比赛计时用 GameState 复制属性而非 GameMode;跨关卡数据用 UGameInstance 而非 AGameState;输入绑定放在 PlayerController 或 Pawn::SetupPlayerInputComponent,不要放在 ACharacter 主体。
- 需要服务器确认的 Pawn 时使用 AcknowledgedPawn,而不是 GetPawn()(后者可能在服务器确认附身前就返回 Pawn)。
- 用 if (GetNetMode() != NM_DedicatedServer) 守卫 HUD、相机、音频等绝不应在专用服务器上运行的逻辑。
- 在 PIE 中用 Number of Players 设为 2 或更多测试多人逻辑:每个玩家有各自的 PlayerController,但共享同一个 GameMode 实例。
适用边界 · 注意事项
- 不涉及 Unreal Engine 玩法框架类(GameMode、GameState、PlayerController、PlayerState、Pawn、Character、GameInstance)的项目不适用。
- 纯网络复制细节(DOREPLIFETIME 条件、RPC 模式、push model)应参考 ue-networking-replication;输入映射上下文与输入动作应参考 ue-input-system。
- Actor 生命周期、组件 tick、附件关系应参考 ue-actor-component-architecture。