[程式] 在UE4多人游戏环境变更角色移动速度 (一)

楼主: yekdniw (yekdniw)   2020-07-29 10:33:50
网页版
https://yekdniwue.blogspot.com/2020/07/CustomMove1.html
简介
在还没有任何网络延迟处理的经验下,
很容易做出遇到延迟就会产生问题的功能。
例如说做一个缓速功能,只要遇到网络发生延迟,玩家就会感受到拉回。
在过去的专案有幸遇到前辈指教,在UE4做了一点验证,本篇算是学习的成果。
本系列我将会以一个实际的UE4 4.23案例做说明。
要实作的功能是:
玩家按下某一个键后,会进入移动射击状态(假设名字定义为Strafe),
放开按键后离开移动射击状态(UnStrafe)。
Strafe时,移动速度会减慢一半,UnStrafe后移动速度回到正常。
然后以新手的角度实作,接着提到如何模拟网络延迟,
验证新手的实作方法有问题,以及问题在哪边。
再来就是提出正确的解法。这个解法需要以C++继承UE4内建的
CharacterMovementComponent,并复写部分函式。
这样的做法服务器端就会接受玩家的指令,
如同玩家送出的移动一样,不会造成拉回。
本系列目标是能够介绍一系列的流程,包含如何开发移动减速功能,
如何验证网络延迟,结束于改善网络延迟移动的问题。
读者可能需要知道什么是RPC,文章前面提的部份是BP专案就能做到。
后面要改善移动的时候才需要C++专案,有需求的人可以参考部份就好。
本篇不会提到改善网络延迟移动的做法,该作法会放到下一篇。
新手做法(以RPC)
本节会介绍我当初在错误的观念做出来的做法以及结果。
虽然可能有人会想说为什么要介绍错误的观念?
主要是我认为并非所有人有网络基础。
所以有必要先用比较浅显易懂的方式,
介绍这个需求的功能,把基础建设先解释完。
然后接下来我只要专注在介绍修正错误的部份,
避免本篇文章的阅读难度一开始就过高。
首先在玩家的PlayerCharacter要新增按钮接收的事件,
在这边我用input action strafe定义了输入事件strafe,
触发的话就进入strafe,放开事件就离开strafe。
在多人连线的架构,直觉的作法就是client收到按键事件后,
玩家角色端先套用Strafe处理,然后透过reliable RPC发送事件给server。
server收到事件后作一样的处理。
所以我们要新增两个事件,一个是PerformStrafe ,
根据现在事件是Strafe还是UnStrafe,
作移动速度的变更,如图所示。
[图]
另一个则是Client,通知Server的reliable RPC 事件,
命名为ServerPerformStrafe,里面就是Server呼叫PerformStrafe来更改速度。
如图所示。
[图]
最后就是事件Input Action Strafe,里面要接上PerformStrafe还有
ServerPerformStrafe事件。
如图所示。
[图]
测试环境设定
本章会介绍如何模拟网络延迟,并验证前一章提的做法是有问题,问题会发生在哪边。
为了客观验证,我们需要使用dedicated server+client这样的环境做测试。
千万要记得如果环境设定成单机,或是自己就是Listen Server,
那不管怎么调整都是测不出来的。
所以要测试网络延迟,只有两种对象可以达到。
1. dedicated server / client 架构的任一client
2. listen server / client 架构下server以外的client。
在UE4,如果想在Editor的环境验证,还需要多设定以下几项:
[图]
[图]
最重要的就是Run Dedicated server,以及取消single process,
并设为Play As Client。
这样server跟client才会分开成两只独立的程式执行。同一个process等于没办法模拟延
迟,所以很重要。通常我要模拟延迟的之前,会使用StandaloneGame做测试。
也因为开启的时候是开两个程式起来,所以如果要修改BP,请记得两个开起来的程式都要
先关掉,以免跳错或得到不预期的结果。
实际测试与网络延迟模拟
先前的设定都好了之后就可以点Play执行。
这时候就会跳出两个视窗,一个是server,一个是client。
如图所示,左上的图是client,右下方的是dedicated server的讯息视窗。
[图]
这时候我们开始移动,并频繁的操作Strafe,UnStrafe,会发现没有问题。
这是正常的,因为毕竟两个程式还是在同一台电脑,所以不会有延迟。
就算我们将环境架在内网,大概也不会差太多。
所以我们必须先学会如何模拟网络的延迟。
取得网络延迟资讯
在开始模拟延迟之前,先介绍如何在UE4知道网络有延迟。
在PlayerState里面有个变量是Ping
Engine/Source/Runtime/Engine/Classes/GameFramework/PlayerState.h
这个变量是Server计算出来同步给所有玩家的值,但是因为有处理过,
所以不是真正的数值。
坦白说我没去追查这个值跟真正的值的换算公式,
我只知道因为这个值要同步给玩家,所以有做过处理,
以避免每个frame可能都在变动的数值一直传输给玩家。
不过,Ping这个变量是UPROPERTY,所以我们可以使用console command
displayall playerstate ping
来获得结果,一行程式码都不用写。
在我的环境开起来Ping显示的是个位数左右,印象中如果是SingleProcess的话,
应该会是0。
所以如果不在意精准的话,大概就是0~个位数就是几乎无延迟。
如果想获得比较精准的值,请参考PlayerState内的ExactPing。
但是这个值就必须要到C++处理了。
模拟网络延迟
在UE4内有一系列的console command可以模拟网络异常的状况。
1. Net PktLag=[延迟ms]
2. Net PktOrder=[]
3. Net PktLoss=[掉包机率]
4. Net PktVariance=[延迟变量]
5. Net PktDup=[重送机率]
这些参数的意义 都可以在
Engine/Source/Runtime/Engine/Classes/Engine/NetDriver.h
里面查到
最重要的当然就是模拟延迟,例如输入
Net PktLag=500
就可以模拟延迟500 ms的结果。
不过我有查到,UE4的模拟延迟只能延迟送出,无法模拟延迟接收。
如果Client延迟500ms,指的是他送资料给server会慢500ms。
如果Server延迟200ms,指的是Server会延迟200ms才送给"所有人"。
所以如果想做
Server送到Client1延迟100ms,
Server送到Client2延迟200ms。
这种更详细的测试,只用UE4内建不行,这时候可以考虑使用Clumsy
(https://jagt.github.io/clumsy/)
来处理。
新手作法验证与检讨
开启Net PktLag=500之后,我们再来测试之前的作法。这时候就会发现只要频繁的
Strafe/UnStrafe切换,画面就会有明显异常发生,玩家的移动将不再感觉到顺畅。
详情可以看影片:
[影片]
为什么速度切换不再顺畅?
问题就出在当我们按下减速的时候,Client端已经先行减速,
这时候Server还是以原来的速度前进,直到500ms后Server收到RPC,
才会把该Player减速。
在这段时间Client与Server的误差会越来越大,
大到一定程度的时候Client就会矫正自己的位置,
因为最后正确的位置还是要以Server为主。
这个矫正就会使玩家感受到不顺畅,也就是前面提到的拉回。
结论
本篇以Blueprint搭配RPC来制作角色减速的功能,然后介绍如何在UE4编辑器内建立正确
的多人游戏测试环境。
为了验证正确性,我说明如何验证网络延迟,如何模拟网络延迟等UE4内建的功能。最后
则是对这个错误的做法做基本的分析与检讨。
在本系列的下一篇,就要介绍如何不拉回的做法了。
作者: sampp1213205 (佛朗Sam哥)   2020-07-29 10:50:00
先推再看
作者: metallican (钢铁人)   2020-07-29 18:48:00
推爆
作者: coolrobin (泳圈)   2020-07-29 22:13:00
坐等下一篇
作者: wangm4a1 (水兵)   2020-07-30 12:39:00
作者: nyc0125 (乃)   2020-07-30 18:05:00
楼主乐于分享一生平安
作者: ConSeR (草履重根)   2020-07-31 14:21:00
感谢 很受用

Links booklink

Contact Us: admin [ a t ] ucptt.com