航位推算需要一组变量来运行——称为运动状态——通常包含给定对象的位置、速度、加速度、方向和角速度。如果您只是在寻找位置,您可以选择忽略方向和角速度。如果您想预测方向和位置,请发表评论,我会更新我的答案。
网络游戏的标准航位推算算法如下所示:
上述变量描述如下:
P t:估计的位置。输出
P O : 对象最近一次的位置更新
V O : 物体最近的速度更新
A O : 对象最近的加速度更新
T:当前时间和上次更新时间戳之间经过的秒数- 不是收到数据包的时间。
这可用于移动对象,直到从服务器接收到更新。然后,您有两个运动学状态:估计位置(上述算法的最新输出)和刚刚收到的实际位置。实际混合这两种状态可能很困难。
一种方法是在两种状态之间创建一条线,甚至更好,一条曲线,例如Bézier 样条 Catmull-Rom 样条和Hermite 曲线(其他方法的一个很好的列表在这里),同时仍将旧方向投影到未来。所以,继续使用旧状态,直到你得到一个新状态——当你正在混合的状态变成旧状态时。
另一种技术是使用投影速度混合,它是两个投影的混合——最后已知状态和当前状态——其中当前渲染位置是给定时间内最后已知速度和当前速度的混合。
该网页引用了《Game Engine Gems 2》一书,是航位推算的金矿:
网络游戏的可信航位推算
编辑:以上所有内容仅适用于客户端在未获得更新时应采取的行动。至于“什么时候应该从服务器向客户端发送消息”,Valve 说好的服务器应该以大约 15 毫秒的间隔发送更新,大约每秒 66.6 次。
注意:“ Valve 说”链接实际上也有一些很好的网络提示,使用 Source Multiplayer Networking 作为媒介。如果你有时间,请检查一下。
编辑 2(代码更新!):
以下是我在 C++/DirectX 环境中实现这种算法的方法:
struct kinematicState
{
D3DXVECTOR3 position;
D3DXVECTOR3 velocity;
D3DXVECTOR3 acceleration;
};
void PredictPosition(kinematicState *old, kinematicState *prediction, float elapsedSeconds)
{
prediction->position = old->position + (old->velocity * elapsedSeconds) + (0.5 * old->acceleration * (elapsedSeconds * elapsedSeconds));`
}
kinematicState *BlendKinematicStateLinear(kinematicState *olStated, kinematicState *newState, float percentageToNew)
{
//Explanation of percentateToNew:
//A value of 0.0 will return the exact same state as "oldState",
//A value of 1.0 will return the exact same state as "newState",
//A value of 0.5 will return a state with data exactly in the middle of that of "old" and "new".
//Its value should never be outside of [0, 1].
kinematicState *final = new kinematicState();
//Many other interpolation algorithms would create a smoother blend,
//But this is just a linear interpolation to keep it simple.
//Implementation of a different algorithm should be straightforward.
//I suggest starting with Catmull-Rom splines.
float percentageToOld = 1.0 - percentageToNew;
final->position = (percentageToOld * oldState->position) + (percentageToNew * new-State>position);
final->velocity = (percentageToOld * oldState->velocity) + (percentageToNew * newState->velocity);
final->acceleration = (percentageToOld * oldState->acceleration) + (percentageToNew * newState->acceleration);
return final;
}
祝你好运,呃,如果你碰巧在游戏中赚了几百万,试着把我放在学分中;)