在研究《侠盗猎车手IV》和《侠盗猎车手5》以外的其他游戏时,我遇到了这个(旧的)问题,但是我有一个不错的答案来实现可控的过度转向。我只对《侠盗猎车手5》中的驾驶模型有所了解,但是该信息应适用于大多数实际驾驶模型。
在大多数驾驶游戏中似乎发生的情况是,即使使用某种(时间)平滑功能,汽车转向输出也直接与玩家输入相关联。这会导致呆滞或生涩的感觉-放开控件后,汽车无法自行校正。这与真实的汽车相反,在真实的汽车中,在释放方向盘上的力后,汽车趋于居中。一些游戏试图通过更改其处理模型或使用街机处理模型来纠正此问题。
在侠盗猎车手V中可以观察到的是,用户转向输入未直接链接到转向输出。车辆自身转向其当前速度矢量。当迫使轻微的过度转向情况并观察转向轮时,这是可见的-没有任何输入,它们自己反转向。然后,在这些“自然”更正之上添加任何用户输入。
但是,这种方法的缺点是,汽车感觉太粘且有些固执,无法滑入大功率滑行或漂移中-因此此反转向值可以限制在某个角度。
可以通过重新实施转向系统并将其与原始行为进行比较来验证该理论。
- 当直接将输入链接到输出时,即使应用了基于速度的转向输入限制器,车辆的确也确实很难控制。
- 当添加自然反向转向时,其行为与游戏的实现几乎相同,但是汽车“过于”稳定。
- 当将15度限制添加到反转向时,其行为几乎相同。
要记住的一点是,侠盗猎车手V在这里被视为“理想”,尽管我还没有找到其他实现该系统的游戏。
如果您对某些代码感到好奇,这是我的实现的摘要。
// Returns in radians
float Racer_calculateDesiredHeading(float steeringMax, float desiredHeading,
float reduction) {
desiredHeading *= reduction;
float correction = desiredHeading;
// Get the relative velocity vector
Vector3 speedVector = ENTITY::GET_ENTITY_SPEED_VECTOR(vehicle, true);
if (abs(speedVector.y) > 3.0f) {
// Simplify it to an angle
Vector3 target = Normalize(speedVector);
float travelDir = atan2(target.y, target.x) - static_cast<float>(M_PI) / 2.0f;
if (travelDir > static_cast<float>(M_PI) / 2.0f) {
travelDir -= static_cast<float>(M_PI);
}
if (travelDir < -static_cast<float>(M_PI) / 2.0f) {
travelDir += static_cast<float>(M_PI);
}
// Correct for reverse
travelDir *= sgn(speedVector.y);
// Limit to some degree, R* uses 15 degrees
travelDir = std::clamp(travelDir, deg2rad(-15.0f), deg2rad(15.0f));
// User input deviation
correction = travelDir + desiredHeading;
}
return std::clamp(correction, -steeringMax, steeringMax);
}