我正在制作一个 Unity 多人游戏,我想将 Y 旋转轴从发送整个四元数压缩到只发送一个字节。
我的问题是,是否有可能以更......适当的方式进行第三次压缩尝试,或者我的潜在解决方案是我唯一可以实现的?
答案 0 :(得分:3)
我不会声称您总共节省了 15 个字节^^
如果无论如何您只需要一个旋转组件,那么同步单个浮点数(4 个字节)的第一步似乎非常明显;)
我还想说,超出这个范围听起来有点像不必要的微优化。
增量同步非常聪明,乍一看是从 4 个字节到 2 个字节的 100% 改进。
但是
它也很容易出错,如果只有一个传输失败,可能会不同步。
这当然会将精度降低到 1 度整数步长,而不是完整的 float
值。
老实说,我会坚持使用 4 个字节,只是为了稳定性和精度。
使用 2 个字节,您实际上可以做得比尝试更好!
为什么仅仅为了值的符号而浪费整个字节?
使用 short
您只需要将 -180
到 180
的浮点范围映射到 -32768
到 32767
范围。
发送
// your delta between -180 and 180
float actualAngleDelta;
var shortAngleDelta = (short)Mathf.RondToInt(actualAngleDelta / 180f * shortMaxValue);
var sendBytes = BitConverter.GetBytes(shortAngleDelta);
接收
short shortAngleDelta = BitConverter.ToInt16(receivedBytes);
float actualAngleDelta = (float) shortAngleDelta / (float)short.MaxValue * 360f;
但老实说,你不应该同步增量而是同步实际值。
所以,使用 ushort
!
它涵盖了从 0
到 65535
的值,因此只需在其上映射可能的 360 度。当然你会失去一点精度,但不会下降到全度;)
// A value between 0 and 360
float actualAngle;
ushort ushortAngle = (ushort) Mathf.RoundToInt((actualAngle % 360f) / 360f * ushort.MaxValue);
byte[] sendBytes = BitConverter.GetBytes(ushortAngle);
接收
ushort ushortAngle = BitConverter.ToUInt16(receivedBytes, 0);
float actualAngle = (float)ushortAngle / (float)ushort.MaxValue * 360f;
两者都保持低至约 0.0055
(= 360/65535) 度的精度!
如果您仍然可以选择较低的精度,那么您可以完全幻想并说您不会以度为单位同步每个精确的旋转角度,而是将圆划分为 256 步而不是 360 度。
然后,您可以将增量映射到较小粒度的“度”角,并且可以在单个字节中覆盖整个圆:
发送
byte sendByte = (byte)Mathf.RoundToInt((actualAngle % 360f) / 360f * (float)byte.MaxValue);
收到
float actualAngle = receivedByte / (float)byte.MaxValue * 360f;
其精度约为 1.4
度。
但老实说,所有这些来回计算真的值得节省 2/3 字节吗?