Engineering a 240Hz Deterministic Physics Engine in Pure Swift for iOS 17
When building Velocity Unleashed, one of our uncompromising engineering constraints was ensuring that driving at 285+ MPH felt visceral, precise, and completely free of physics stutter or collision tunneling.
Most mobile games rely on standard variable delta time ($dt$) tied directly to the display frame rate (30, 60, or 120 FPS). But at supersonic racing speeds, variable $dt$ introduces non-deterministic tire slip, erratic barrier bounces, and floating-point divergence between devices.
Here is how we architected a deterministic 240Hz fixed-step physics engine in pure Swift 5.9 leveraging SIMD vector math on Apple Silicon.
Why 60Hz Variable Time Fails at 285 MPH
- At 285 MPH (127.4 m/s), a vehicle travels over 2.12 meters per frame at 60 FPS. If a physics step only evaluates once every 16.6ms:
- A car can tunnel completely through thin track barriers or rumble strips before collision detection registers
- High-frequency suspension dampers and anti-roll bars oscillate out of control, causing vehicles to launch violently into the air
- Multiplayer ghost replays and leaderboards fail to reproduce identically across different hardware
To solve this, we decoupled rendering from simulation using a 240Hz fixed-clock time accumulator (FixedStepClock.swift). At 240Hz, the simulation steps forward every 4.166 milliseconds, reducing travel distance to just 0.53 meters per tick.
---
1. The Fixed-Step Accumulator (`FixedStepClock.swift`)
The game loop captures elapsed real time from the display CADisplayLink / SceneKit renderer and feeds it into an accumulator buffer. The engine consumes fixed $dt = 1/240$ slices until the accumulated time is depleted.
public final class FixedStepClock {
public static let targetFrequency: Double = 240.0
public static let fixedDeltaTime: Float = 1.0 / Float(targetFrequency) // 0.0041667s
private var accumulatedTime: Double = 0.0
private let maxAccumulatedTime: Double = 0.1 // Clamps spiral of death
public func advance(realDeltaTime: Double, tick: (Float) -> Void) -> Float {
accumulatedTime += min(realDeltaTime, maxAccumulatedTime)
while accumulatedTime >= Double(Self.fixedDeltaTime) {
tick(Self.fixedDeltaTime)
accumulatedTime -= Double(Self.fixedDeltaTime)
}
// Alpha interpolation factor for sub-frame smooth rendering
return Float(accumulatedTime / Double(Self.fixedDeltaTime))
}
}Alpha State Interpolation Even when the physics runs at 240Hz, rendering on an iPhone ProMotion display occurs at 120Hz or 60Hz. To eliminate micro-jitter between physical ticks and visual frames, we perform linear state interpolation (alpha in [0, 1]):
visualPosition = simd_mix(previousPhysicsPosition, currentPhysicsPosition, alpha)
visualRotation = simd_slerp(previousPhysicsRotation, currentPhysicsRotation, alpha)This guarantees butter-smooth rendering without sacrificing physical determinism.
---
2. Pacejka Magic Formula Tire Dynamics (`VehicleDynamics.swift`)
Real racing dynamics live or die by the tire contact patch. Rather than using simplified arcade raycast grip, we implemented a modified Pacejka Magic Formula curve:
$$F_y = D \cdot \sin(C \cdot \arctan(B\alpha - E(B\alpha - \arctan(B\alpha))))$$
- Where:
- alpha: Lateral tire slip angle
- B: Stiffness factor (governs initial steering bite on turn-in)
- C: Shape factor (determines the peak transition)
- D: Peak friction coefficient multiplied by normal load (Fz)
- E: Curvature factor (controls how grip falls off into a drift)
Grip Force (Fy)
▲ Peak Grip (Turn-in)
│ ╭──╮
Peak ┼──────────────╭╯ ╰─────────── Dynamic Slide Zone
│ ╭╯ (Controllable Counter-Steer)
│ ╭╯
│ ╭╯
│ ╭╯
0 ─────────┴─────────────────────► Slip Angle (α)Dynamic Weight Transfer As the driver brakes hard into a sharp chicane, inertia transfers mass forward across the suspension geometry:
let longitudinalAccel = (currentSpeed - previousSpeed) / dt
let pitchTransfer = (carMass * longitudinalAccel * centerOfGravityHeight) / wheelbase
let frontAxleLoad = (staticFrontLoad + pitchTransfer).clamped(min: 200, max: carMass * 0.85)
let rearAxleLoad = (staticRearLoad - pitchTransfer).clamped(min: 150, max: carMass * 0.85)This allows drivers to execute authentic trail braking — loading up the front tires to rotate the car into the apex before applying power.
---
3. Ground-Effect Aerodynamics & Slipstream Wakes
Modern open-wheel cars generate massive downforce through underfloor venturi tunnels. In Velocity Unleashed, downforce is calculated quadratically:
$$F_{\text{downforce}} = \frac{1}{2} \rho \cdot v^2 \cdot C_L \cdot A$$
- Ground Effect Compression: As the car compresses on high-speed banked turns, ride height drops, multiplying $C_L$ by up to 1.45x.
- High-Speed Stability: At 250+ MPH, total downforce exceeds 1,250 kg — more than the car's weight — giving incredible grip in high-speed sweepers.
The 3D Slipstream Vortex Cone Behind each AI and player car, we compute a real-time turbulent wake cone:
let distanceToLeader = simd_length(leaderPos - followerPos)if forwardDot > 0.92 && distanceToLeader < 45.0 { let wakeIntensity = (1.0 - (distanceToLeader / 45.0)) * forwardDot dragCoefficient *= (1.0 - (wakeIntensity * 0.38)) // 38% drag reduction drsRechargeRate += wakeIntensity * 1.5 // Charges nitro/KERS } ```
Tucking behind an opponent cuts aerodynamic drag by up to 38%, creating massive slingshot overtaking opportunities down the main straights.
---
4. Sub-Millisecond SIMD Execution on Apple Silicon
A physics engine running 240 times per second must execute in under 1.0 millisecond per tick to prevent frame drops.
- 1To achieve this in Swift 5.9:
- 2Zero Heap Allocations in Tick Loop: All vehicle states, raycasts, and force accumulators use stack-allocated Swift structs with no reference-type overhead.
- 3Apple SIMD Accelerated Vectors: We use `simd_float3`, `simd_quatf`, and `simd_float4x4` directly, compiling down to hardware NEON vector instructions.
- 4No Dynamic Dispatch: Physics methods are marked `final` and marked for aggressive compiler inlining (`@inline(__always)`).
Benchmarked Execution Time On an Apple A17 Pro (iPhone 15 Pro), our entire 240Hz physics update for a 6-car race grid completes in just **0.28 milliseconds** per step:
- Raycast Ground Probing: 0.08 ms at 240 Hz
- Tire Slip & Pacejka Model: 0.06 ms at 240 Hz
- Aerodynamics & Aero Wakes: 0.04 ms at 240 Hz
- Collision & Barrier Resolvers: 0.07 ms at 240 Hz
- State Integration & Clock: 0.03 ms at 240 Hz
- Total Simulation Step: 0.28 ms (Comfortably under 4.16ms budget)
---
Conclusion: Crafting Console-Grade Mobile Racing
By uniting a deterministic 240Hz fixed-step clock, true Pacejka tire friction, ground-effect aerodynamics, and hardware SIMD vectors, Velocity Unleashed delivers high-fidelity handling that rewards skill and racecraft.
Experience the physics for yourself: Download Velocity Unleashed free on the App Store →


Community Responses0
No comments yet.
Be the first to share your thoughts on this dev log!