Tank!
Tank!
坦克暂时告一段落,做坦克以及吉普等其他物理载具的过程中,遇到了很多问题,也积累了一些经验,记录下来,算是一个交代。
坦克需要实现业务功能
- 载人
- 撞人、撞树
- 开火,炮筒、炮台转动
- 相机,Free Camera
- 遥感移动,非常复杂的移动逻辑…
- 除了这些业务逻辑,我们要做的真实感的坦克,坦克底层的物理(PhysXVehicle)是最困难的部分
- 网络同步
- AI
载人
在车门附近配置 volumes,车门挂载socket等,触发上车逻辑,这个很常规,
玩家上车之后,玩家的物理和载具的物理穿透的话,会出现很诡异的物理现象,坦克飞在天上,等等,我们处理的办法就是在上车之后关闭掉玩家和载具的物理交互,
下车通过射线等检测玩家落脚点,这一步没有难点;
撞人、撞树
撞人的难点是载具移动速度快的时候,车在撞人的一刹那有撞到墙的感觉,然后人死,整个过程是不流程的,
我们的解决办法是在坦克身上挂载一个 Box,根据载具的速度动态控制 Box size,然后根据 Overlap 事件来判断撞人,这个 Box 是比坦克本省大一些的,这样的话就避免了我们刚才说的问题。
撞树等障碍物的时候,有撞到墙的感觉是正常的,我们没有特殊处理,但是会动态的移除树木、篱笆等障碍物,保证坦克开起来比较顺畅。
需要注意的是,我们在处理撞人的时候,使用 RingBuffer 记录坦克坐标,来检测坦克是否 AtRest,作为撞人的一个条件之一。
开火,炮筒、炮台转动
这一步核心点是 IK 动画以及开火后坐力效果,IK 动画控制炮筒和炮台的旋转,
注意如果想单纯的由 IK 动画来控制,记得移除(关闭)炮台和炮筒身上的Physics Asset,只保留底座的 Assset,因为 IK 和物理不能同时控制一个骨骼节点。开火后坐力实现比较简单,给坦克底座添加一个反方向的力即可。
相机,Free Camera 等
这一步难点是,我们的相机会根据炮台和炮筒来控制旋转和坐标,据我所知,是没办法直接使用 UE 的CameraController 的,我自己写了一个独立的 Camera Component,处理坦克的相机需求,
核心点就是平滑输入,UI 层屏幕滑动输入是不平滑的,断断续续,我们首先插值玩家输入,然后根据炮筒和炮台的旋转(Yaw&Pitch)计算 Camera 的 位置和朝向,这里要注意的就是0-360边界的问题,我是用 Quaternion 计算差值来避免这个问题。
遥感移动,复杂的移动逻辑…
第一步,坦克炮筒本身分离,有两个控制维度,一个是镜头、一个AI根据底座的转向控制;
玩家输入方向,镜头方向映射移动方向,判断坦克转向逻辑,计算坦克是车头还是车尾、顺时针还是逆时针、给油还是给刹车,然后对坦克履带施加力,希望坦克精准移动到目标方向;这是第二步
最难是第三步,
因为坦克本身惯性,比如坦克在高速前进时候玩家输入转向,策划希望如果方向大致一致的情况下,坦克不减速,惯性就很大、以及上坡坡度很大的时候滑坡这个是最难的等,坦克在坡上的时候,AI 很难精准控制目标方向,需要写很多逻辑驱动AI,然后暴露很多参数,调节参数;
因为影响坦克的参数(包括物理参数)特别多,所以这个优化起来就很费劲;
最后优化来优化去,加了误差之后比如10度,我们勉强可以达到策划的要求,在坡上也可以自由转向移动到我们的目标点。
坦克底层的物理(PhysXVehicle)
我们先大致讲一下 vehicle 的底层结构
- Vehicle Manager
- Vehicle Data Struct
- Vehicle Raw Input
- Vehicle Wheels Animation
Vehicle Manager
VehicleManager,负责管理 Vehicle,管理 vechile 的 PreTick、Tick、PostTick,包括更新 Wheels 的 WheelState,比如 LocalPose、SteerAngle等等。
- PxVehicleSuspensionRaycasts
- PxVehicleUpdates
Vehicle Data Struct
- VehicleEngineData MaxRPM、MOI、TorqueCurve…
- VehicleGearboxData UpRatio、DownRatio、SwitchTime…
- VehicleWheelData Radius、Width、DampingRate、Mass、MaxSteer…
- VehicleSuspensionData MaxDroop、MaxCompression、SpringStrength…
- VehicleCluthData??
- VehicleWheelAnimData BoneName、LocalPose…
Vehicle Raw Input
Throttle、Brake、Steer、Clutch…
Vehicle Wheels Animation
Wheel 在初始化的时候通过Vehicle Manager 绑定,保证一一对应,然后每一帧根据轮胎的 Index 获取 Wheel LocalPose,在 AnimNode 里渲染。
参数调整
我们在做坦克的过程中,遇到了很多奇怪的问题,比如坦克在撞击有些障碍物的时候会突然有奇怪的表现,坦克被反弹甚至击飞,后来我们发现这可能是UE的一个bug。
如果障碍物设置为 BlockAll,但是障碍物的碰撞盒没有设置,载具撞击上障碍物的时候就会表现很奇怪,我们的解决办法是要求美术同事把所有需要设置 Block 的物件都一定要设置对应的 CollisionBox。
我们还遇到坦克在撞击到时候会原地旋转,速度很快,经过无数次测试发现是因为我们修改 physx 数学库导致的…血的教训。
关于坦克的爬坡能力,最重要的是坦克自身的 Physics Asset,一定要注意和地面的碰撞,以及轮胎的半径。
然后就是轮胎力矩和坦克马力比例,保证爬坡时力矩的数值。
第三点要注意档位的变换,在爬坡时调节 GearboxData 的 SwitchTime 尽量保证档位不要快速切换,让坦克在低档爬坡。
其他的比如摩擦力等,但是不要一味的调大,过大的摩擦力会导致坦克启动的时候抖动,因为摩擦力太大了,启动困难。
还有其他的小细节,比如坦克的 SpringStrength,保证坦克在坡面的抖动效果,轮胎履带通过设置 UV 滚动来实现,轮胎压过地面的痕迹通过 Decal 实现等。
网络同步
这个比较常规,预测和插值,预测的时间根据坦克的速度以及 Ping 调节。
炮台和炮筒的旋转和移动包一起,每0.1s同步一次,插值保证平滑。
AI
坦克在复杂地形上移动很复杂,关于AI部分,我后续更新…
感谢阅读。
更多细节
physx Vehicles