本
文
摘
要
1. 前言
刚接触UE4的同步机制感觉功能挺强大的,变量同步、RPC都无缝支持,但是却不知道怎么正确使用这些机制来开发游戏,什么时候客户端调用服务器,什么时候从服务器调用客户端,哪些代码在客户端写,哪些代码在服务器写。
2. 正文
首先应该明确游戏应该是数据安全的,原则上客户端不能直接修改任何数据,而客户端主要向 服务器上传玩家的输入,然后服务器处理逻辑,逻辑处理结束后让客户端播放效果。
例如跳跃功能的开发,客户端应该监听跳跃键"Space", 然后通过RPC调用服务器跳跃函数,服务器让Actor跳跃,然后RPC所有客户端让这个actor播放跳跃的动画 (跳跃导致actor会通过移动组件同步到客户端)。
代码如下:
UCLASS() class Game_API ABasePlayer : public ACharacter { GENERATED_BODY() // ... 省略代码 ... public: // 按键被按下绑定此函数 void Input_Jump() { Server_Jump(); } UFUNCTION(Server, Reliable) void Server_Jump(); void Server_Jump_Implementation() { if(CanJump()) { Client_JumpEffect(); } } UFUNCTION(NetMulticast, Reliable) void Client_JumpEffect(); void Client_JumpEffect_Implementation() { Jump(); PlayAnimMontage(JumpAnimMontage, 1.0); } }最理想情况下应该像上述代码那样做,但是实际做起来可能会发现网络不好的情况下,延迟可能会比较高,所以我们可能在客户端可以在 跳跃键按下时立即播放跳跃的效果,并同时rpc后台,但是需要注意的是客户端应该缓存足够的状态以判断客户端是否应该跳跃。
另外,还需要注意一下rpc的频率,比如手持机枪的射击操作,如果每次射击都调用rpc的话,0.1射速的武器 一秒可能就要调用10次rpc函数,我认为这个频率是不可以接受的,我们可以按下射击键的时候rpc服务端通知服务端开始射击,松开射击键时rpc服务端通知停止射击,这样能有效减少rpc次数。
射击的代码:
UCLASS() class Game_API ABasePlayer : public ACharacter { GENERATED_BODY() // ... 省略代码 ... public: // 按键被按下绑定此函数 bool IsFireKeyPressed {false} float FireTime = 0.0f; void Input_StartFire() { Server_StartFire(); } void Input_EndFire() { Server_EndFire(); } UFUNCTION(Server, Reliable) void Server_StartFire(); void Server_StartFire_Implementation() { IsFireKeyPressed = true; } UFUNCTION(Server, Reliable) void Server_EndFire(); void Server_EndFire_Implementation() { IsFireKeyPressed = false; } void Tick(float DeltaTime) { // 如果是在服务器 if (HasAuthority()) { FireTime -= DeltaTime; if (FireTime < 0) FireTime = 0; if (IsFireKeyPressed ) { if (FireTime == 0.0f) { // 服务器射击逻辑 // RPC客户端播放射击的效果 } } } } }