Survive the collision before the pass

An obstacle can cross the player between updates and still earn a pass in a faulty game. This simple racing game JavaScript prototype uses small simulation steps and collision-first resolution, so reaching the end of the road is not enough to count as safe.

Play a three-lane course with three scheduled rectangle obstacles, or use the inspection buttons to compare two repeatable routes. Start begins in lane 1; Left and Right move one lane per activation. The inspectable avoidance trace stays in lane 1 until 4 seconds, moves to lane 0, and finishes with three passes at 7.5 simulation seconds. Its separate no-move trace loses on O2 at 4.26 seconds.

Survive the collision before the pass
Survive the collision before the pass
Open the full example ↗

Define coordinates before movement

Lane indices are 0, 1 and 2, with centers x=70, 160 and 250. The player is 24 pixels wide and 40 high, centered on the selected lane, with fixed top y=180. It starts in lane 1, so its rectangle is x=148–172 and y=180–220.

Obstacles use the same 24 × 40 dimensions. They start at top y=−40 and move down at 80 logical pixels per simulation second.

ID Lane Spawn time Initial top
O1 0 0 seconds −40
O2 1 2 seconds −40
O3 2 4 seconds −40

Each Reset restores the same three obstacle IDs and spawn schedule. All positions are logical drawing coordinates, not miles per hour or a claim about an actual road.

The game moves through Ready, Running, Paused, Lost, and Finished states. Start works only from Ready, establishes time zero and spawns O1. Repeated Start cannot duplicate the obstacle schedule.

Require strict overlap on both axes

MDN describes axis-aligned rectangular hitboxes. The game uses that overlap relationship for its player and obstacle rectangles. MDN: 2D Collision Detection

In this model, contact at a border alone is not a hit. Both horizontal and vertical intervals must overlap by a positive amount.

For the lane-1 player, a lane-1 obstacle at top 140 has bottom 180: it only touches the player's top and does not collide. At top 141, its y interval extends to 181, creating a one-pixel overlap and a hit.

An obstacle at top 220 only touches the player's bottom and does not collide. At top 219 it overlaps by one pixel. An obstacle in a different lane has no horizontal overlap, regardless of its vertical position.

Touching, overlap and lane choice are separate cases. The fixed-step implementation resolves positive overlap before awarding a pass.

Count a pass once and keep future spawns pending

An active obstacle whose top reaches 240 without a collision transitions once to Passed. Remove it from active collision tests and increment the pass count once. Its bottom leaving the road is not the criterion; its top reaching the lower boundary is.

O1 passes at t=3.5 if avoided, O2 at 5.5 and O3 at 7.5. Before t=4, O3 is still pending even if the screen has no active obstacles. Finish requires all three IDs spawned and passed, with no loss.

The avoidance inspection stays in lane 1 for O1, moves to lane 0 at t = 4 seconds before O2 reaches the player, and stays there for O3. Its update sequence reaches Finished with three passes at 7.5 seconds. Use it to understand the timing before trying the route with the movement buttons.

Remaining in lane 1 instead meets O2 when its top becomes greater than 140, just after t=4.25. The t=4.26 step gives top 140.8 and positive overlap, so the expected result is Lost. O2 cannot later earn a pass, and pending O3 cannot continue gameplay after terminal loss.

Play the bounded course

Use Start, then the Left and Right buttons or focused-region arrow keys. Lane changes are discrete, not a physical lateral driving model. Held key repeats do not keep moving the player; release before another activation. The visible lane number and obstacle records make the movement readable without relying only on the road drawing.

The single animation loop accumulates elapsed time in 0.01-second steps, with at most ten steps per frame. Excess elapsed time is discarded as a slowdown policy. Obstacles use scheduled simulation ticks and move 0.8 logical pixels per step, preventing a whole-road update from skipping the player.

Pause freezes simulation time, and Resume starts with a fresh timing stamp. Hiding the page or leaving the game region also pauses. Reset cancels the old callback generation and restores Ready, lane 1, zero passes and the original schedule.

The two inspection buttons run the same update function through the supplied traces synchronously. They are useful reproducible examples, separate from a person’s live play. Finished requires all three unique obstacle IDs passed; no empty interval before a future spawn can finish the course early. The drawing uses logical pixels, not real speed or driving ability.

Copy a prompt for this example

Build a single self-contained HTML three-lane avoidance game with embedded CSS and JavaScript. Draw a 320 by 240 logical road with lane centers at x = 70, 160, and 250. Use simple original rectangles and show game state, time, lane, passes, and pending obstacles as readable text.

The player is 24 by 40 pixels, with top y = 180 and initial lane 1. Obstacles have the same dimensions, begin at top y = -40, and move down at 80 logical pixels per simulation second. Schedule O1 in lane 0 at time 0, O2 in lane 1 at time 2, and O3 in lane 2 at time 4.

Advance through 0.01-second simulation steps, with at most ten steps per animation frame. Discard excess elapsed time as slowdown. A collision requires positive rectangle overlap on both axes; touching at an obstacle top of 140 or 220 is not a hit. Resolve collision before pass credit. An obstacle passes once when its top reaches 240. Finish only after all three unique obstacles pass.

Provide Start, Left, Right, Pause, Resume, and Reset. Focused arrow keys move one lane per fresh press. Pause on hiding or leaving the game region; resume with a fresh clock.

Include inspection buttons using the same updater. Staying in lane 1 until 4 seconds then moving left finishes at 7.5 seconds with three passes. Staying still loses on O2 at 4.26 seconds. Return only the complete HTML file.

For a collision-order review, NOS can display this prepared HTML course. Run the no-move trace, compare O2’s overlap with the avoided course, and compare those cases with the JavaScript update function before changing step size or adding obstacles.

Keep reading