游戏中,经常会出现qte的时候,需要玩家狂点某个键:
通常这种功能实现和判断办法有2种:
(相关资料图)
累加判断。
在规定的时间内按满多少次:
通常规定时间会比较短,这样能保证玩家的按键频率一定是高的。
变体:只记录距离上下两次的平均dt<a的按键进入累加计数。这种适用于判定时间较长,但是又要求玩家高频点击的情况(比如动画的时间比较长,所以出现了这种情况)
2.高频连续时间判断
跟上面的变体类似,不过这回判断的是高频连续时间,也就是说中间不能“慢”,“断”,即不能出现突然低频的情况。一旦断了就结束这段时间的累加,或者严格的游戏会直接结束QTE。
PS:值得注意的是由于首尾点没有前/后点,所以频率可以丢弃或者和前/后相等。类似多点曲线插值的切线方向。
但都不太适合我。我需要一个特殊的狂点机制,又能表现双方对决时互相顶撞的力度感:
于是我想到了冲击函数和指数衰减。由于有指数衰减的存在,玩家的点击必须高频,才能使留存值增加到1。一旦低频,先前的贡献会随着时间流逝而衰减。指数衰减又能保证在留存值非常低的情况下会衰减得很慢,保证玩家在极端劣势的情况下仍有一线生机。
由于这个系统类似燃料箱,我们的冲击相当于瞬时添加燃料,而燃料以指数衰减。所以接下来简称这个系统为impulseTank。它的燃料留存初始值为y0,最大值为1,最小值为0。
实现细节:
第一:使用递推式而非解析式。
解析式是:y=y0*e^(-a*t) 。
其中y0是初始留存值,e是自然常数e,a是衰减系数,t是当前系统时间,y是当前留存值。
可以看出,当t=0,y=y0,当t->∞,y->0。a越大,衰减越快。
为什么不用解析式?
不方便编程。玩家可能暂停游戏,继续游戏。而且我也希望这个impulseTank的更新频率能够手动控制,类似一个物理模拟的物理帧数可以自己设置30PS/60FPS....不管怎么说都是递推式方便。
递推式推导:
y1 = y0*e^(-at)
y2 = y0^e(-a*(t+dt))
=y1*e^(-a*dt)
所以每次更新的代码就是:
第二,自定义物理帧一定要注意的问题。
这段代码的:
我原先写成了
这样会漏掉了微小的时间差,因为不能保证t_update到时候会正好累加成interval_update。
对于其他功能,这点极小时间差也许不影响功能,但在这里影响了。因为tank里是累加的。这个错误最终导致我在Play Focus和Play Maximum的时候,狂点之后留存值y不同。因为Play Focus和Play Maximum的帧率不同,导致了微小的时间差的不同,累计之后就会出现比较大的不同,即在高屏幕帧率下累计的y少于低屏幕帧率的y,即便都是同一个tank,同一个物理模拟帧率。
最终效果:
标签: