系列导读
经过前两篇,你已经装好了引擎、创建了项目,也熟悉了编辑器的基本操作。理解 UE 的框架类是入门开发的重中之重,后续写蓝图、写 C++,本质上都是在与这些类打交道。
第一次打开 UE 的文档或源码,很容易被一堆名字吓住:GameMode、GameState、PlayerController、PlayerState、Pawn、Character、HUD......它们长得都差不多,到底有什么区别?
别担心。本篇主要讲解这些类是什么,管什么;在真实场景当中,如何完成一整局游戏的。
读完你会发现,这套框架不是什么死记硬背的知识,而是一套非常自然的"分工设计"。
一、核心框架类什么
在讲任何细节之前,先建立整体印象。UE 的框架类本质上是在回答一个问题:"一局游戏里,都需要哪些角色来分工?"
| 类 | 一句话定义 | 类比 |
|---|---|---|
| GameMode | 定义游戏规则":用什么角色、怎么重生、怎样算赢 | 裁判 |
| GameState | 存放全局共享的游戏数据(比分、剩余时间),并同步给所有玩家 | 记分牌 |
| PlayerController | 接收玩家输入(键盘/鼠标),指挥角色行动 | 玩家的大脑 |
| PlayerState | 记录单个玩家的持久数据(昵称、击杀数、得分) | 玩家档案 |
| Pawn | 世界中"被控制的身体",自己不会思考 | 身体 |
| Character | Pawn 的强化版:能走能跳、带骨骼动画的角色 | 有血有肉的身体 |
| AIController | AI 的大脑,用行为树驱动 Pawn 行动 | AI 的大脑 |
| HUD / UMG | 把游戏状态画到屏幕上(血条、准星、比分板) | 显示屏 |
再提炼一层,这八个类其实属于四个"层级":
- 规则层:GameMode(只存在于服务器,负责裁决);
- 状态层:GameState(全局)、PlayerState(个人),负责"让所有人看到同一份数据";
- 控制层:PlayerController / AIController(大脑)+ Pawn / Character(身体),负责"行动";
- 表现层:HUD / UMG,负责"展示"。
这里最主要的:AGameMode 、AGameState 、APlayerController 、APawn/ACharacter 、AHUD/UMG
打开任意关卡,在菜单栏进入 窗口(Window)→ 世界场景设置(World Settings),右侧面板中可以看到当前关卡使用的游戏框架类:

这里指定的 GameMode,决定了这个关卡"怎么玩"------用什么角色、用什么控制器、死了怎么重生。其他几个类(GameState、PlayerState、HUD 等)通常在 GameMode 内部指定。
类继承图
UObject(所有对象的基类)
└── AActor(世界中的实体,可以放进关卡)
├── APawn(可被控制/附身的载体)
│ └── ACharacter(带骨骼动画和移动组件的 Pawn,最常用)
├── AController(控制 Pawn 的"大脑",不在关卡中放置)
│ ├── APlayerController(玩家控制,处理键盘/鼠标输入)
│ └── AAIController(AI 控制,由行为树驱动)
├── AGameModeBase(游戏规则定义者)
├── AGameStateBase(全局游戏状态,同步所有客户端)
└── AHUD(平视显示器,绘制 UI)
二、每个类是做什么的
1. AGameMode
核心职责:定义"游戏规则"。包括使用哪个角色、哪个控制器、如何重生、胜利条件是什么。
常用可重写的函数:
| 函数 | 调用时机 | 典型用途 |
|---|---|---|
InitGame() |
游戏开始时 | 初始化全局数据 |
PreLogin() / PostLogin() |
玩家连接前 / 连接后 | 校验玩家、发放初始资源 |
SpawnDefaultPawnFor() |
需要生成角色时 | 自定义出生点选角逻辑 |
OnActorKilled()(需自行调用) |
任意 Actor 死亡时 | 计分、重生调度 |
EndMatch() |
满足胜利条件时 | 结束比赛 |
在编辑器里怎么用 :在世界场景设置中直接指定,或创建蓝图继承 GameModeBase,在类默认值(Class Defaults)里配置 DefaultPawnClass、PlayerControllerClass、GameStateClass 等。
GameMode 只存在于服务器。单机游戏中你就是服务器,所以一切正常;但做联机时,客户端拿不到 GameMode------比分这类所有人都要看的数据必须放进 GameState。
2. AGameState
核心职责 :存储全局共享的游戏状态,并自动复制(Replication)到所有客户端。剩余时间、双方比分、当前回合数都属于它。
UPROPERTY(Replicated, BlueprintReadOnly)
float RemainingTime;
UPROPERTY(Replicated, BlueprintReadOnly)
int32 TeamAScore;
简单来说 GameMode 决定游戏规则;判断谁赢了,什么时候结束。而GameState是记录游戏状态,给所有人共享数据
3. APlayerController
核心职责 :捕获输入、控制视角、管理 UI 交互。它是玩家与游戏世界之间的"代理",每个玩家独立拥有一个。
常用功能:
- 输入处理:
SetupInputComponent()中绑定按键(后续 获取输入篇 详解); - 视角控制:持有 CameraManager,管理相机震动、淡入淡出;
- UI 交互:管理鼠标显示/隐藏、SetInputMode(游戏模式 / UI 模式);
- 获取玩家状态:
GetPlayerState<APlayerState>()拿到自己的战绩数据。
4. APawn 与 ACharacter
APawn :世界中被控制的实体,本身没有智能 。它提供 AddMovementInput() 等移动接口,但"什么时候移动"要听 Controller 的。
ACharacter:最常用的 Pawn 子类,额外拥有:
- CharacterMovementComponent:处理走/跑/跳/游泳/飞行的移动组件,内置网络同步和碰撞;
- SkeletalMesh:骨骼网格体,挂上角色模型;
- 胶囊体碰撞(CapsuleComponent):角色的根碰撞。
简单来说,Pawn 像是一个句柄,控制物体如何移动; Charactor 是任务角色的类。
Pawn 与 Controller 的接口 :Controller 通过 Possess() 附身 Pawn,通过 UnPossess() 离开。附身之后,Pawn 收到的输入才有效。
5. AHUD 与 UMG
AHUD :传统的画布绘制类,通过 DrawHUD() 用代码画准星、血条。现代项目更多把它当作 UMG 的"宿主"。
UMG(Widget):基于控件的 UI 系统,用 UUserWidget 做血条、背包、计分板,是实际开发的主流选择。HUD 小节先了解概念即可,后续会专门展开UMG的详细介绍。
6. APlayerState
核心职责 :记录单个玩家的持久数据:昵称、ID、击杀数、死亡数、得分。
和 GameState 的区别:GameState 存"全局局势"(哪队领先),PlayerState 存"个人战绩"(你杀了几个人)。联机时每个客户端都有一份所有玩家的 PlayerState 副本。
7. AAIController
与 PlayerController 平级,但不做输入处理,而是由**行为树(Behavior Tree)和黑板(Blackboard)**驱动。核心函数:
RunBehaviorTree():启动行为树;MoveToActor()/MoveToLocation():寻路移动。
这也是"身体与大脑分离"设计的最大受益者:让 AI 接管一个玩家角色,只需 AIController->Possess(Character),角色代码一行不用改。
这里暂时不考虑理解这个AIController,简单了解就可以
三、理解一局游戏是如何运行的
了解了每个类的定义,现在把它们放回一个真实场景中:
场景:玩家启动游戏 → 进入一个对战地图 → 控制角色移动 → 击杀敌人获得分数 → 游戏结束时显示胜负。
1. GameMode
玩家启动游戏、地图加载,GameMode 第一个登场。它像开赛前检查场地的裁判:这场比赛用哪个地图、每位玩家操控什么角色(DefaultPawnClass)、由什么控制器接管(PlayerControllerClass),都是它说了算。
2. Controller 附身 Pawn
玩家连接进来,GameMode 依次生成两样东西:一个 PlayerController 和一个 Character 。然后 PlayerController 对 Character 执行 Possess(附身)------从这一刻起,按键才有了意义。
同时,GameMode 还生成了一份 PlayerState(玩家档案),里面登记着这位玩家的昵称和初始战绩。
3. 按键如何变成移动
玩家按下 W 键,流程是:
- PlayerController 最先收到输入事件;
- 它调用 Character 的移动接口
AddMovementInput(); - CharacterMovementComponent 真正执行移动,并把结果通过网络复制给其他客户端。
注意:Character 自始至终没"决定"过任何事,它只是执行者
4. 数据存储在哪里
玩家击杀一名敌人,数据兵分两路:
- 个人战绩(击杀数 +1)→ 写入 PlayerState。因为战绩属于"这位玩家",且要跟随他直到对局结束;
- 队伍比分 → 写入 GameState。因为比分属于 全局数据 ,且必须同步到所有客户端。
GameMode 此时并不存数据,它只负责裁决:听到击杀事件后,检查胜利条件是否达成。
5. 判断游戏结束
胜利条件达成,*GameMode* 判定比赛结束,广播结束事件。结果经由 *GameState* 同步到每个客户端,最终由 *HUD / UMG* 把"胜利"画面画到每位玩家的屏幕上。
1. 玩家启动游戏
→ GameMode 决定使用哪个地图、哪个 Pawn、哪个 Controller
2. 玩家进入游戏(PostLogin)
→ GameMode 生成 Pawn、PlayerController 和 PlayerState
→ Controller 附身(Possess)Pawn
3. 玩家操作(按 W 键)
→ PlayerController 捕获键盘输入
→ 调用 Pawn 的移动函数(AddMovementInput)
→ CharacterMovementComponent 执行移动,并复制给其他客户端
4. 玩家击杀敌人
→ 更新 PlayerState 中的击杀数(个人战绩)
→ 更新 GameState 中的队伍比分(全局局势)
→ GameMode 检查胜利条件
5. 游戏结束
→ GameMode 判定结束并广播事件
→ GameState 同步结果
→ HUD / UMG 显示胜负界面
玩家按键 → PlayerController(接收)→ Pawn/Character(执行)→ 数据写入 PlayerState(个人)/ GameState(全局)→ GameMode 裁决 → UI 展示
四、生命周期
梳理整个流程,会发现这些类的生命周期是不一样的
| 对象 | 创建者 | 生命周期 |
|---|---|---|
| GameMode | 引擎(关卡加载时) | 随关卡,仅服务器 |
| GameState | GameMode | 随关卡,所有端 |
| PlayerController | GameMode(玩家加入时) | 玩家连接期间 |
| PlayerState | GameMode(玩家加入时) | 整个对局(跨重生) |
| Pawn / Character | GameMode(重生时) | 一次生命,死亡即销毁 |
| HUD | PlayerController | 随本地玩家 |