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

Exercises

Six game dev exercises: physics loop, AABB collision, FSM, pooling, A* pathfinding, save/load.

Game dev — exercises

EXAMPLE
// ===== Exercise 1: fixed-timestep loop =====
const STEP = 1 / 60;
let acc = 0, last = performance.now();
let ball = { x: 100, y: 100, vx: 200, vy: -150 };

function frame(now) {
  const dt = Math.min(0.25, (now - last) / 1000); last = now;
  acc += dt;
  while (acc >= STEP) {
    ball.x += ball.vx * STEP;
    ball.y += ball.vy * STEP;
    ball.vy += 600 * STEP;  // gravity
    if (ball.y > 500) { ball.y = 500; ball.vy *= -0.9; }  // bounce
    acc -= STEP;
  }
  // render(ball, acc / STEP)
  requestAnimationFrame(frame);
}
requestAnimationFrame(frame);

// ===== Exercise 2: AABB collision =====
function aabbOverlap(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;
}

const box1 = { x: 100, y: 100, w: 50, h: 50 };
const box2 = { x: 120, y: 120, w: 50, h: 50 };
console.log(aabbOverlap(box1, box2));  // true

// ===== Exercise 3: simple FSM (enemy AI) =====
class Enemy {
  constructor() { this.state = 'patrol'; this.hp = 100; }
  update(player) {
    if (this.state === 'patrol') {
      if (distance(this, player) < 100) this.state = 'chase';
    } else if (this.state === 'chase') {
      if (distance(this, player) < 30) this.state = 'attack';
      if (this.hp < 20) this.state = 'flee';
    } else if (this.state === 'attack') {
      if (this.hp < 20) this.state = 'flee';
      if (distance(this, player) > 50) this.state = 'chase';
    } else if (this.state === 'flee') {
      if (this.hp > 80) this.state = 'patrol';
    }
  }
}

// ===== Exercise 4: object pool =====
class Pool {
  constructor(create, reset, size) {
    this.create = create;
    this.reset = reset;
    this.free = [];
    for (let i = 0; i < size; i++) this.free.push(create());
  }
  acquire() {
    return this.free.length ? this.free.pop() : this.create();
  }
  release(obj) {
    this.reset(obj);
    this.free.push(obj);
  }
}

const bulletPool = new Pool(
  () => ({ x: 0, y: 0, alive: false }),
  (b) => { b.alive = false; },
  100,
);

// ===== Exercise 5: A* pathfinding =====
function aStar(start, end, neighbors, heuristic) {
  const open = new Map([[key(start), { node: start, g: 0, h: heuristic(start, end), parent: null }]]);
  const closed = new Set();

  while (open.size) {
    let curKey, cur;
    let minF = Infinity;
    for (const [k, v] of open) {
      if (v.g + v.h < minF) { minF = v.g + v.h; curKey = k; cur = v; }
    }
    if (key(cur.node) === key(end)) {
      const path = [];
      let p = cur;
      while (p) { path.push(p.node); p = p.parent; }
      return path.reverse();
    }
    open.delete(curKey); closed.add(curKey);
    for (const n of neighbors(cur.node)) {
      const k = key(n);
      if (closed.has(k)) continue;
      const g = cur.g + 1;
      const existing = open.get(k);
      if (!existing || g < existing.g) {
        open.set(k, { node: n, g, h: heuristic(n, end), parent: cur });
      }
    }
  }
  return null;
}
function key(n) { return n.x + ',' + n.y; }

// ===== Exercise 6: save/load via localStorage =====
function save(state) {
  localStorage.setItem('save', JSON.stringify(state));
}
function load() {
  const s = localStorage.getItem('save');
  return s ? JSON.parse(s) : null;
}

// ===== Patterns =====
// - Fixed timestep + accumulator
// - AABB for cheap rect collision
// - FSM for enemy AI; behaviour trees for richer
// - Object pools for bullets / particles
// - A* for grid pathfinding
// - Serialise state to localStorage / IndexedDB

// ===== Pitfalls =====
// - Frame-locked physics (movement * dt not constant)
// - Forgetting to clamp dt -> simulation explodes after tab returns
// - Pools without reset -> stale data persists
// - A* without consistent heuristic -> sub-optimal paths

Why it matters

Six game dev exercises drill the daily patterns: fixed timestep loop, AABB collision, FSM, object pool, A*, save/load. The same patterns port across Unity / Godot / Phaser / Bevy — only the surface API changes.

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

Example

Example
// Fill in: player.x += speed * ____
Try it Yourself »

Discussion

Loading…