我们正在开发一个相当简单的2D多人平台射击游戏,我们遇到了为世界实体(玩家,子弹等)的状态构建UDP缓冲区的一些问题。目前,我们发送每个游戏实体的位置(x,y)及其x和y速度30次/秒。只要没有数据包丢失,这给我们提供了相当流畅的体验。但是,如果数据包丢失,我们就会出现抖动。为避免这种情况,我们希望在最后的已知位置之间使用插值。
我们正在使用Libgdx进行游戏开发,我们的网络服务是使用kryonet库完成的。
问题是:
如何构建简单可靠的UDP缓冲区?我们尝试使用发送时间和到达时间之间的时间差来延迟接收端的数据包执行50ms。但要么我们做错了,要么插值本身就有缺陷,因为抖动变得更糟。
如何正确地线性插入旅行轨迹?
以下代码是我们的插值方法的片段。
//Called every time a UDP packet has arrived adding it to the queue.
public void addEntityPacket(EntityPacket pkt){
entityStates.add(pkt);
}
//Called each Gdx update (60times/s). Linearly interpolates (lerp)
//the entity with the next entityState in queue using getAlpha().
public void updateEntityState(){
if (entityStates.size > 0) {
EntityPacket pkt = entityStates.pop();
currentPos.set(body.getPosition()); // sets currentPos to the entitys current position.
targetPos.set(pkt.xp, pkt.yp); // sets the targeted to the next state position retrieved from the queue.
interpolatedPos.set(currentPos).lerp(targetPos, getAlpha()); // calculates the linear interpolation using getAlpha().
body.setTransform(interpolatedPos, 0); // Moves the entity to the calculated position
body.setLinearVelocity(pkt.xf, pkt.yf); // Sets the velocity
}
}
//Called when calculating interpolation.
public float getAlpha(){
long now = TimeUtils.millis(); // current time
float alpha = (now - lastUpdateTime) / 30f; // time difference divided by update frequency.
lastUpdateTime = now;
return MathUtils.clamp(alpha, 0f, 1.0f); // We do not want the alpha to be less than 0 or greater than 1 or the interpolation will behave strangely.
}