当前位置:嗨网首页>书籍在线阅读

07-添加步长定时器

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

9.1.5 添加步长定时器

第8章曾创建了一个简单的FrameRateCounter对象原型,用于显示游戏运行时的帧率。本节将扩展这个计数器的功能,向其中添加一个“步长计时器”。步长计时器将计算两帧之间的时间差,并创建“步长因子”——计算对象在画布上的位置时将用到步长因子。这样做的结果不仅会在帧率丢失的情况下保持游戏对象的平滑渲染,还可以在不同浏览器和不同系统上保持游戏运行的一致性,特别是在那些提供维持游戏高效运行帧率的系统上。

下面将修改FrameRateCounter的构造函数,使其能够接收一个新参数fps。这个值表示游戏运行时的每秒期望的帧数。

function FrameRateCounter(fps){
  if (fps == undefined){
   this.fps = 40
  }else{
   this.fps = fps
  }

如果没有传入fps,将使用40作为fps的值。

添加两个对象级作用域的变量,用于计算步长计时器的步长。

this.lastTime = dateTemp.getTime();
this.step = 1;

lastTime变量将保存前一帧结束工作时的时间。

通过在每一帧中比较当前时间的值与lastTime的值计算步长。在FrameRateCounter的countFrames()函数中进行计算。

FrameRateCounter.prototype.countFrames=function(){
  var dateTemp = new Date();
  var timeDifference = dateTemp.getTime()-this.lastTime;
  this.step = (timeDifference/1000)*this.fps;
  this.lastTime = dateTemp.getTime();

局部变量 timeDifference 的值等于 lastTime 的值减当前时间(即 dateTemp.getTime()的返回值)。

为了计算step的值,用timeDifference除以1000(1s中包含1000ms),再乘以期望的帧率作为结果。如果游戏在运行时没有产生多余的帧或者丢帧,step的值将是1。如果当前帧的处理时间超过1帧的结束时间,则step值将大于1(丢帧)。如果当前帧的处理时间小于1帧的时间,则step值将小于1(多余帧)。

例如,如果上一帧的处理时间过长,那么作为补偿,当前帧需要比step值为1时将每个物体多移动一点。下面通过一个简单示例进行说明。

假设飞碟在每帧应该向右移动5个像素,也就是说,dx的值等于5。

在这例子中,再假设期望的帧率是40FPS。这意味着希望每一帧的时间是24ms(1000/40=25)。

假设在当前帧和上一帧之间的时间差timeDifference是26ms。游戏运行时每帧将缺少1ms,这意味着游戏处理花费了比预期要长的时间。

为了计算step的值,将timeDifference除以1000,即26/1000=0.026。

用这个值乘以游戏的期望帧率:0.026*40 = 1.04。

当前帧的step值是1.04。由于处理时间的欠缺,因此需要将每个物体比正常的1帧多移动一点,这样才能消除多余或欠缺的时间。在没有多余或欠缺时,step的值是1。如果存在多余时间,step的值将会小于1。

在每个对象的更新函数中,将step的值乘以移动向量。这样,即使帧率有波动,游戏的动画也可以看起来相对平滑。此外,游戏在不同的浏览器和系统上刷新屏幕的方式相对一致,这样可以保证每一个用户运行游戏的体验相对一致。

以下是为每个对象计算新的移动向量。

  • player;
player.x += player.movingX*frameRateCounter.step;
player.y += player.movingY*frameRateCounter.step;
  • playerMissiles;
tempPlayerMissile.x += tempPlayerMissile.dx*frameRateCounter.step;
tempPlayerMissile.y += tempPlayerMissile.dy*frameRateCounter.step;
  • rocks;
tempRock.x += tempRock.dx*frameRateCounter.step;
tempRock.y += tempRock.dy*frameRateCounter.step;
  • saucers;
tempSaucer.x += tempSaucer.dx*frameRateCounter.step;
tempSaucer.y += tempSaucer.dy*frameRateCounter.step;
  • saucerMissiles;
tempSaucerMissile.x += tempSaucerMissile.dx*frameRateCounter.step;
tempSaucerMissile.y += tempSaucerMissile.dy*frameRateCounter.step;
  • particles。
tempParticle.x += tempParticle.dx*frameRateCounter.step;
tempParticle.y += tempParticle.dy*frameRateCounter.step;

前面已经讲解了将Geo Blaster Basic升级为Geo Blaster扩展版所有的主要变化。例A-2显示了游戏最终的完整代码。