关闭

Dead Reckoning: 在网络游戏中消除延时影响

1326人阅读 评论(0) 收藏 举报

原文来自Gamasutra的Dead Reckoning: Latency Hiding for Networked Games,作者是Jesse Aronson。可以通过这个地址http://www.gamasutra.com/features/19970919/aronson_01.htm查看该文章(可能需要先登陆到Gamasutra),或者通过文章名到Google上查找其他转贴。

翻译的不好的地方欢迎指出,我会尽快改进,转贴请注明出处。

 以下是正文部分:

----------------------------------------华丽的分割线------------------------------------------

  

网络游戏的开发人员会很快发现需要处理网络延时的问题,延时就是网络数据包从一台计算机到另外一台计算机上所需要的时间。

对于移动缓慢的游戏,或者类似象棋这样的基于回合制的游戏来说并不是什么大问题。另一方面,如果玩家之间需要快速交互,比如“Twitch”这样的游戏,都会被典型的WAN甚至是LAN延迟所严重的影响。玩家期待联机游戏的表现能够接近于单机游戏。

当前的网络游戏供应商的解决方案大多依赖于专用网段,点对点的延时大概在150到200毫秒之间。专用网络是可行的解决方案,尽管当网络游戏操作是在一个不固定的,响应方式是在标准的网络环境下的时候它可以表现得更好,这时候的延时几乎不可预测并且大多时候会比较大。

很幸运的是,作为一个纳税人,你的美元曾被用来开发一个关于网络游戏的技术方案。美国国防部重金投资于一个用于军事训练的分布式模拟系统,特别是在分布式交互模拟(DIS)协议中,这个协议是在国防部高级研究项目机构(DARPA)的SIMNET项目中研发出来的。

DIS包含了隐藏延时和减少带宽使用的技术,它被称为Dead Reckoning(DR)。DR被广泛的使用,在DARPA的高级分布式模拟架构项目中被扩展成为“可预测性合约”的概念。DIS是做为网络坦克群模拟的环境被创建的,一些DIS的应用和twitch游戏一样使用了常用的特性。

 

DR的概念

DR是复制计算的一种形式,在游戏中每个人参与模拟游戏个体(典型的是交通工具),虽然逼真度很低。基本的DR概念就是预先在一些算法上建立一个协议,每个玩家都可以用来推断游戏中的个体的行为,并且协议也规定当推断算法和实际值的误差是多大的时候进行修正。

DIS下,当一个交通工具或者游戏个体被创建的时候,拥有该个体的计算机向网络上的所有计算机发送该个体的状态协议数据单元(PDU),个体状态的PDU包含了唯一确定该个体的信息;描述了个体当前运动状态的信息,包括位置,速度,加速度和方向;以及如个体伤害程度等其他信息。

最后,个体状态PDU包含了一个标志符,它告诉网络上的其他节点该个体使用的是何种DR算法。当参与分布模拟的其他计算机接收到该PDU的时候,它们创建该类型个体的本地备份。这样,每个网络上节点可以见到该个体,之后,最小的个体状态PDU将会每五秒发送出去。

撇开某些类型的推断算法,开始时发送的单个个体状态PDU会出现在远程终端上,但是它时静止的,只有描绘它的更新参数的附加PDU被发送的时候才会移动。这样,远程个体的运动看起来会很不稳定,在下一个PDU到达之前它们是静止的,而当新的PDU到达的时候又将发生位置上的跳动。减少PDU发送间隔将会减少这种不稳定感,但是这种方法在某些有着大量个体的关卡中,会极快的消耗可用的网络带宽。

DR中,接收到第一个个体状态PDU的时候,网络上的每个节点都开始使用约定的DR算法使该个体开始移动。该个体以一种可预测的方式持续移动,在所有的节点上,它的路径都使一致的同步的,也不需要更多的网络通信。

当然模拟个体并不总是以可预测的方式移动,玩家随时移动控制杆来操纵它,它就背离了平滑的,算法可以定义的一个路径。在DIS中,拥有该个体的计算机将会去检测和操作。

个体的拥有者记住最后一次发送PDU的时间,同时也基于这个PDU运行DR算法,那么它就拥有一个最新值的拷贝,正如网络上的其他点所看到的。

拥有者的模拟将DR值和玩家所控制的个体的真实状态进行比较,如果DR值和真实值之间的差距超过了DR协议所规定的极限,那么将把新的个体状态PDU发送给网络上的其他节点。所有的节点根据最新的个体状态PDU值更新它们的本地拷贝,DR就从新的数据点重新开始。

 

上图展示了DR的一个例子。在时间T0的时候,图左的一个飞船模拟器发送了第一个PDU告知网络上其他所有计算机飞船的存在和位置。这时,所有的计算机同步了飞船的位置。从这个点之后,其他所有计算机开始显示飞船,并根据协议算法让它向前移动。如虚线所示。

飞船的拥有者,基于玩家的输入(比如摇杆)来移动飞船,如左边的红线所示,而此时网络上的其他玩家看到的移动路线按虚线所示。当DR算法的位置和真实位置保持在预定义的一个阀值之间的时候,就不向网络上发送任何别的信息。节省网络带宽的同时其他玩家也可以基于DR算法看到一个平滑的移动路径。

然而,拥有者和网络上其他的模拟者之间始终存在着很微小的差异。当这个差异变大,在T1时刻超过预定的DR阀值的时候,就向外发送新的PDU包。这时,网络上的其他计算机马上根据新的PDU包同步它们本地的飞船位置,并重置DR算法,如T1’所示。DR算法重新开始运行,从T1’开始往后。

从图中我们可以很容易看出,过大的DR阀值会导致当远程终端收到新的PDU包的时候做一个明显的剧烈的跳动。从另一个角度来说,小的DR阀值会导致需要发送更多的PDU包。我们应该根据应用类型来选择最优的DR阀值。

DIS模拟也很典型的应用了平滑算法,使得个体在从DR位置更新到新的真实位置的时候的跳动效果减小。DIS模拟象位置一样应用了DR来面向移动。方向推断使用了另外一些算法,和位置推断有所不同,但是它们都是基于同样的原理。

 

DR的算法

下一步,我们来看一下DIS所实现的真正的DR算法。有九种标准算法,其中最有效的是两种,其他的大致相同,只不过使用了不一样的坐标系。我们来看一下最典型的三种算法。

位置1 = 位置0

位置1 = 位置0 + 速度 × (T1 – T0)

位置1 = 位置0 + 速度 × (T1 – T0)+ 1/2 × 加速度 × (T1 – T0)平方

以上就是DIS的三种DR算法。它们都基于最基本的物理定律。第一个算法把位置保持在T0时刻的个体状态PDU中所指定的位置。第二个算法根据已知的T0时的位置推断它向前的移动。第三种算法也从个体的最后已知位置向前推测,但是在推测种同时使用了速度和加速度。

这三种算法都很好的推测了位置。DIS中使用的更多精密复杂的算法也考虑了个体的方向(卷动,投掷,航向),甚至推测了个体的部分移动。比如,一辆坦克在向前巡逻的时候它的炮台向后扫描,我们可以用DR算法同时推测它的位置和坦克上的炮台的角度。

 

DR的应用

L1(最下方)显示了一个程序段,它从网络上的别的程序接收个体状态PDU,然后把已知的都显示出来,使用上面所提到的第二个DR算法。代码是C++风格的,类的构造,程序的初始化以及其他的细节没有在这里显示。

程序的主循环首先检查了是否有新的网络可用包。IDS使用UDP来通信,所以这里我们使用一个类JAVA的UDP socket类来存取UDP包。下一步,初始的包被解析并转换成个体状态UDP对象,其中包含了远程个体的位置,速度和特性等信息。

如果这个个体已经是已知的(比如TankList中已经存在该ID),那它的位置和速度将被更新。否则一个将在TankList中添加一个新的单位。接收时间也将被储存在远程移动物体表中(ctime是取得当前时间的一个函数);这是DR的要求。

当接收到新的包的时候,使用DR对TankList中的所有个体的位置做更新,然后显示在屏幕上。DR并不重置接收位置,因为它可能在一段时间之后的DR运算中被使用到。

L2(最下方)显示了一段用于发送模拟坦克信息的程序。它也遵守了DR的规则。程序基于用户摇杆输入不断的更新myTank。每次更新之后,它检查差值是否超过了DR阀值。如果超过,那就发送新的PDU来描绘新的状态。程序在最开始发送了一个个体状态PDU以使得网络上的其他计算机知道myTank的存在,程序必须记录最后发送的状态信息以及发送的时间。

 

DR的扩展

DIS主要使用DR来推测车辆的位置和方向,它也通过多项式来实现。DIS应用扩展了DR算法,允许推测车辆的可动部分(比如坦克上的炮台)。

DARPA ADS架构研究验证了DR的价值,拓展了原理以应用于网络对象的所有属性和推测的更大类别。使用这些拓展定义的推测被认为是预测性协议。

比如在一个坦克战役模拟中,某个被称为“沿路行驶到特定点”的预测性协议是可以被定义的。在这个预测性协议下,计算机模拟一辆坦克只需要发送关于车辆的一条信息:这是路上的某个特定点,而它正在沿路往前走,直到某个指定的点。

网络上的其他计算机都认同“沿路行驶”(比如你在右边行驶)的含义,并且所有的计算机都知道坦克所在的路的定义,那么它们就可以创建坦克的连续视图,而不需要进行任何的网络通信。当然,如果坦克偏离了它原计划的路径或者改变状态到其他任意一条不可预测的路径上,新的坦克状态信息将被发送到网络上。附加的预测性协议可以定义什么时候坦克关闭或者打开传感器,什么时候发送无线电报告,或者坦克行为的其他属性。

分布式对象计算的JAVA模型的出现允许更精确的预测性协议。在DIS模型中,所有的DR算法是在编译器被定义的,对于模拟来说没有办法在运行期去定义新的DR算法。使用类似JAVA这样的语言,模拟就可以随意通过网络发布更新的预测性协议。

 

其他

DR和预测性协议为网络模拟和游戏提供了两个好处。它们隐藏了网络固有的延时,也带来了另一个好处,就是通过允许模拟器仅在真正需要的时候才传输信息,减少了网络通信量。在DIS中,DR也允许通过更佳效果的通信方式(比如UDP)来传输个体状态信息,相比于代价昂贵的,保证可靠传输的机制比如TCP/IP。这是因为DR可以用来平滑丢包带来的缺口,即使丢失了一些网络同步包。

DR并不是无代价的。它需要网络上的每台计算机运行一个算法来推测模拟关卡中的每一个个体。如果模拟环境中的所有的个体同时表现得不可预测,DR就收效甚微了。然而,DR在DIS这样的大关卡和众多的计算机产生的个体中提供了重要的优势。在这种情况下,如果处理器周期能被交替使用以减少网络使用和明显的延时,DR可以成为一种非常有效的最佳技术。

Jesse Aronson是Science Application International Corp. 的首席软件架构师。他积极参与了国防部次世代的建模和模拟的架构定义,也是当前一个项目的技术总监,该项目将创建一个由数百台计算机模拟数千个移动对象的网络训练模拟环境。可以通过jaronson@std.saic.com联系他。

L1: 使用DR的接收模拟

main(){
  //接收模拟
  DataGramSocket socket1;
  DataGramPacket packet1;
  EntityStatePDU espdu1;
  TankList remoteTanks;
  int i;

// 初始化代码,开启socket等等

// ... (其它未显示)

// 进入循环,接收并处理远程信息

while(1){
// 接收新的包

if (socket1.packetAvailable()){ #1
 socket1.receive(&packet1);
 espdu1.convertFromRawPacket(&packet1); //#2
 if (TankList.member(espdu1.entityID()) //#3
   TankList.update(espdu1,ctime());
 else
   TankList.addEntity(espdu1,ctime());
 }
...

L2: 使用DR的发送模拟

main(){
  //发送模拟
  Joystick stick1;
  DataGramSocket socket1;
  EntityStatePDU espdu1;
  tank myTank(initPosition);
  int i;
 
 
  // 开始时记录信息并发送
  espdu1.initializeWithPosition(myTank.Position());
  socket1.send(espdu1.convertToRawPacket());
  lastStateSent = myTank;
  lastTimeSent = ctime();
 
 
  while(1){
    // 根据摇杆更新坦克信息
    myTank.calcNewPosition(JoyStick.read());
 
 
    // 计算DR位置
    myTank.setDRposition(lastStateSent.position() + 
        lastStateSent.velocity() * (ctime() - lastTimeSent);
               
    // 仅当超过阀值时发送
    if (abs(myTank.position() - lastStateSent.position() > thresh){
      socket1.send(espdu1.convertToRawPacket());
      lastStateSent = myTank;
      lastTimeSent = ctime();
      }
    }

}

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:135238次
    • 积分:1403
    • 等级:
    • 排名:千里之外
    • 原创:2篇
    • 转载:49篇
    • 译文:1篇
    • 评论:21条
    游戏相关
    友情BLOG