大家好,欢迎来到IT知识分享网。
帧同步和状态同步区别
TCP | UDP | |
---|---|---|
连接 | 面向连接 | 无连接 |
可靠性 | 可靠,有序 | 不可靠,丢包,无序 |
数据 | 多个数据包转成字节流,有粘包问题 | 每个数据包视为一个独立的报文进行传输,没有粘包问题 |
流量 | 控制 | 手动 |
速度 | 慢 | 快 |
状态同步一般使用 TCP,帧同步一般使用 UDP
帧同步需要保证计算的一致性,包括随机数,容器遍历,浮点数,时间
随机数算法
为了保证每个客户端的表现相同,需要使用相同的随机数种子,比如以帧号为种子,还需要一个随机数容器,里面的随机数是固定的,这样相同的容器,相同的种子就可以得到相同的结果。
逻辑严格排序
经常会有需要排序的列表或者数组,比如攻击距离自己最近的敌人,这时候就需要将身边的敌人进行距离排序,一般来说只要排序距离就行了,但是如果出现两个敌人距离一样的时候,就会导致在不同的机器上选择的敌人是不同的。所以排序一定要排到id为止,才能避免出现条件相同顺序不同的问题。
浮点数的精度问题
定点数
定点数:把整数部分和小数部分拆分开来,都用整数的形式表示,小数点位置固定,缺点是占用空间更大。可以直接使用网上的定点数库,也可以使用自定义的定点数
实现自定义定点数
using System; /// <summary> /// 自定义64位定点数 /// </summary> [Serializable] public struct Fixed64 : IEquatable<Fixed64>, IComparable, IComparable<Fixed64> {
public long value; //小数部分位数 private const int FRACTIONALBITS = 12; private const long ONE = 1L << FRACTIONALBITS; public static Fixed64 Zero = new Fixed64(0); /// <summary> /// ֱ直接对value赋值 /// </summary> Fixed64(long value) {
this.value = value; } /// <summary> /// 传入具体数字的构造函数 /// </summary> public Fixed64(int value) {
this.value = value * ONE; } /// <summary> /// 重载运算符 /// </summary> public static Fixed64 operator +(Fixed64 a, Fixed64 b) {
return new Fixed64(a.value + b.value); } public static Fixed64 operator -(Fixed64 a,Fixed64 b) {
return new Fixed64(a.value - b.value); } public static Fixed64 operator*(Fixed64 a,Fixed64 b) {
//直接相乘后面会多出0,所以这里要右移 return new Fixed64((a.value >> FRACTIONALBITS) * b.value); } public static Fixed64 operator/(Fixed64 a,Fixed64 b) {
return new Fixed64((a.value << FRACTIONALBITS) / b.value); } public static bool operator ==(Fixed64 a,Fixed64 b) {
return a.value == b.value; } public static bool operator !=(Fixed64 a,Fixed64 b) {
return !(a == b); } public static bool operator>(Fixed64 a,Fixed64 b) {
return a.value > b.value; } public static bool operator <(Fixed64 a, Fixed64 b) {
return a.value < b.value; } public static bool operator >=(Fixed64 a, Fixed64 b) {
return a.value >= b.value; } public static bool operator <=(Fixed64 a, Fixed64 b) {
return a.value <= b.value; } /// <summary> /// 显式强制类型转换,Fixed64转换为long类型 /// </summary> public static explicit operator long(Fixed64 value) {
return value.value >> FRACTIONALBITS; } public static explicit operator Fixed64(long value) {
return new Fixed64(value); } public static explicit operator float(Fixed64 value) {
return (float)value.value / ONE; } public static explicit operator Fixed64(float value) {
return new Fixed64((long)(value * ONE)); } public int CompareTo(object obj) {
return value.CompareTo(obj); } public int CompareTo(Fixed64 other) {
return value.CompareTo(other.value); } public bool Equals(Fixed64 other) {
return value == other.value; } public override int GetHashCode() {
return value.GetHashCode(); } public override bool Equals(object obj) {
return obj is Fixed64 && ((Fixed64)obj).value == value; } public override string ToString() {
return ((float)this).ToString(); } }
实现自定义定点数向量
using System; /// <summary> /// 自定义定点数三维向量 /// </summary> public struct Fixed64Vector3 : IEquatable<Fixed64Vector3> {
public Fixed64 x; public Fixed64 y; public Fixed64 z; public Fixed64Vector3(Fixed64 x, Fixed64 y, Fixed64 z) {
this.x = x; this.y = y; this.z = z; } public Fixed64 this[int index] {
get {
if (index == 0) return x; else if (index == 1) return y; else return z; } set {
if (index == 0) x = value; else if (index == 1) y = value; else y = value; } } public static Fixed64Vector3 Zero {
get {
return new Fixed64Vector3(Fixed64.Zero, Fixed64.Zero, Fixed64.Zero); } } public static Fixed64Vector3 operator +(Fixed64Vector3 a, Fixed64Vector3 b) {
Fixed64 x = a.x + b.x; Fixed64 y = a.y + b.y; Fixed64 z = a.z + b.z; return new Fixed64Vector3(x, y, z); } public static Fixed64Vector3 operator -(Fixed64Vector3 a, Fixed64Vector3 b) {
Fixed64 x = a.x - b.x; Fixed64 y = a.y - b.y; Fixed64 z = a.z - b.z; return new Fixed64Vector3(x, y, z); } public static Fixed64Vector3 operator *(Fixed64 d, Fixed64Vector3 a) {
Fixed64 x = a.x * d; Fixed64 y = a.y * d; Fixed64 z = a.z * d; return new Fixed64Vector3(x, y, z); } public static Fixed64Vector3 operator *(Fixed64Vector3 a, Fixed64 d) {
Fixed64 x = a.x * d; Fixed64 y = a.y * d; Fixed64 z = a.z * d; return new Fixed64Vector3(x, y, z); } public static Fixed64Vector3 operator /(Fixed64Vector3 a, Fixed64 d) {
Fixed64 x = a.x / d; Fixed64 y = a.y / d; Fixed64 z = a.z / d; return new Fixed64Vector3(x, y, z); } public static bool operator ==(Fixed64Vector3 lhs, Fixed64Vector3 rhs) {
return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z; } public static bool operator !=(Fixed64Vector3 lhs, Fixed64Vector3 rhs) {
return lhs.x != rhs.x || lhs.y != rhs.y || lhs.z != rhs.z; } /// <summary> /// 进行左移和右移是为了增加哈希值的混淆性和分布性,参考Vector3中的写法 /// </summary> public override int GetHashCode() {
return x.GetHashCode() ^ (y.GetHashCode() << 2) ^ (z.GetHashCode() >> 2); } public override bool Equals(object obj) {
return ((Fixed64Vector3)obj) == this; } public override string ToString() {
return string.Format("x:{0} y:{1} z:{2}", x, y, z); } public bool Equals(Fixed64Vector3 other) {
return this == other; } }
查表法
查表计算是一种通过预先计算并存储特定值的方法,来避免实时计算中可能出现的精度问题。例如,在计算三角函数等复杂函数时,可以预先将度数对应的值存储在数据表中,然后在需要时直接查表获取结果。
放大截断法
放大截断法是一种使用整数替代浮点数进行计算的方法。首先确认放大因子(如1000),将浮点数乘以放大因子后转换为整数,进行计算,最后再将结果除以放大因子转换回浮点数。这种方法通过舍去小数部分来减少精度损失,但需要注意选择合适的放大因子以避免溢出。
帧同步流程
游戏中按固定的时间间隔更新,在逻辑帧中计算角色位置,旋转,碰撞,有碰撞就修正位置,计算子弹的移动,修正和销毁,然后在渲染帧中进行同步,保证逻辑和渲染分离
客户端-服务端架构:每个客户端把自己的一个或多个操作发给服务端,服务端把这些操作应用到游戏状态中,并将结果发给所有客户端,保持一致性,上图中方框表示服务端
- 严格帧同步:每个关键帧只有当服务器集齐了所有玩家的操作指令,才可以进行转发,进入下一个关键帧,否则就要等待最慢的玩家。
上图表示严格帧同步流程,服务器和客户端约定每5帧同步一次,这里每一帧的时间间隔由服务器决定,UPDATE 0表示服务器发的第0帧数据,CTRL 0表示客户端发的第0帧操作,服务器在第5帧开始前收到了客户端A,B的数据,进行打包再转发给A,B。服务端在第10帧开始时没有收到所有客户端的数据,开始等待,直到收到所有客户端的数据。 - 乐观帧同步:服务器定时广播操作指令,而不必等待慢的客户端,如果转发时某个客户端没有提交帧数据,认为进行了空操作。
对抗网络延迟
1.前向冗余纠错
在发送第N帧数据时,同时包含N-1到N-k(k为动态调整的冗余帧数)帧的数据。这样,即使部分帧丢失,接收端也能通过接收到的冗余数据重构出完整的帧序列。冗余帧可以动态调整,网络不好的时候多发几帧,好的时候少发几帧。当客户端发现有丢帧的情况要发送重传请求,冗余帧可以减少重传次数。
2.预表现
3.预测,回滚,追帧
录像回放
保存每一帧数据,使用 Update 来播放,通过 Time.timeScale 来调整播放速率
短线重连
重新进入游戏后,检测对局是否存在,获取缺失的帧数据,从第一帧开始追帧
反外挂
服务器收集数据后,运行部分客户端逻辑,作为权威,比如服务器计算玩家移动和物理碰撞
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/125653.html