2.1.1 离线处理
视野遮挡主要有两种实现方式,一种是,运行时实时射线检测目标与自己之间是否有阻挡,这种方式几乎没有额外的内存消耗,但对于探索源与被探索单位多并且查询频繁的游戏,运算效率较低。另一种则是,预计算了每一个网格与它视野范围内其他网格的可见性,并保存为局部视场(Field Of Vision)来进行快速视线检测(FastLOS,Fast Line-Of-Sight)[1],这种方式有额外的内存消耗,但基于视场遮罩线性表查询的方式效率高,并且计算量较大的部分能够分离到静态离线处理。离线处理主要是为了减轻运行时计算压力,从而提高游戏帧率(FPS),因此基于局部视场遮罩的方式更适合MOBA这类对实时性、爽快性有高要求的游戏。
视野的离线部分主要分为网格属性生成与视场遮罩生成两部分,如图2.5所示。首先根据场景大小来二维网格化场景,这一步需要确定单个视野网格边长(GridSize)与网格数量,以此生成覆盖整个场景的视野网格。
需要注意的是,网格边长越小,网格精度就越高,但整个网格与视场遮罩所需的内存就越大,同时视野更新的计算量也就越大。接着需要对每个网格生成其属性,例如,草丛网格、常亮网格、墙体网格等。如图2.6所示,黄色的是常亮网格,绿色的为草丛网格,红色的是墙体网格,这些网格描述了场景中具有静态视野属性的区域与物件。
图2.5 离线计算流程
图2.6 网格属性
可以实现一套属性画刷工具来进行网格属性的编辑。也可以使用标定的方式,赋予标定脚本网格属性并标定一块几何区域,然后根据每个网格与标定几何区域的位置自动对网格属性进行赋值。还可以根据美术资源的网格信息来实现网格属性的自动生成。如图2.7所示,左图列举了一套基于UGUI(Unity GUI)简易的画刷系统来对网格属性进行编辑与修改,右侧两图是一种标定脚本,标定了一块具有草丛属性的区域。
图2.7 画刷与标定脚本
视场遮罩(视场可见性)表示某个网格在它视野范围内的可见性,它使用2D顶视角局部视场算法来进行计算。计算2D顶视角局部视场常用的算法有射线投射、阴影投射、菱形算法、松散视野检测等[2][3][4]。计算离线视场遮罩时需要视野范围参数,此参数被认为是对局支持的最大视野范围,一般通过配置进行读取,不能动态增加,否则需要重新进行离线预计算流程。图2.8展示了一种基于射线投射方案的改进型视场遮罩,图中以中心网格为角色所在点,白色代表对其可见的网格,黑色代表对其不可见的网格,并且草丛不具有视野遮挡功能,但墙体能够遮挡角色视野。除此之外,视场遮罩的计算也需要处理草丛规则,例如,草丛对非草丛的不可见性、相同草丛可见、不同草丛不可见等规则。如图2.9所示,分别表示在草丛外的视场遮罩、在草丛A内的视场遮罩、在草丛B内的视场遮罩。
图2.8 视场遮罩
图2.9 不同规则下的视场遮罩
计算出每个网格的视场遮罩后,需要序列化存储,在运行时反序列化读取使用。文中所述的网格属性与视场遮罩数据均为数组形式,这里使用基于Unity引擎实现的自定义序列化器来序列化上述数据,并在逻辑层反序列化使用。