Other Projects

Other interesting projects

Scroll to explore
Game · Physics & gameplay programming

Bounce NDS

BOUND is a physics platformer where you have no jump button: you move a ball left and right and wall-jump off surfaces, Mario-style, to reach the exit on the right of each stage. I wrote its physics engine — the vector math, the Ball, the gravity and acceleration integration, the AABB collision and the wall-jump — over ten hand-built stages that introduce bouncy pads, launchers, breakable stone and lethal bombs.

Role
Physics engine, vector math & Ball class, input/state, wall-jump
Team
NDS · with Junhyuk Cha (map system)
Context
DigiPen · 2019
Stack
JavaScript · p5.js v0.9.0 · p5.dom / p5.sound
Overview

No jump button — just a ball and the walls

The whole game is one verb: move the ball. Left and right arrows accelerate it, the walls bounce it, and the only way up is to wall-jump off a surface the way you would in a 2D Mario. Reach the right edge of the screen and the stage clears; fall off the bottom and you lose a life; R restarts the current stage.

Because there is no dedicated jump, every stage is really a physics puzzle: you read the geometry, build horizontal speed, and convert it into height by slamming into the right wall at the right moment. That made the feel of the simulation — gravity, top speeds, the bounce response — the actual gameplay, which is the part I owned.

Stage 1 — the opening room
Core — Physics engine

A small physics simulation, hand-written

01

Vector math from scratch

Everything sits on a custom _vec2 class — add / subtract / multiply / divide, length and angle, dot product, and in-place variants — so position, velocity, acceleration and gravity are all plain 2D vectors the rest of the engine composes.

02

Integration & clamping

The Ball integrates each frame: gravity adds a constant downward vector, input adds horizontal acceleration, then checkMaxSpeed clamps both axes to per-axis caps so the ball never outruns the collision test and tunnels through a block.

03

AABB broad phase

Collision first tests the ball against each block as an axis-aligned box, then decides whether it struck a vertical face, a horizontal face, or only a corner — routing each case to a different response so attached blocks do not double-resolve.

04

Corner case, literally

When the ball touches only a block corner, IsBallHitsEdge measures the distance from the ball centre to each of the four corners against its radius, and treats a corner hit as a top/bottom hit so the response stays stable on tight diagonal gaps.

Mechanic — Wall-jump

Turning a wall hit into a jump

The wall-jump is the signature move and the trickiest bit of the physics. On a side collision the ball is first pushed just outside the block to avoid resolving the same hit twice; then, if you are holding the arrow into the wall, wallJump fires: it reverses horizontal velocity and overshoots it to 1.5× the cap, kicks the ball upward, and steps the simulation forward until it is clear of geometry before settling into a clean launch velocity.

If you are not pressing into the wall, the engine instead arms a 100 ms window in which a press still counts as a wall-jump and simply reflects the horizontal velocity — the difference between a deliberate kick off the wall and an accidental bounce. The launcher and bouncy blocks reuse the same velocity plumbing: arrow blocks disable gravity and fling the ball horizontally at double speed, bouncy pads raise the vertical cap so the next bounce sends it higher.

Stage 5 — bouncy pads and a launcher
Content — Blocks & stages

Six block types, ten stages

Normal & stone

A normal block bounces the ball back at full vertical speed; a stone block bounces once and then breaks, splicing itself out of the level and triggering a redraw of the ball's trail so the map stays clean.

Bouncy & launchers

A bouncy block boosts the vertical speed cap for an extra-high rebound. Two launcher blocks — left-arrow and right-arrow — cut gravity and fling the ball horizontally at double speed until it lands again.

Bomb

The bomb block is instant death: any contact flips the game into an explosion state, costs a life, and restarts the stage — the hazard the late levels are built around.

Levels as grids

Each of the ten stages is authored as a 20×15 integer grid, where the value selects the block type and a sentinel marks the ball's spawn point. My teammate Junhyuk Cha built that map system and laid out the stages on top of the physics.

Stack

What it's built on

Engine
JavaScriptCustom _vec2 mathBall physicsAABB collision
Gameplay
Wall-jumpBlock interactionsState machine loop
Runtime
p5.js v0.9.0p5.dom.jsp5.sound.jsBrowser canvas
Delivery
Runs in the browserDeployed live on Bitbucket Pages
Early

Stage 1

A single open room that teaches the one rule: build speed and wall-jump your way to the exit on the right.

Stage 1
Mid

Stage 5

Bouncy pads and a launcher block start stacking the verbs, asking you to chain a boosted bounce into a horizontal fling.

Stage 5
Final

Stage 10

The last stage threads bomb blocks around the route to the exit — one wrong bounce ends the run.

Stage 10 — bomb blocks & the exit

My first game: a hand-written 2D physics engine — vectors, integration, AABB collision and the wall-jump — shipped in the browser with team NDS.