线性扫描枪的最简单实现的思路

  • 一、从准星位置发出射线检测阻挡物,目的是获取当前阻挡物。
    1. 获取准星在3D世界的位置(Position,Direction)
    2. 将Position作为起点,方向为Direction,方向如果是单位向量记得乘以一个比较大的数。
      1. PS:我是觉得这个数可以根据枪支类型来改变,冲锋枪 / 手枪可以小一点,狙击枪远一些。
    3. GetWorld()->LineTraceSingleByChannel()(UE发出射线检测的函数)
    4. 如果碰到阻挡物,则拿阻挡物的位置返回;碰不到就直接拿最长距离。
  • 二、将获取到的阻挡物的位置作为End向量。
    1. 获取枪口位置Location,使用他作为Start的向量。
    2. 当前获取的阻挡物 HitTarget - Start 为方向向量,可能有时候够不着,可以乘以一个1.X的系数。
    3. GetWorld()->LineTraceSingleByChannel()(UE发出射线检测的函数)
    4. 如果是本地游戏,检测到就应用伤害ApplyDamage即可;网络游戏要在服务器ApplyDamage(UE检测当前是否为服务器函数HasAuthority())。
    5. 应用特效(射击轨迹,终点特效,枪口特效)。

改进版本的线性扫描枪

  • TODO: zhongqian 这里应该有一张图片解释一下原因。
  • 原因:你从准星作为起点获取的阻挡物可能提前被挡住了。
  • 修复BUG:
    • 执行后,需要在以枪口为起点,阻挡物为终点,使用射线判断一下是否有其他阻挡物提前阻挡在枪口到原来的HitTarget中间了。

散弹枪实现版本

  • 首先,需要知道的是散弹枪与之前实现的手枪之间的差别是什么?
    • 单个子弹与多个子弹(散弹枪一般都是多颗子弹一起发射)
    • 弹:是范围伤害而不是单体伤害。
  • 实现思路:
    1. 每颗子弹单独计算,说实话有点浪费了。
    2. 在一定范围内用一个圆包围着所有子弹,所有子弹均落点在圆内。
      • PS1:因此这个圆的远近与大小决定了这个散弹枪的性能,如果远距离 + 小圆可以表现出独头弹的效果。
      • PS2:圆的半径与距离应该存在一个正相关的关系。
  • 具体流程,PS:这个流程插入在 最简单实现的思路改进版本的线性扫描枪 之间:
    1. 获取当前Start到HitTarget的归一化向量
    2. 计算到随机圆中心的向量
    3. 在随机圆内随机生成的向量
    4. 计算 射击终点 & 发散圆内某一点的最终位置
    5. 计算 到起始点到随机点的向量
    6. 返回 从起点到终点的随机圆的向量 * 一个非常大的值 作为 HitTarget
  • 如果服务器与客户端同时计算会导致随机数不一致的问题,交给客户端计算随机数;当然,如果预防作弊,则记录一下弹道,如果很长一段时间弹道计算在客户端计算有问题,则需要进行以下我的头脑风暴结果:
    • 如果遇到完全集中在一个点并发生了很多次,则有作弊嫌疑;
    • 如果散弹枪的每颗子弹都远距离(设置一个阈值)命中并发生了很多次,则有作弊嫌疑;

线性扫描枪支使用客户端预测算法

  • 思路:
    • 在客户端中如果击中角色先把特效全部使用,但是逻辑伤害交给服务器去计算,计算完毕后返回并应用被击中角色上。
  • 效果 / 优点:先应用特效能够让高Ping的客户端玩家减轻卡顿的体验,但是关键的逻辑计算依然是交给服务器处理。
  • 缺点:如果客户端因为高Ping而当前判断不够准确,只会有击中特效而服务器逻辑计算失败,会影响玩家体验。