游戏中的帧同步要求的计算一致性——定点数(Fixed Point)

最近做了一款帧同步游戏,其寻路算法采用了RVO算法。但是由于是移动端的游戏。需要在不同的设备上运行,其所有运算必须符合一致性——即所有客户端运算出来的结果必须一致。但是由于浮点数的特性,具有误差,且在不同设备上误差更为明显。因此所有的算法都不能采用浮点数来运算。一般来说,这些游戏内大多采用*1000 再/1000的方式来实现帧同步的计算一致性。

        但是由于RVO算法,是用来寻路的,其中大量的向量运算,其算法复杂度非常高。而向量运算是一个特例。其中比如normalize,是不能放大的——因为放大多少倍最后的结果也只能是(1,0)(0,1)(0,0).还有一些 sin函数 cos函数是没有办法先乘后除的。在这种情况下,采用老式的方式已经非常不便了(大量的临时变量和成员变量你已经记不清哪些放大过哪些是标准值了)。因此,我打算采用定点库。网上的定点数库大多重载不全,而且没有找到跨语言的。。。所以就自己实现了一个。直接上代码(代码是c#的)。
       (其中的sin cos 的实现请参考上一篇文章)
 
 
using System.Collections;
using System;
using System.Globalization;
 
namespace FP
{
public struct FPoint 
{
public static int Fix_Fracbits = 16;
public static FPoint Zero = new FPoint(0);
        internal Int64 m_Bits;
public FPoint(int x)
{
m_Bits = (x<<Fix_Fracbits);
}
public FPoint(float x)
{
m_Bits =(Int64)((x) * (1 << Fix_Fracbits));
//x*(((Int64)(1)<<Fix_Fracbits))
}
public FPoint(Int64 x)
{
m_Bits = ((x) * (1 << Fix_Fracbits));
}
public Int64 GetValue()
{
return m_Bits;
}
//******************* +  **************************
public static FPoint operator +( FPoint p1,  FPoint p2)
{
FPoint tmp ;
tmp.m_Bits = p1.m_Bits + p2.m_Bits;
return tmp;
}
public static FPoint operator +(FPoint p1, int p2)
{
FPoint tmp ;
tmp.m_Bits = p1.m_Bits + (Int64)(p2<<Fix_Fracbits);
return tmp;
}
public static FPoint operator +(int p1, FPoint p2)
{
return p2+p1;
}
public static FPoint operator +(FPoint p1, Int64 p2)
{
FPoint tmp ;
tmp.m_Bits = p1.m_Bits + p2<<Fix_Fracbits;
return tmp;
}
public static FPoint operator +(Int64 p1, FPoint p2)
{
return p2+p1;
}
 
public static FPoint operator +(FPoint p1, float p2)
{
FPoint tmp ;
tmp.m_Bits = p1.m_Bits + (Int64)(p2*(1<<Fix_Fracbits));
return tmp;
}
public static FPoint operator +(float p1, FPoint p2)
{
FPoint tmp = p2 + p1;
return tmp;
}
//*******************  -  **************************
public static FPoint operator -(FPoint p1, FPoint p2)
{
FPoint tmp ;
tmp.m_Bits = p1.m_Bits - p2.m_Bits;
return tmp;
}
 
public static FPoint operator -(FPoint p1, int p2)
{
FPoint tmp ;
tmp.m_Bits = p1.m_Bits - (Int64)(p2<<Fix_Fracbits);
return tmp;
}
 
public static FPoint operator -(int p1, FPoint p2)
{
FPoint tmp ;
tmp.m_Bits = (p1<<Fix_Fracbits) - p2.m_Bits;
return tmp; 
}
public static FPoint operator -(FPoint p1, Int64 p2)
{
FPoint tmp ;
tmp.m_Bits = p1.m_Bits - (p2<<Fix_Fracbits);
return tmp;
}
public static FPoint operator -(Int64 p1, FPoint p2)
{
FPoint tmp;
tmp.m_Bits = (p1<<Fix_Fracbits) - p2.m_Bits;
return tmp; 
}
 
public static FPoint operator -(float p1, FPoint p2)
{
FPoint tmp;
tmp.m_Bits = (Int64)(p1*(1<<Fix_Fracbits)) - p2.m_Bits;
return tmp; 
}
public static FPoint operator -(FPoint p1, float p2)
{
FPoint tmp;
tmp.m_Bits = p1.m_Bits - (Int64)(p2*(1<<Fix_Fracbits));
return tmp; 
}
 
//******************* * **************************
public static FPoint operator *(FPoint p1, FPoint p2)
{
FPoint tmp ;
tmp.m_Bits = ((p1.m_Bits) * (p2.m_Bits)) >> (Fix_Fracbits);
return tmp;
}
 
public static FPoint operator *(int p1, FPoint p2)
{
FPoint tmp ;
tmp.m_Bits = p1 * p2.m_Bits;
return tmp;
}
public static FPoint operator *(FPoint p1, int p2)
{
return p2 * p1;
}
public static FPoint operator *(FPoint p1, float p2)
{
FPoint tmp;
tmp.m_Bits =  (Int64)(p1.m_Bits*p2);
return tmp;
}
public static FPoint operator *(float p1, FPoint p2)
{
FPoint tmp ;
tmp.m_Bits =  (Int64)(p1  * p2.m_Bits);
return tmp;
}
//******************* / **************************
public static FPoint operator / (FPoint p1, FPoint p2)
{
FPoint tmp ;
if(p2 == FPoint.Zero)
{
UnityEngine.Debug.LogError("/0");
tmp.m_Bits = Zero.m_Bits;
}
else
{
tmp.m_Bits = (p1.m_Bits) * (1<<Fix_Fracbits) / (p2.m_Bits); 
}
return tmp;
}
public static FPoint operator / (FPoint p1, int p2)
{
FPoint tmp ;
if(p2 == 0)
{
UnityEngine.Debug.LogError("/0");
tmp.m_Bits = Zero.m_Bits;
}
else
{
tmp.m_Bits = p1.m_Bits/(p2);
}
return tmp;
}
public static FPoint operator /(int p1, FPoint p2)
{
FPoint tmp ;
if(p2 == Zero)
{
UnityEngine.Debug.LogError("/0");
tmp.m_Bits = Zero.m_Bits;
}
else
{
Int64 tmp2 = ((Int64)p1 << Fix_Fracbits << Fix_Fracbits);
tmp.m_Bits = tmp2/(p2.m_Bits);
}
return tmp;
}
public static FPoint operator / (FPoint p1, Int64 p2)
{
FPoint tmp;
if(p2 == 0)
{
UnityEngine.Debug.LogError("/0");
tmp.m_Bits = Zero.m_Bits;
}
else
{
tmp.m_Bits = p1.m_Bits/(p2);
}
return tmp;
}
public static FPoint operator /(Int64 p1, FPoint p2)
{
FPoint tmp;
if(p2 == Zero)
{
UnityEngine.Debug.LogError("/0");
tmp.m_Bits = Zero.m_Bits;
}
else
{
if(p1>Int32.MaxValue ||p1
{
tmp.m_Bits = 0;
return tmp;
}
tmp.m_Bits = (p1<<Fix_Fracbits)/(p2.m_Bits);
}
return tmp;
}
public static FPoint operator /(float p1, FPoint p2)
{
FPoint tmp ;
if(p2 == Zero)
{
UnityEngine.Debug.LogError("/0");
tmp.m_Bits = Zero.m_Bits;
}
else
{
Int64 tmp1 = (Int64)p1 * ((Int64)1 << Fix_Fracbits << Fix_Fracbits);
tmp.m_Bits = (tmp1)/(p2.m_Bits);
}
return tmp;
} 
public static FPoint operator /(FPoint p1, float p2)
{
FPoint tmp;
if(p2>-0.000001f && p2<0.000001f)
{
UnityEngine.Debug.LogError("/0");
tmp.m_Bits = Zero.m_Bits;
}
else
{
tmp.m_Bits = (p1.m_Bits<<Fix_Fracbits)/((Int64)(p2*(1<<Fix_Fracbits)));
}
return tmp;
} 
public static FPoint Sqrt(FPoint p1)
{
FPoint tmp;
Int64 ltmp = p1.m_Bits * (1 << Fix_Fracbits);
tmp.m_Bits = (Int64)Math.Sqrt(ltmp); 
return tmp;
}
public static bool operator >(FPoint p1, FPoint p2)
{
return (p1.m_Bits>p2.m_Bits)?true:false;
}
public static bool operator <(FPoint p1, FPoint p2)
{
return (p1.m_Bits
}
public static bool operator <=(FPoint p1, FPoint p2)
{
return (p1.m_Bits<=p2.m_Bits)?true:false;
}
public static bool operator >=(FPoint p1, FPoint p2)
{
return (p1.m_Bits>=p2.m_Bits)?true:false;
}
public static bool operator !=(FPoint p1, FPoint p2)
{
return (p1.m_Bits!=p2.m_Bits)?true:false;
}
public static bool operator ==(FPoint p1, FPoint p2)
{
return (p1.m_Bits==p2.m_Bits)?true:false;
}
 
public static bool Equals(FPoint p1, FPoint p2)
{
return (p1.m_Bits==p2.m_Bits)?true:false;
}
 
public bool Equals(FPoint right)
{
if(m_Bits == right.m_Bits)
{
return true;
}
return false;
}
 
public static bool operator >(FPoint p1, float p2)
{
return (p1.m_Bits>(p2*(1<<Fix_Fracbits)))?true:false;
}
public static bool operator <(FPoint p1, float p2)
{
return (p1.m_Bits<<Fix_Fracbits))?true:false;
}
public static bool operator <=(FPoint p1, float p2)
{
return (p1.m_Bits<=p2*(1<<Fix_Fracbits))?true:false;
}
public static bool operator >=(FPoint p1, float p2)
{
return (p1.m_Bits>=p2*(1<<Fix_Fracbits))?true:false;
}
public static bool operator !=(FPoint p1, float p2)
{
return (p1.m_Bits!=p2*(1<<Fix_Fracbits))?true:false;
}
public static bool operator ==(FPoint p1, float p2)
{
return (p1.m_Bits==p2*(1<<Fix_Fracbits))?true:false;
}
 
public static FPoint Cos (FPoint p1)
{
            return FP.TrigonometricFunction.Cos(p1);
}
public static FPoint Sin (FPoint p1)
{
            return FP.TrigonometricFunction.Sin(p1);
}
 
public static FPoint Max()
{
FPoint tmp ;
tmp.m_Bits = Int64.MaxValue;
return tmp;
}
 
public static FPoint Max(FPoint p1 ,FPoint p2)
{
return p1.m_Bits>p2.m_Bits?p1:p2;
}
public static FPoint Min(FPoint p1 ,FPoint p2)
{
return p1.m_Bits
}
 
public static FPoint Precision()
{
FPoint tmp ;
tmp.m_Bits = 1;
return tmp;
}
 
public static FPoint MaxValue()
{
FPoint tmp ;
tmp.m_Bits = Int64.MaxValue;
return tmp;
}
public static FPoint Abs(FPoint P1)
{
FPoint tmp ;
tmp.m_Bits = Math.Abs (P1.m_Bits);
return tmp;
}
public static FPoint operator -(FPoint p1)
{
FPoint tmp ;
tmp.m_Bits = -p1.m_Bits;
return tmp;
}
 
public float ToFloat()
{
return m_Bits/(float)(1<<Fix_Fracbits);
}
 
        public int ToInt()
        {
            return (int)(m_Bits >> (Fix_Fracbits));
        }
public string ToString()
{
double tmp = (double)m_Bits/(double)(1<<Fix_Fracbits);
return tmp.ToString();
}
}
}

 

posted on 2018-09-29 00:16  &大飞  阅读(1712)  评论(0编辑  收藏  举报

导航