游戏车辆固定转向轨迹计算
概述
车辆游戏是我们经常接触到的一类游戏,这里游戏在只用键盘操作时,往往非常不方便。这是因为这一类游戏大部分都是按下按键时转向,释放按键时方向就会自动转正。这种控制方式在实现方面比较容易。但是缺点也很明显,就是无法像现实中开车一样,我固定一个转向角度来做圆周(圆弧)运动。对于在弯道时,键盘的操作体验非常糟糕。
所以,就想到,采用转向角度来控制车辆转弯,挡位来控制速度(包括前进和后退)。这样的话,当按下左键时,车辆将一直按照一个拐弯角度来运行,在按下其他键之前,车辆将一直进行圆周(圆弧)运动。这中操作方式和现实比较接近,就像我们开车转弯后,必须回正方向盘一样。但是这种的程序实现起来稍微复杂一些,经过研究,特此公布车辆轨迹计算方法。
效果
这是效果展示:
2023-04-27 10-17-43
计算
几何概念
这里仅考虑2D环境下,正如我另外一篇文章所述,三角函数的天然局限性并不能很好的满足在整个圆周下的相互计算。简言之就是在0到360度范围内,存在一个三角函数值对应2个角度的问题。故我们需要自己解决该问题,不能简单的利用三角函数反算。解决途径两种如下:
- 自己编写全角函数;
- 利用复数计算;
这两种方式的关键就是三角函数值不再用一个数字表示,而是采用两个数值表示。
位置计算
已知一个车辆的当前角度、转弯角度,和速度值,从理论来讲可以计算出它在任意时刻的准确位置和方向。
固定思维如下:
- 确定下一个位置刷新时间
- 利用速度和时间求导弧长
- 利用刷新时间求导刷新后转向角度
- 利用弧长和转向角度、起始点位置、当前角度求导圆形、圆形角,进而确定下一个刷新位置的坐标和旋转角度
上述步骤虽说可以求导,但是步骤还是非常麻烦的。同时涉及计算绘图坐标系和笛卡尔坐标系的不同,非常容易计算出错或者混乱。
除了这个因素外,位置刷新的时间往往非常短,要计算弧长需要更高精度的浮点运算才能满足。这可能也是大部分赛车游戏直接采用按下转向、释放回正的最直接原因。
这种简单的处理方式也有好处,那就是当车辆转弯的需要的角度后,释放按键,车辆就会保持这个角度走直线。所以虽然简单处理,但是对游戏的趣味性影响较小。
解决思路
思路一,提高程序计算能力,利用上面1到4步骤分别计算获得下一坐标点。
思路二,简化掉中间计算步骤,直接利用输入、输出关系自制函数。
这里就介绍以下研究了很久之后的解决知道,效果见上面。
【重点】
车辆的屏幕上的正确像素位移速度我们计算起来较为困难,但是我们知道不论是逻辑速度,还是像素位移速度,都和位移对应的圆心角成反比。即速度越大,转弯半径越大,对应的圆心角越小。
车辆的起始角度加上对应的圆形角的正弦值与y方向的偏移量成正比,余弦值与x方向的偏移量。
速度与弦长成正比。
//! [4]方向
setRotation(tankRotation);
//! [4]
//! [5]
// 计算车轮转交下偏移量
tankRotation += tankTurnRadians;
tankBarrelDirection += tankTurnRadians;
//TODO 让上面两个变量在[0..260)之间
if (tankRotation < 0) tankRotation += 360;
if (tankRotation >= 360) tankRotation -= 360;
if (tankBarrelDirection < 0) tankBarrelDirection += 360;
if (tankBarrelDirection >= 360) tankBarrelDirection -= 360;
qDebug()<<"tankRotation:"<<tankRotation;
//! [5]
//! [7]移动
QPointF newPos;
if (tankSpeed > 0.0){
newPos = this->pos() + Circlemetric::DegreesToPoint(tankRotation - 90) * tankSpeed;
setPos(newPos);
}else if (tankSpeed < 0.0){
newPos = this->pos() + Circlemetric::DegreesToPoint(tankRotation - 90) * tankSpeed;
setPos(newPos);
}
[4]中已经设置了item的旋转,所以车辆的转向直接累加车辆转角即可。
[7]中的Circlemetric::DegreesToPoint是自己编写的全角函数,是用一个点(x,y)来一一对应0到360度的角度。
可以看出只通过简单的计算就可以得到车辆的新位置和新转角。
那么这种计算出来的转交或者方向大小不满足自己需要怎么办?很简单,您只要添加相应的系数即可。
因为本来在游戏中,如果你要100%的模拟是非常困难的。即便你计算的再正确,也未必能得到预期的结果。
那我们为什么不通过主要关系,建立简单的运算,通过调整固定参数,来达到自己想要的效果呢?
事实证明,这种简算不但简化了程序,而且通过系数的调整,所得到的效果并不亚于复杂的计算!
进阶
车辆的速度并不是线性关系,更多地是接近与对数关系。举例说明:
1档——10km/h
2档——20km/h
3档——30km/h
4档——40km/h
5档——50km/h
上述对应关系是和实际不同地。这里我采用了指数函数,需要更详细速度效果地可以直接采用真实车辆地挡位和速度对应关系。
尾记
欢迎大家转发、打赏。