射击游戏手感与表现构建综述(上)

鹤舞九霄

2021-11-1511270次浏览

3评论

22收藏

4点赞

分享

>>> 本课程收录于《游戏手感的解读》专题

本文以策划视角介绍射击游戏中常见体验的构建方向。程序同学关注点可以放在“知道策划可能要做这么个东西,程序可以提前做一些相关思考”。希望这篇文章能够帮到同在制作射击游戏的同学们。

前言

本文以策划视角介绍射击游戏中常见体验的构建方向。程序同学关注点可以放在“知道策划可能要做这么个东西,程序可以提前做一些相关思考”。希望这篇文章能够帮到同在制作射击游戏的同学们。

一、外设输入

射击游戏的反馈通过外设输入,经过游戏逻辑处理,最终呈现于屏幕上。外设输入是这个环节中的第一步。本段介绍外设输入相关参数的处理。

1.1 鼠标灵敏度定义

射击游戏的鼠标灵敏度可以定义为:鼠标在现实中移动的物理距离,与游戏内镜头旋转角度的对应关系。游戏内的鼠标灵敏度一般由EDPI表示。

EDPI = 鼠标DPI * f(游戏内设置的灵敏度数值)。函数f即为游戏内的灵敏度规则。

1.2 常见游戏的灵敏度规则

主要有线性型和指数型两种。

线性型:代表游戏有CSGO,COD系列,守望先锋,APEX。

相同鼠标DPI下。当灵敏度值为a时,镜头转动360°需要移动鼠标的距离为d;当灵敏度值为2a时,镜头转动360°需要移动鼠标的距离为d/2。

线性型的游戏之间,灵敏度值往往是一个固定倍率的关系。比如CSGO的灵敏度值为1.0,对应COD系列和守望先锋的灵敏度值为3.33,对应APEX的灵敏度值也为1.0。详细的关系可以在https://www.mouse-sensitivity.com/中查到。

指数型:代表游戏仅有PUBG,所以以PUBG为例。

相同鼠标DPI(以1000为例)下。灵敏度值为0,50和100的对比如下图所示。

图线形式如下图所示。x表示游戏灵敏度值,y表示镜头转360°需要移动鼠标的距离。

公式为y=y0/pow(10, x/50)。其中y0表示灵敏度为0时y的值。

1.3 镜头FOV和相对灵敏度

上文提到的是鼠标移动与游戏镜头旋转角度的关系。但是,玩家感知到的鼠标灵敏度,是从镜头旋转时景物变化的快慢感知到的,并不是从镜头旋转角度量中感知到的。这里介绍玩家感知景物变化快慢与镜头实际旋转角度的对应关系,即相对灵敏度。

1.3.1 镜头FOV

在介绍相对灵敏度之前,需要介绍镜头FOV的概念。

上图中,s为视锥的中垂线。s⊥v,s⊥h,v⊥h。

屏幕分辨率resolution = h / v。

∵h = s*tan(HFOV/2),

  v = s*tan(VFOV/2)

∴resolution = tan(HFOV/2) / tan(VFOV/2)

笔者使用的引擎,FOV指的是VFOV。HFOV根据当前的屏幕分辨率,由VFOV换算而来。

1.3.2 玩家感知景物变化快慢

玩家感知景物变化快慢,实际上是屏幕最左端的景物标志物滑动到屏幕最右端的速度,即以“屏幕”为单位(例如下图中CS的半屏甩狙)。

1.3.3 倍镜与相对灵敏度

射击游戏中往往有多种倍镜。不同放大倍率,本质上对应了不同的镜头FOV。以PUBG为例,TPP下默认的HFOV为80,开2倍镜时为40,开4倍镜时为20,开8倍镜时为10。

这里我们假设某游戏的默认HFOV为120,开倍镜后的HFOV为60,那么可以得到下面两张图(左图为默认,右图为开倍镜)。

现在从玩家体验层考虑。在左图的视野下,玩家环视一周的景物变化为“3屏”;在右图的视野下,玩家环视一周的景物变化为“6屏”。假设玩家在相同时间内,鼠标移动相同距离完成了上述环视一周操作。显然,玩家会觉得右图视野下的鼠标灵敏度更高(为左图的2倍),因为景物变化速度右边是左边的2倍。为了让玩家感觉左右两边的景物变化速度相同,以获得相接近的手感,就需要使右图视野下,鼠标移动相同距离下景物变化也为“3屏”。这种校正的方式,即为相对灵敏度。

综上,在定好了鼠标灵敏度的基础规则后,需要根据HFOV的变化来调整“鼠标移动相同距离时,镜头转动的角度”,以保证手感的一致性。

1.4 摇杆输入数据源的处理

市面上的两大主流游戏机为PS和Xbox。所用输入设备均为手柄。

玩家通过手柄的摇杆输入方向。摇杆看上去是圆形的,但是拨动摇杆旋转一周得到的源数据却是如下图所示(数据源由引擎支持同学提供)。

从图中可以看出,得到的摇杆输入源数据,并不是标准的1*1正方形,也不是标准的单位圆,而是一个类似圆角正方形的图形。如果游戏逻辑层粗暴地以处理1*1正方形或者处理单位圆的方式,来处理摇杆输入源数据,游戏中摇杆输入对应的表现(可能是镜头或主角动作)和手感必定会造成奇怪的体验。

因此,我们需要引入摇杆输入源数据的修正规则,先把摇杆输入源数据clamp到单位圆上。然后游戏逻辑层再以处理单位圆的方式,处理修正后的摇杆输入数据,就不会有体验层的问题。

可以发现,摇杆输入源数据,实际上由下图的蓝圈和红框取交集而得,修正规则的目标是把这个“圆角正方形”clamp到绿色的单位圆上。

详细规则如下:

(1)确定原始输入幅度

magnitude = sqrt( pow(X, 2) + pow(Y, 2) ); 
if(magnitude>1){ magnitude = 1;}

(2)剔除摇杆死区得到修正后的输入幅度

activeRange = (magnitude - deadzone)/(1 - deadzone); if(activeRange<0){activeRange = 0;}

(3)计算输入角度

angle = atan2(Y/X)

(4)归一化(clamp到绿色单位圆)

newX = activeRange*cos(angle); newY = activeRange*sin(angle)

得到的newX和newY即为修正后的X和Y。脚本其他需要用到摇杆输入的地方,都必须读取newX和newY。

算法原链接地址:
https://answers.unrealengine.com/questions/226365/analog-stick-input-traces-a-square.html

二、镜头基础规则

2.1 TPS镜头

2.1.1 TPS镜头基础参数

TPS镜头的基础参数有offset(Vector3类型)和length(Float型)。

其中,offset表示角色模型空间下的镜头焦点位置。以PUBG为例,焦点大约在角色的头部偏右一些的位置。

length为镜头的焦距,表示镜头实际位置与镜头焦点的距离(镜头朝向为镜头位置指向镜头焦点位置组成的方向向量)。因此,抛开角度限制的因素,当镜头焦点位置不变时,镜头实际位置组成的集合为一个球体,球心为镜头焦点位置,球面为镜头位置,半径为镜头焦距。在笔者使用的引擎中,这种镜头模式为FollowPlacer。

但是如果将FollowPlacer直接用于TPS游戏会出现一些问题。还是以PUBG为例,按住Alt键自由观察时,角色的模型空间是没有变化的,只变了镜头。如果此时镜头以模型空间下某个固定的offset为焦点,那么在转动镜头时,角色在屏幕中的位置就会绕圈,而offset点在屏幕中的位置是不变的,这并不是玩家期望的效果。玩家期望的是角色在屏幕中的位置不变。因此需要做补充规则。Offset只是镜头在pitch=0,yaw=0时,焦点在模型空间中的位置。当镜头转动时,焦点需要以焦点到角色轴心的距离为半径,绕着一个圆旋转,这样才能保证角色在屏幕中的位置不变。在笔者使用的引擎中,这种镜头模式为TpsPlacer。

有了原始的TpsPlacer,可以发现,当pitch(俯仰角)较大时,镜头离角色的位置会过远。因此需要根据镜头当前的pitch值修改镜头的length。从侧视图看,镜头位置的集合变为椭圆。

侧视图参数说明(以笔者使用引擎的坐标系为例):

上方向对应y轴正向,右方向对应z轴正向。

O点为主角位置,P点为镜头焦点位置,C为某个pitch角度下的镜头点。

OP为offset。

椭圆上一点到P点的距离记为PivotDistance。PivotDitance由椭圆的半长轴和短半轴以及当前镜头的俯仰角(pitch)决定。

最终,策划想要定义一个TPS镜头的位置,就需要配置offset(pitch和yaw都为0时,焦点在角色模型空间的位置),length_a(pitch=0时的length,也是侧视图椭圆的半长轴),length_b(pitch=±90时的length,也是侧视图椭圆的短半轴),共3个参量。

2.1.2 TPS镜头之间的过渡

上文中提到,一个完整的TPS镜头由offset, length_a, length_b三个参数组成。当主角的状态变化(例如进入肩射视角、蹲下、趴下)时,策划需要给出新状态的镜头参数。

例如站姿肩射时,策划需要配置站姿肩射的offset,并将原有的length_a和length_b等比例缩小一个倍率;蹲下时,策划需要配置蹲下状态对应的offset;趴下时,策划需要配置趴下状态对应的offset。保证每个状态都有唯一的offset和length_a, length_b。

PUBG肩射镜头过渡:

然后是过渡的过程。以笔者使用的引擎为例。可以通过脚本的Mover实现过渡(引擎目前提供了“无过渡”和“线性过渡”两种过渡规律。如果想通过脚本实现更复杂的过渡规律,则需要策划给出过渡公式,程序同学自定义Mover)。也可以通过编辑器的CameraPivotCtrl节点,配置halflife参数使用半衰期过渡规律。策划同学在配置镜头参数时,除了需要配置offset和length以外,还需要配置进入该镜头时的transit_time或者halflife。

实际应用中的细节点:状态是唯一的,但是镜头表现一定不能跳变,程序层的插值算法需要保证镜头在任意时刻都是连续的。除非策划有特殊要求,否则任何镜头跳变的情况都会极大降低玩家的游戏体验。

2.2 FPS镜头

2.2.1 FPS镜头的基础参数

FPS镜头的基础参数有offset(Vector3类型)和length(Float型)。

其中,offset表示pitch=0且yaw=0时,镜头在角色模型空间的位置。length表示旋转轴长度。

当玩家以第一人称旋转视角时,模拟的是角色的瞄准偏移。角色的瞄准偏移,并不是保持视点位置不动,仅作“向上看”和“向下看”的表现。而是在整个向上向下看的过程中,视点的位置也有所变化,如下图所示(做了夸张处理)。

因此引入length来表示旋转半径。

最终,策划想定义一个FPS镜头的位置,就需要配置offset。而length只需要在镜头初始化的时候指定一次即可。

2.2.2 FPS镜头之间的过渡

上文中提到,策划只需要指定offset参数即可指定一个状态下的FPS镜头参数。

例如蹲下时,策划需要配置蹲下时的镜头offset值;侧身peek时,策划需要配置左peek和右peek时镜头的△offset值,站姿peek就是站姿的offset+△offset,蹲姿peek就是蹲姿的offset+△offset。

以笔者使用引擎为例。过渡过程可以通过脚本用Mover实现过渡,引擎提供的过渡规律也是“无过渡”和“线性过渡”两种,如果想通过脚本实现更复杂的过渡规律,同样需要策划给出过渡公式,程序同学自定义Mover。

2.2.3 FPS与TPS镜头之间的过渡

TPS视角下使用的是TpsPlacer,FPS/ADS视角下使用的时FpsPlacer。

TPS(Third Person Shooting)视角:

FPS(First Person Shooting)视角:

ADS(Aiming Down Sight)视角:

以笔者使用的引擎为例,TpsPlacer与FpsPlacer切换时,使用Blender做镜头的过渡。引擎提供的Blender过渡规律也是“无过渡”和“线性过渡”两种,如果想通过脚本实现更复杂的过渡规律,同样需要策划给出过渡公式,程序同学自定义Blender。

2.3 关于Mover修改FOV的补充

以笔者使用的引擎为例。

上文提到Mover时,只提到了其修改镜头位置参数的作用。实际上镜头参数还包含了镜头的FOV值,使用Mover同样可以在脚本中修改镜头的FOV值,以及控制过渡规律。例如屏息操作的镜头反馈。策划需要配置屏息状态下的FOV倍率,以及进出屏息镜头的过渡时间。

使用编辑器的CameraFovCtrl能够实现同样的效果,过渡规律为半衰期过渡。触发屏息操作时,脚本设置控制屏息模块的开关图变量,策划使用开关图变量加上平滑过渡即可。

▼▼▼

《射击游戏手感与表现构建综述(下)》

▲▲▲

评论 (3)

0/1000
网易游学APP
为热爱赋能
扫描二维码下载APP