|
|
一、前言
最近在设计基于组装和物理的玩法,其中有两个非常有趣的问题,最近初步思考出结果,值得探讨交流一下。
问题1
如何基于组装和物理,设计单位间碰撞的伤害规则,既要好理解,且和其他伤害类型尽量统一逻辑?
问题2
如何基于组装和物理,设计移动操控方案,同样,既用物理作为底层,便于未来的拓展,又要保证操作手感?
在开始具体设计前,先要回答一个问题,为什么底层基于物理那么重要?基于物理其实设计和实现都会麻烦很多,但是好处就是未来的拓展性,一个统一坚实的底层,将会串联起所有未来的设计。例如如果我们的底层移动规则是基于力和质量等物理设计,那未来所有影响单位位移的特性,都可以用简单的施力方式改变来实现,比如后坐力,击退等等。同时,物理本身的好处比如具有提前认知,有足够深度,复杂系统能支持涌现设计等等,以前的文章都详细提过,就不赘述了。
实际上,这里强调的是统一坚实的底层,只要达到这两个要求,不管是不是物理作为底层都行。
二、碰撞设计
现实参考
设我们单位的所有常规碰撞为非弹性碰撞,因为完全弹性碰撞并不会造成伤害。同时,我们的单位是组装而成,因此基于模块设计,模块有基础的碰撞伤害,碰撞伤害和被伤害都是以模块为单位。若模块和核心相连,则质量为整体质量,速度仍为模块自己的速度,若模块脱离,则为模块自身的质量和速度。
整体上,碰撞需要符合玩家的直觉,一定是参考现实物理,但又不能完全照搬。因此我们只取物理中和碰撞相关的,且玩家最容易感知到的特性。
先参考现实,现实中的碰撞伤害很难有一个统一的标准,碰撞结果本身就多种多样,但不论怎样的结果,有一个统一的度量方法,就是基于动能损失,本质就是将动能转化成其他能量,一般我们忽略产生的热能等等,基本上就等于双方受到伤害的程度。我们先列一些现实中的公式:
动量:p=m*v
动能:ke = (1/2) * m * v²
损伤D = 参数M * (1/2) * (m1 * m2) / (m1 + m2) * |v1 - v2|²
M代表调整参数,表达不同材质,角度等因素造成的影响
游戏设计
游戏中设计,则需要我们进一步细化,且做出自己的变化,我将我们的碰撞过程抽象为五个步骤:
1.首先是碰撞角度考虑
碰撞时两模块相对速度 Vr=v1 - v2
过一遍阈值,Vr小于阈值则跳过计算,忽略伤害
获取碰撞点的法线向量,unity里就是collisionNormal
则最终的相对碰撞速度为 Vrf = Vector2.Dot ( Vr , collisionNormal )
Vrf也过一遍最小阈值,小于则忽略本次伤害
2.质量,动量,能量考虑
设双方总质量为m1,m2,则初步损伤Da= (1/2) ( (m1 * m2) / (m1 + m2) ) Vrf²
3.统一的撞击能力表达
将现实中的强度和硬度等概念去掉,用一个类似攻击力的,撞击能力来同时体现锋利度硬度等背后的特性
同样的,不同组件可配,整体上,我们希望用于撞击的,锋利的,强度高的,撞击能力配高一些即可
设我方组件撞击能力ImpactPower1,敌方ImpactPower2
则我方最终受到伤害Db1 = ImpactPower2 * Da;敌方为Db2 = ImpactPower1 * Da
4.统一的防御能力表达
将所有常规伤害来源的防御能力统一,暂定为装甲值Armor,碰撞或者子弹,激光击中等,都过一样的防御流程
防御公式也统一,比如用常规的除法防御,Dc_1 = Db1 × K / (Armor_1 + K)
至于其他防御公式,也可以随时换
5.模块间的伤害传递
用伤害类型来区分是否触发蔓延效果,所有动能伤害,触发冲击蔓延,所有非动能,触发其他机制。简化为用伤害类型来控制,如此可以更灵活,例如碰撞为全动能伤害,武器则更灵活,可以部分动能伤害混合其他伤害,各自计算即可。
冲击蔓延规则,是基于面的规则,目的是让玩家感受到冲击后影响一片组件的感受,符合直觉且塑造物理碰撞独有的意义。规则为:
用BFS方式,找出被冲击组件L0的相连组件L1,以及L1相邻的组件L2(不包含L0和L1)
L0收到的动能伤害D0,以一定比例P1折损后D1,平均分配到L1上,该伤害不视作动能伤害,视作特殊传递伤害,不会触发蔓延
同理,D1以P2比例折损后的D2,平均分配到L2。P1,P2可配
加入阈值,低于阈值伤害V,则不触发蔓延,V可配
三、机动性设计
再次回顾设计目的,基于物理的机动性设计有两大重点:
- 基于物理的提前认知,来降一些复杂设定的门槛,不需要多拟真,但要玩家感知上符合物理
- 未来所有可以基于现实规则的设计,都可以利用物理底层统一起来实现,而不需要另加一套规则
先总结一下,对玩家体验有较大影响的机动性相关要素是哪些?
- 最高速度
- 加速度,减速度,旋转角速度,影响操控手感
- 质量,不仅影响速度,也影响惯性感受
- 响应风格,摇杆推动时的响应曲线,同样明显影响手感
这里先提另外一种实现方案,有少量基于物理的游戏,一般是太空类游戏,是通过控制飞船引擎出力推动主角移动,这种确实更拟真物理。但问题是玩家操控难度大,因为玩家一般期望控制结果,而这种操控方式需考虑加减速过程,与常规游戏操作逻辑不同,操作手感一般都比较差。
而要手感比较好,一般游戏都会让操控输入,直接映射角色的实际速度,甚至定死几档速度,同时加减速度都跟物理无关,是直接设定好,甚至有很多不遵循现实的设定来保证手感,例如土狼时间,边缘吸附,空中转向等等。这当然没问题,绝大多数游戏的设计意图下,手感大于拟真。
而对我们来说,是“既要又要”,我们需要玩家手感好,但是底层需要仍是由物理驱动,来保证拓展性。具体来说,我们将运动分为两层,一层物理层,一层操控层。飞船的实际运动由物理层控制,跟飞船的总推力和总质量等物理参数有关。另一个是操控层,玩家操控摇杆时,抽象为给船一个目标速度和方向的指令,剩下的推力赋予,由系统来计算,减轻玩家负担。等于有一个飞船中控在帮玩家实时调节引擎推力,防止出现转向和精确控制速度困难的问题。同时,考虑到后续的组装,对物理层进行一定简化和抽象,具体如下:
物理层
飞船物理层运动的核心参数如下:
1.总推力Fa
用作计算飞船理论最大速度等等,由组装时的情况决定一个最终值,忽略方向和组装位置等影响,简化为一个总推力
2.总质量Ma
同上,组装时所有模块带来的质量加总,或者有其他加成减益都算完后的一个结果值,物理侧不关心细节,也只关心一个总值
3.阻尼系数μ
系统默认阻尼系数,加上环境带来的阻尼情况,例如固定摩擦和空气摩擦的近似设计,最终抽象为一个阻尼系数μ的输出结果。我们先省略默认阻尼,看需要再设计。先将阻尼系数分为两个部分,持续固定阻力以及类空气阻力两部分:
- 持续固定阻力F_const,作用是在低速时,防止停不下来,让操控更加干净利落
- 类空气阻力F_air,特点是速度越快阻力越大,因此可以控制最大速度,且反过来,因为有空气阻力,所以加速过程可以更快,让手感更好
- 则最大速度时的平衡条件为Fa = F_const + F_air
- 先简化空气阻力F_air的公式为线性公式,F_air = Kair * V_current。Kair可配。公式有可能会换平方公式,看实际手感调。
- 则最大预测速度 Vmax = ( Fa - F_const )/ Kair
4.总转动惯量I
惯量I表达了物理上,一个物体旋转的难度,我们用一个近似的简化公式:I = k*m*R^2
- k代表质量形状分布,质量越集中,越好旋转。我们可以用组装的长宽比来近似的定这个值,参考现实,0.2到1之间
- R为半径,越大旋转越难,直接用组装飞船的最小包裹圆的半径即可
- m就是总质量,理论上物体的质量分布会影响惯量,但这里我们进行简化,直接取总质量Ma即可
如上,就是I的精细设计方向,可以让组装有符合直觉的隐形影响,同时,自然地达成大船转的慢这点。
5.总姿态推力力矩Tmax
和惯量一起决定了最大角加速度Aθ=Tmax/I。这里的力矩可以简化为根据组装时的引擎情况来决定,可以精细也可以粗犷,丰俭由人。对我们游戏来说,因为当前单位旋转的重要性没有那么高,因此暂时简化设计,例如姿态力矩Tmax = 总推力Fa的百分比。也就是引擎装的多这个也高。
这个参数可以默认对玩家隐藏,但可以有这个空间,给到不同的机动组件不同风格,比如机械腿,这个就贼大,来表达转向快之类的。
6.比较重要的衍生参数
最大理论速度Vmax 由推力质量以及阻尼系数,共同计算出来的最大速度,每张地图都有可能不同
最大线加速度Amax 由Fa/Ma直接得来
最大角加速度Aθ Aθ=Tmax/I
操控层
操控层如下:
1.计算目标速度差(向量)
左边的摇杆来控制机动,左摇杆坐标:s = (sx, sy) ∈ [-1,1]²
摇杆有死区设定,若 |s| < deadzone,则视为 0,防止抖动,具体比例可配
设摇杆的输入向量为V_in,以及当前飞船的速度V_current
将V_in的模长设定为,死区起点为|Vmin|,可配,摇杆拉到底设为最大速度的模|Vmax|。先用线性变化,后续可以优化成立方曲线或自定义曲线,手感会更好
最终得出一个目标速度V_target,方向没变,大小变成了上一行所算的大小
然后,当前的速度向量差Δv = V_target - V_current
2.计算目标加速度
计算Δv的绝对值,来跟最大速度比,来实现根据速度差距,用不同加速度加速,可以防止最后的抖动,设最大加速度阈值比例Smax,最小Smin
|Δv|> Smax * Vmax 时,直接用 Amax,注意,如果组件破坏质量要动态变化,则Amax要重新更新
|Vd|< Smin * Vmax 时,用一个Amin,Amin可以直接配置
Smin * Vmax <|Vd|< Smax * Vmax 时,Amin,Amax间线性变化即可。
最后得出一个 A_target,也就是达成上述速度变化的一个目标加速度
3.赋力
然后速度部分最后一步,目标力F_target = Ma * A_target。同样注意Ma为当前的质量,unity直接赋予这个力就行。
4.飞船朝向
在目标速度V_target和当前速度V_current间插值,来留出调不同风格手感船的空间
目标朝向方向d_face = normalize( lerp(normalize(v_current), normalize(v_target), k_face) )。k_face可配
然后取飞船当前的朝向向量 ship_forward
算出角度差,同样可以算出角加速度需求,然后和线速度类似,设两个角度阈值,θmin,θmax。
大于θmax直接用最大角速度Aθ,小于θmin则用一个最小角加速度Aθmin,可配;两者之间则插值,来防止抖动。
最后也用这个算出来的目标角加速度,用unity赋予飞船,同样注意飞船质量变化带来的影响。
四、总结
以上是最近的思考结果,初步思路先记录一下,还不是很成熟,还需持续落地迭代,欢迎大家交流斧正。
相关阅读:
如何真正达成UGC,可玩编辑器思考
关于FPS的随想记录:信息、技巧和枪械
破坏深入做机制代价太大?游戏破坏设计实践复盘
游戏设计思考:核心玩法的立项
【万字长文】新手游戏设计师进阶指南
游戏设计左道:如何塑造鲜活NPC?
游戏中的破坏设计思考:涌现与复杂设计
游戏制作的基石——工程能力
游戏设计左道:匹配机制Elo系统与Trueskill系统原理研究
游戏设计终极问题的半个答案-赛季
文/余田
来源:鱼塘游戏制作工坊
|
|