首先,我正在尝试使用Three.js制作“简单”的3D游戏,并在将来使用一些网络框架使其成为多人游戏,因为我计划在将来做网络部分,因此我做了一些搜索并且发现大多数“动作”游戏都使用基于“滴答”的游戏循环来同步客户端和服务器,然后在滴答之间进行插值以使其顺畅。
我已经有了一些滴答(处理输入,更新,绘制)功能的“工作”代码,我想知道的是我的实现是否正确,以及该“确定性”循环应该如何工作(假设我的实现)在正常工作时,当我增加“报价”速度时,游戏会变得更快(更新功能运行了多次),对吗?
this.loops = 0;
this.tick_rate = 20;
this.skip_ticks = 1000 / this.tick_rate;
this.max_frame_skip = 10;
this.next_game_tick = performance.now();
代码的第一部分在Game类的构造函数中
Game.prototype.run = function () {
this.handle_input();
this.loops = 0;
while (performance.now() > this.next_game_tick && this.loops < this.max_frame_skip){
this.up_stats.update();
this.update();
this.next_game_tick += this.skip_ticks;
this.loops++;
}
this.draw();
//monitor performance
this.stats.update();
//next update
requestAnimationFrame(this.run.bind(this));
};
完整代码位于:https://github.com/derezzedex/first_three_js/blob/master/js/game/main.js
答案 0 :(得分:0)
这对我来说似乎很合理,过去我也使用过类似的模式。
构建同步模拟是一个巨大的话题,但是您拥有的是一个很好的起点,并且可能取决于游戏的复杂性。
编辑:更多细节...
是的,它的工作原理相同,只是this.dt始终相同。即1000 /游戏循环所需的FPS。
如果要在两帧之间进行平滑/插值...则还必须记录对象的先前状态..您可能不想使用Euler旋转,因为euler不会插值不好。因为360度的角度会翻转回0,所以插值逻辑变得很奇怪...
但是,相反,您可以记录更新前后的状态...
然后内插.quaternion ..对于较小的旋转变化,它仅适用于线性内插..如果变化太大,则可以使用quaternion.slerp()来处理较大距离的内插。
所以您有lastTickTime,currentTime和nextTickTime...。
每个框架..您正在做类似的事情:
要进行插值,请执行以下操作:
var alpha= (currentTime-lastTickTime) / (nextTickTime-lastTickTime);//nextTickTime-lastTickTime = your framerate delta so for 60fps = 1000/60 = 16.666666666666668
var recip = 1.0 - alpha;
object.position.x = (object.lastPosition.x * recip)+(object.nextPosition.x*alpha)
object.position.y = (object.lastPosition.y * recip)+(object.nextPosition.y*alpha)
object.position.z = (object.lastPosition.z * recip)+(object.nextPosition.z*alpha)
object.scale.x = (object.lastScale.x * recip)+(object.nextScale.x*alpha)
object.scale.y = (object.lastScale.y * recip)+(object.nextScale.y*alpha)
object.scale.z = (object.lastScale.z * recip)+(object.nextScale.z*alpha)
object.quaternion.x = (object.lastQuaternion.x * recip)+(object.nextQuaternion.x*alpha)
object.quaternion.y = (object.lastQuaternion.y * recip)+(object.nextQuaternion.y*alpha)
object.quaternion.z = (object.lastQuaternion.z * recip)+(object.nextQuaternion.z*alpha)
object.quaternion.w = (object.lastQuaternion.w * recip)+(object.nextQuaternion.w*alpha)
在适当的三个应用程序中,您可能不应该将lastPosition和nextPosition直接存储在对象上,而是将其放置在object.userData中,但是不管怎样,它仍然可以工作。.