上篇讲到客户端的同步策略,也就是Client to Server的发包策略。那么这篇说一下Server to Client的网络抖动情况下优化本地表现。
延迟实际并不会造成客户端表现障碍,但是网络抖动会,我们优化的点在于不要让用户看到模型坐标拉扯,让表现过度自然。处理的过程中尽量追平服务器计算的实时位置。

这里讲一下我的思路,玩家每次收到的Pack结构如下:position是此刻当前物体处在位置,angle为运动方向,speed为0则物体进入idle。

1
2
3
4
5
6
public class PlayerStatePack
{
public float speed;
public Vector3 position;
public int angle_deg;
}

下面是模拟服务端延迟的实现,fluctuation用来模拟网络抖动:

currentTime = Time.time + Ping / 1000f 2 + Random.Range(-fluctuation 2/1000f , fluctuation * 2/1000f );

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void Update()
{
for (int i = 0; i < packLst.Count; i++)
{
if (packLst[i].BeSend)
continue;
if (packLst[i].currentTime <= Time.time)
{
packLst[i].BeSend = true;
ReceivePack?.Invoke(packLst[i]);
}
}
}

客户端接收消息实现如下:通过ReceivePack函数订阅模拟服务器下发的Pack, 在该函数内做一个向量的减法,获取当前客户端所处与服务器同步过来的位置之间的误差,
有了此向量,那后面就可以通过插值逐渐修正到一个趋近正确的位置,一定程度上抹平网络波动引起的误差。
在 ApplyPoint 函数我做了一个当前误差的差值与角度差值,这样效果会好一些。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
public void OnMove(float passTime,float step,Vector3 pos,float angle)
{
...
}
private void ReceivePack(PlayerStatePack item)
{
Debug.Log("其他玩家收到同步包");
modifyOffset = item.position - transform.position;
localPositon = transform.position;
localAnlge = transform.eulerAngles.y;
...
}
public float timeTakenDuringLerp = .2f;
private void Update()
{
....
var passTime = Time.time - currentPack.CurrentTime;
OnMove(passTime,step,pos,angle);
ApplyPoint(passTime);
}
private void ApplyPoint(float passTime)
{
float percentageComplete = passTime / timeTakenDuringLerp;
if(percentageComplete >= 1.0f)
{
transform.position = RuntimePos + modifyOffset;
return;
}
var offset = Vector3.Lerp(Vector3.zero, modifyOffset,percentageComplete);
transform.position = RuntimePos + offset;
if(percentageComplete*2 >= 1.0f)
{
return;
}
var yoffset = Mathf.LerpAngle(localAnlge, currentPack.angle_deg,percentageComplete*2);
transform.eulerAngles = new Vector3(transform.transform.eulerAngles.x,yoffset,transform.transform.eulerAngles.z);
}

结语

还有其他方式优化表现,对我来说目前这种方式表现已经足够便没有尝试,下面贴了条链接其中有讲到 立方样条插值,这种方式常见于各种导航软件比较复杂。如果是
赛车游戏我倒是非常推荐用这种预测模式降低网络抖动造成的拉扯现象。

参考链接

网络游戏的移动同步(三)平滑算法