step method
Advances the bob and the recoil by one simulation step.
speed is the player's horizontal speed, and grounded whether their
feet are down: a weapon that keeps swaying while the player is in mid-air
is the detail that makes a jump feel weightless.
Implementation
void step(double dt, {required double speed, required bool grounded}) {
if (grounded && speed > 0.2) {
_bobPhase += dt * _bobSpeed * (speed / 6.0).clamp(0.3, 1.8);
_bobOffset = math.sin(_bobPhase) * _bobAmount;
} else {
// Eased back to centre rather than snapped: stopping dead mid-swing is
// more noticeable than the sway itself.
_bobOffset += (0.0 - _bobOffset) * easeFactor(8.0, dt);
}
if (_recoil > 0.0) {
_recoil -= _recoilRecovery * dt;
if (_recoil < 0.0) _recoil = 0.0;
}
_holder.setPosition(
_restPosition.x,
_restPosition.y + _bobOffset,
// Back towards the eye, and slightly up: a straight backwards kick reads
// as the weapon shrinking.
_restPosition.z + _recoil * _recoilKick,
);
_holder.setRotation(
Quaternion.axisAngle(Vector3(1.0, 0.0, 0.0), _recoil * 0.22),
);
}