iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Cheatsheet

A printable game development cheatsheet: game loop, fixed timestep, collision, input mapping, and the smallest snippets to get each working.

Game dev — printable cheatsheet

EXAMPLE
// ===== The game loop =====
// Naive (frame-locked):
//   while (running) { input(); update(dt); render(); }
//
// Fixed timestep (decouples physics from render):
let lastTime = performance.now();
let acc = 0;
const STEP = 1 / 60;             // 60 Hz physics
function frame(now) {
  const dt = Math.min(0.25, (now - lastTime) / 1000);   // clamp big stalls
  lastTime = now;
  acc += dt;
  while (acc >= STEP) { update(STEP); acc -= STEP; }
  const alpha = acc / STEP;
  render(alpha);                 // interpolate render between physics steps
  requestAnimationFrame(frame);
}
requestAnimationFrame(frame);

// ===== Vec2 quick math =====
const v = (x, y) => ({ x, y });
const add = (a, b) => v(a.x + b.x, a.y + b.y);
const sub = (a, b) => v(a.x - b.x, a.y - b.y);
const mul = (a, s) => v(a.x * s, a.y * s);
const len = (a) => Math.hypot(a.x, a.y);
const norm = (a) => { const L = len(a) || 1; return v(a.x / L, a.y / L); };
const dot = (a, b) => a.x * b.x + a.y * b.y;

// ===== AABB collision =====
function aabb(a, b) {
  return a.x < b.x + b.w && a.x + a.w > b.x &&
         a.y < b.y + b.h && a.y + a.h > b.y;
}

// ===== Circle vs circle =====
function circ(a, b) {
  const r = a.r + b.r;
  return (a.x - b.x) ** 2 + (a.y - b.y) ** 2 <= r * r;
}

// ===== Input mapping =====
const keys = new Set();
addEventListener('keydown', e => keys.add(e.code));
addEventListener('keyup',   e => keys.delete(e.code));
function axis(neg, pos) { return (keys.has(pos) ? 1 : 0) - (keys.has(neg) ? 1 : 0); }
// move: const vx = axis('ArrowLeft', 'ArrowRight'); const vy = axis('ArrowUp', 'ArrowDown');

// ===== Spatial partition (grid) =====
class Grid {
  constructor(cell) { this.cell = cell; this.map = new Map(); }
  key(x, y) { return ((x / this.cell) | 0) + ',' + ((y / this.cell) | 0); }
  insert(o) {
    const k = this.key(o.x, o.y);
    if (!this.map.has(k)) this.map.set(k, []);
    this.map.get(k).push(o);
  }
  near(o) {
    const cx = (o.x / this.cell) | 0, cy = (o.y / this.cell) | 0;
    const out = [];
    for (let dy = -1; dy <= 1; dy++)
      for (let dx = -1; dx <= 1; dx++) {
        const list = this.map.get((cx + dx) + ',' + (cy + dy));
        if (list) out.push(...list);
      }
    return out;
  }
}

// ===== Easings =====
const easeOutCubic  = t => 1 - (1 - t) ** 3;
const easeInOutQuad = t => t < 0.5 ? 2 * t * t : 1 - (-2 * t + 2) ** 2 / 2;

// ===== Sound (Web Audio) =====
const audio = new AudioContext();
async function load(url) {
  const buf = await fetch(url).then(r => r.arrayBuffer());
  return audio.decodeAudioData(buf);
}
function play(buffer, vol = 1) {
  const src = audio.createBufferSource();
  const gain = audio.createGain();
  gain.gain.value = vol;
  src.buffer = buffer; src.connect(gain).connect(audio.destination); src.start();
}

// ===== Pitfalls =====
// - Frame-locked physics on uneven hardware -> jitter
// - Using deltaTime without clamping the big stall after tab returns
// - O(N^2) collisions on large worlds -> use a grid or quadtree
// - Audio without user gesture -> blocked on web (resume() after a click)
// - Floating-point comparisons for grid keys -> bugs at cell boundaries

Why it matters

Pin the cheatsheet, drill the fixed-timestep loop, and reach for spatial partitions before the world grows. The same skeleton ports across engines: physics on a tick, render with interpolation, input as discrete events.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
// Game loop | Delta time | Sprites | Input | Collisions | State machine | A*
Try it Yourself »

Discussion

Loading…