Appearance
多人联机
如果希望开发多人游戏,应尽早把相关多人功能想好,否则以单人游戏为基础开发多人游戏,会非常困难。
多人游戏类型
同步性 | 会话长度 | 独立开发者友好度 | 虚幻支持度 | |
---|---|---|---|---|
回合制游戏 | 不做要求 | 协商 | 高 | 有限(需自实现) |
基于会话的实时游戏 | 需要 | 协商 | 中 | 高(内置的) |
大型多人在线游戏,持续世界游戏 | 需要 | 永久存在 | 低 | 有限 |
物理层面上的客户端与服务器
有两种:一种是某位玩家的电脑作为主机,其他玩家通过网络服务连入;另一种是所有玩家都通过网络上的某台独立的服务器,然后由该服务器进行运算,并向各个玩家分发游戏中的数据。
关键概念——复制
复制,是指权威服务器将状态数据发送到连接的客户端的过程。即:服务器到客户端的数据传输。
在游戏中,主要使用Actor和Actor派生的类通过UE中的网络连接复制其状态。
注意:UObject 派生的类也可以复制,但必须作为复制的子对象附加到Actor才能恰当复制。
输入与状态
状态,可以视为一种结果、事实。例如血量值、法力值
输入,可以视为状态的触发条件、引发条件。例如:着火或中毒会扣血。
Gameplay框架
游戏规则、玩家输出与控制、相机和用户界面等核心系统。
学习gameplay框架的重点在于,知道虚幻中的类的上下级关系,知道每个关键的类都承担什么样的作用,知道哪些功能应该放到服务器,哪些应该放到本地。
Actor
组成世界的单位,可以互相嵌套,可生成,是网络通信的通道。
并非所有的Actor都必须被看见。也就是可以有Actor只负责逻辑。
Actor派生自Object。
Object是所有类的基类
Component
为Actor提供能力,一般与业务逻辑无关,可跨游戏使用。
有ActorComponent和SceneComponent之分。
SceneComponent能够修改坐标、缩放等
Pawn
棋子,派生自Actor,可被控制。
主要用于作为可动角色的承载。例如动物、怪物、可移动机械(无人机之类)。
Character
类人型角色专用的。一般是双脚、直立行走。
Controller
控制器,用于控制Pawn,或者其他可由玩家进行操控的Actor或Character。
PlayerState
玩家状态。各种需要在服务端进行逻辑运算的,各种与玩家角色相关的状态。
例如,血量、名称、样貌、负重等等
Level与World
Level,关卡。一个游戏可以有很多关卡,但是只能有一个世界(World)。
有持久性关卡,流式关卡之分。持久性关卡中存放那些长久使用的,流式关卡中存放的是随用随弃的内容。
ULevel UWorld
GameState
游戏状态。例如开始、结束等。主要存储的是玩家角色所处的游戏世界的状态、属性等。
属于AInfo下
AInfo下有AGameModeBase和AGameStateBase。它们俩又分别有AGameMode和AGameState。
AGameState属于AGameMode,AGameMode属于UWorld和ULevel的属性。
注意:gamemodebase类的功能没有gamemode多
GameInstance
跨关卡的逻辑。整个游戏的实例。
UGameEngine派生UGameInstance派生FWorldContext派生UWorld。
UGameInstance
SaveGame
游戏存档。序列化保存到磁盘空间。
USaveGame派生UMyCustomSaveGame。
Subsystem
子系统。自动实例化对象,托管生命周期
5类生命周期(引擎内部对象)
- UEngineSubsystem UEngine* GEngine
- UEditorSubsystem UEditorEngine* GEditor
- UGameInstanceSubsystem UGameInstance* GameInstance
- UWorldSubsystem UWorld* World
- ULocalPlayerSubsystem ULocalPlayer* LocalPlayer
Subsystem与OnlineSubsystem是完全不同的概念
USubsystem
多人联机的Gameplay框架
仅服务端中:AGameMode 仅客户端中:AHUD、UMG Widgets
服务器、客户端中:AGameState、APlayerState、APawn 服务器、客户端主机中:APlayerController
关于GetPlayerController()
UGameplayStatics::GetPlayerController(GetWorld(), 0);
在监听服务器上调用返回监听服务器的PlayerController
在客户端上调用,返回客户端的PlayerController
在专用服务器上调用,返回第一个客户端的PlayerController
注意:PlayerIndex的值是给分屏游戏用的。非分屏游戏永远填0
另外需要区分专用服务器(Dedicated Server)和监听服务器(Listen-Server)
专用服务器:
- 不需要客户端的独立服务器
- 与游戏客户端分开运行
- 没有可视部分
- 在游戏中也没有代表他们的角色
监听服务器:
- 是服务器的同时也是客户端
- 始终至少连接一个客户端
- 如果断开连接,服务器将关闭
- 拥有可视部分
Replication
复制,将服务器的信息、数据传递给客户端的行为。参与复制的最基础类是AActor。
类继承于AActor后,它们能够根据需要复制属性
但并不是所有继承于AActor的类都必须复制
标记为复制的Actor在服务器上生成时,也将在所有客户端上生成并复制,但其在客户端上生成时则仅存在于此客户端。
Role与RemoteRole
角色与远程角色。主要区分谁拥有Actor的主控权。
ROLE_Authority,权威 ROLE_SimulatedProxy,模拟,由服务器管理并控制,但是是从其他地方获得的数据 ROLE_AutonomousProxy,自治,受服务器监管,有少量本地控制权力
这个在做判断的时候要带入不同的视角去观察。
角色A | 角色B | 服务端 | |
---|---|---|---|
角色A | 自治 | 模拟 | 权威 |
角色B | 模拟 | 自治 | 权威 |
服务端 | 模拟 | 模拟 |
蓝图中用SwitchHasAuthority和IsServer去判断当前程序在客户端运行还是服务器运行。
RPC - Remote Procedure Calls
远程过程调用,用于调用在另一个实例上的函数
RPC无返回值
规则:
- Run on Server,在Actor的服务器实例上执行
- Run on owning Client,在此Actor的所有者上执行
- Multicast,在此Actor的所有实例上执行
RPC必须从复制Actors调用,即:
服务器调用RPC在客户端执行,只有实际拥有该Actor的Client才能执行该功能;
从Client调用RPC在服务器上执行,则Client必须拥有要调用RPC的Actor。
Multicast RPC中则是:
服务器调用,服务器在本地执行他们,并在所有当前连接的客户端上执行他们
客户端调用,则本地执行,服务器不参与执行
需注意:
RPC标记为Reliable,即操作一定要发送到。
在C++中还可以额外添加验证函数进行Validation(验证)。
蓝图中使用Custom Event(或仅Event)作为RPC的设置对象。