When developing mobile casual games, player retention hinges heavily on tactile responsiveness: the physics must feel snappy, tactile, and strictly deterministic across low-end Android handsets and flagship iPhones alike.
In this inaugural devlog for Crown Match Royale, we break down the challenges of maintaining a rock-solid 60 FPS update loop while running complex multi-body collision calculations.
The Challenge: Variable Frame Timers on Android
Android devices operate across hundreds of distinct chipsets and refresh rates (60 Hz, 90 Hz, 120 Hz). If you tie collision detection directly to requestAnimationFrame or the engine’s render loop, higher refresh rates will inadvertently accelerate game physics, or lower-tier devices will drop inputs.
To solve this, we decoupled our rendering ticks from the physics step using a fixed delta time accumulator pattern:
const FIXED_STEP = 1 / 60; // 16.66ms per physics step
let accumulator = 0;
function updateGame(currentTime, lastTime) {
const frameDuration = Math.min((currentTime - lastTime) / 1000, 0.25);
accumulator += frameDuration;
while (accumulator >= FIXED_STEP) {
physicsEngine.step(FIXED_STEP);
accumulator -= FIXED_STEP;
}
}
Spatial Partitioning for Micro-Collisions
Instead of evaluating $O(n^2)$ pair collisions across all falling gems and crown obstacles, we implemented a 2D spatial grid hash. Every falling entity registers its bounding box into an $8 \times 8$ grid bucket. Collision checks only occur between objects sharing the same active cell.
The result? CPU cycle time during burst cascades dropped by 68%, ensuring smooth 60 FPS animations on devices as modest as 2 GB RAM Android phones.
Stay Updated
Crown Match Royale is currently in closed testing on Google Play. Follow our devlog series here on GeekyOrg as we prepare for global open beta!