Space Game — Team Bob
A walkthrough of three custom game levels built with the GameEngine framework, covering NPC interaction, invisible maze navigation, and a chase-and-survive AI challenge.
🚀 Space Adventure Game — CS111 Level Blogs
Explore how we applied CS111 concepts across all three levels of our adventure game:
| Level | Theme | Key Concepts |
|---|---|---|
| 🌌 Level 1 — Alien Planet | Astronaut meets Chill Guy NPC | Configuration objects, arrays as registries, && guards |
| 🧩 Level 2 — Alien Maze | Invisible maze, find R2 to escape | Factory pattern, ?? / ?. operators, fractional coordinates |
| 👾 Level 3 — Alien Chase | Survive 20 seconds from the alien | Chase AI vector math, concurrent loops, rage mode state machine |
Each blog traces every CS111 requirement — iteration, conditionals, data types, and operators — from where we first learned it in Trimester 1 (snake game or calculator) to how we applied it in the level code.
Quick Navigation
| 🚀 Level 1: Space Level | 🌀 Level 2: Alien Maze |
| 👾 Level 3: Alien Chase | 🎮 Play All Three |
About These Levels
Three custom levels were built using the GameEngine framework and exported from GameBuilder. Each level introduces a new mechanic — from basic NPC interaction to invisible maze navigation to a chase-and-survive AI challenge.
All three levels share the same alien planet backdrop and astronaut player sprite, but each one builds on the last with increasing complexity:
| # | Level | Core Mechanic |
|---|---|---|
| 1 | Space Level | NPC dialogue + level transition via continue = false |
| 2 | Alien Maze | Invisible barriers, red glow on collision, timed run |
| 3 | Alien Chase | Chase AI, survival countdown, rage speed, E-key restart |
Use the sections below to read how each level works, then run the embedded game-runner cells to play them directly in the browser.
Quick Controls Reference
| Level | Move | Interact |
|---|---|---|
| Space Level | ← ↑ → ↓ Arrow Keys | Walk into Chill Guy NPC |
| Alien Maze | W A S D | Walk to R2, press E |
| Alien Chase | W A S D | Press E near alien to restart after being caught |
Level 1: Space Level
An introductory level set on an alien planet. Navigate past a set of visible barriers to reach Chill Guy, who will send you to the next level.
How It Works
NPC Interaction and Level Transition
The Npc object (npcData1) overrides two callbacks that the engine calls at specific moments:
reaction()— fires every frame the player’s bounding box overlaps the NPC hitbox. Used here to display a dialogue line.interact()— fires when the player presses E within range. The key line is:
Challenge
Navigate the alien planet and interact with Chill Guy to advance to the next level. Use Arrow Keys to move.
Setting currentLevel.continue = false signals the GameControl loop to tear down the current level and advance to the next one in gameLevelClasses.
Barrier Layout
Five Barrier objects are placed using absolute pixel coordinates (x, y, width, height). They are marked visible: true so the player can see and navigate around them. The fromOverlay: true flag marks them as builder-managed, which allows the GameBuilder UI to track and toggle them at edit time.
Challenge
Find R2 hidden in the invisible maze — touch a wall and you restart! Use WASD to move.
Setting hitbox percentages to 0.0 means the engine uses the raw pixel rect for collision — no margin added.
Level 1 — Key Code Snippets
Player data (arrow key bindings, scale, spawn position):
Challenge
Survive 10 seconds without being caught by the alien slime! Stand still and it goes into rage mode. Use WASD to move, E near the alien to restart.
NPC dialogues array — rotated on each E-key press:
Level 2: Alien Maze
The walls are invisible. Touch one and you restart from the beginning. Navigate to R2 to complete the level — your time is being tracked!
How It Works
Invisible Barriers with Red Glow on Collision
All barriers are created with visible: false. When a collision is detected, the onCollide callback injects a short-lived <div> over the barrier’s canvas coordinates, styled with a red border and box-shadow. The player is then immediately reset to INIT_POSITION:
Challenge
Play all three levels back to back — Space Level, Alien Maze, then Alien Chase. Use Arrow Keys for Level 1, WASD for Levels 2 and 3.
_glowBarrier() — DOM Overlay Technique
The helper locates the canvas via document.querySelector('canvas'), reads its page offset with getBoundingClientRect(), then positions the glow <div> at canvas.left + barrier.x and canvas.top + barrier.y. A CSS transition: opacity 0.5s fades it out after 300ms, and it is removed from the DOM after 820ms.
Startup Popup and Victory Screen
_showStartupPopup() is called from the constructor before any game objects are created. It appends a dark overlay to document.body with a briefing card. When the player clicks START MISSION, the overlay is removed and GameLevel2._startTime = Date.now() begins the run timer.
When the player reaches R2 and presses E, interact() calls _showVictoryScreen(elapsed) after a short delay. elapsed is computed as:
const elapsed = Math.floor((Date.now() - GameLevel2._startTime) / 1000);
The victory screen formats this as MM:SS and displays it in a green-themed overlay.
Maze Layout
Barrier positions use fractional coordinates (0.0–1.0), which the engine scales to the actual viewport at runtime. The outer walls leave an entrance gap on the left side between y: 0.35 and y: 0.55 — the only way in:
const mazeLeftTop = makeBarrier('maze_left_top', 0.20, 0.15, 0.02, 0.20);
const mazeLeftBottom = makeBarrier('maze_left_bottom', 0.20, 0.55, 0.02, 0.30);
// gap between y=0.35 and y=0.55 is the entrance
%%js
// GAME_RUNNER: Find R2 hidden in the invisible maze — touch a wall and you restart! Use WASD to move.
import GameControl from '/assets/js/GameEnginev1/essentials/GameControl.js';
import GameLevel2 from '/assets/js/adventureGame/GameLevel2.js';
export const gameLevelClasses = [GameLevel2];
export { GameControl };
Level 2 — Mini-Game (No Code Editor)
Play the maze without the code editor. Good for embedding in lesson articles.
%%js
// GAME_RUNNER: Can you beat the invisible maze? Find R2 to win! | hide_edit: true
import GameControl from '/assets/js/GameEnginev1/essentials/GameControl.js';
import GameLevel2 from '/assets/js/adventureGame/GameLevel2.js';
export const gameLevelClasses = [GameLevel2];
export { GameControl };
Level 2 — Key Code Snippets
Static _startTime — shared across all instances:
/** @static {number|null} Unix timestamp (ms) when the run timer started. */
GameLevel2._startTime = null;
// Set when player dismisses the startup popup:
btn.addEventListener('click', () => {
overlay.remove();
GameLevel2._startTime = Date.now();
});
Player finder — searches all common engine object stores:
static _findPlayer(gameEnv) {
const sources = [
gameEnv?.gameObjects,
gameEnv?.objects,
gameEnv?.gameControl?.gameObjects,
].filter(Boolean);
for (const list of sources) {
const arr = Array.isArray(list) ? list : Object.values(list);
const found = arr.find(o => o?.data?.id === 'playerData');
if (found) return found;
}
return null;
}
Level 3: Alien Chase — Survive!
An alien slime is hunting you. Survive for 10 seconds to win. Stand still too long and it goes into rage mode. If it catches you, press E near the alien to restart.
How It Works
This level is the most complex, with two independent systems — AlienChaseAI and SurvivalManager — running alongside the standard game loop.
AlienChaseAI — The Chase Loop
AlienChaseAI runs its own setInterval at TICK_MS: 33 (≈ 30 fps). Each tick it:
- Reads the player and NPC canvas positions using
getBoundingClientRect(). - Computes a normalised direction vector toward the player.
- Accumulates an offset (
offsetX,offsetY) and applies it to the NPC canvas via CSS:
npcCanvas.style.transform = `translate(${this.offsetX}px, ${this.offsetY}px)`;
Stillness Detection → Rage Mode
Each tick, the AI measures how far the player moved since the last tick. If the movement is below STILL_RADIUS: 4 px, a stillSince timestamp is set. Once Date.now() - stillSince >= STILL_THRESHOLD_MS (3 seconds), the alien switches to RAGE_SPEED: 3.8 px/tick (vs. normal BASE_SPEED: 1.2 px/tick) and the HUD border turns red:
if ((now - this.stillSince) >= CHASE_CONFIG.STILL_THRESHOLD_MS) {
this.currentSpeed = CHASE_CONFIG.RAGE_SPEED;
this._setRageVisual(true); // HUD pulses red
}
As soon as the player moves again, speed resets to BASE_SPEED and the HUD reverts to teal.
SurvivalManager — The Countdown
SurvivalManager runs a separate setInterval every 100ms, ticking down remaining from 10000ms. The HUD displays tenths of a second in the final 3 seconds for extra tension. When remaining reaches zero, showWin() fires and the alien freezes.
Full Interaction Chain
Player moves into Alien hitbox
└─ Engine calls NPC.reaction()
└─ SurvivalManager.caught()
├─ frozen = true
├─ countdown stopped
├─ CAUGHT overlay → display: block
└─ AlienChaseAI.pause()
Player presses E near Alien
└─ Engine calls NPC.interact()
└─ SurvivalManager.reset()
├─ remaining = 10000ms
├─ frozen = false
├─ CAUGHT/WIN overlays → display: none
├─ AlienChaseAI.resume() (alien teleports to spawn)
└─ countdown restarted
Countdown reaches zero
└─ SurvivalManager.showWin()
├─ frozen = true
├─ WIN overlay → display: block
├─ AlienChaseAI.pause()
└─ (after 4s) currentLevel.continue = false → next level
Catch Cooldown — Grace Period After Restart
On restart, lastResetTime = Date.now() is recorded. caught() will not fire again until CATCH_COOLDOWN_MS: 1200 ms have passed — giving the player a brief grace window to move away from the spawn point before the alien can catch them again.
Barrier — Blocking the Top-Left Corner
A single Barrier at (0, 1) with size 235×134px blocks the top-left escape route, funneling the player toward the alien and increasing collision likelihood. This is an intentional level-design choice to raise tension.
%%js
// GAME_RUNNER: Survive 10 seconds without being caught by the alien slime! Stand still and it goes into rage mode. Use WASD to move, E near the alien to restart.
import GameControl from '/assets/js/GameEnginev1/essentials/GameControl.js';
import GameLevelstuck_final from '/assets/js/adventureGame/GameLevelstuck_final.js';
export const gameLevelClasses = [GameLevelstuck_final];
export { GameControl };
Level 3 — Mini-Game (No Code Editor)
Play the survival challenge without the code editor.
%%js
// GAME_RUNNER: Survive the alien chase! Can you last 10 seconds? | hide_edit: true
import GameControl from '/assets/js/GameEnginev1/essentials/GameControl.js';
import GameLevelstuck_final from '/assets/js/adventureGame/GameLevelstuck_final.js';
export const gameLevelClasses = [GameLevelstuck_final];
export { GameControl };
Level 3 — Key Code Snippets
CHASE_CONFIG — all AI tuning in one place:
const CHASE_CONFIG = {
TICK_MS: 33, // ~30 fps
BASE_SPEED: 1.2, // px/tick — normal
RAGE_SPEED: 3.8, // px/tick — when player stands still
STILL_THRESHOLD_MS: 3000, // ms of stillness to trigger rage
STILL_RADIUS: 4, // px — movement below this = "still"
STOP_RADIUS: 18, // px — alien stops nudging this close
INIT_POSITION: { x: 500, y: 300 }
};
HUD last-3-second warning:
_updateHUD() {
const secs = this.remaining / 1000;
// Show tenths in the final 3 seconds
const display = secs <= 3 ? `⏱ ${secs.toFixed(1)}s` : `⏱ ${Math.ceil(secs)}s`;
el.textContent = display;
if (secs <= 3) {
el.style.color = '#ff9900'; // orange pulse
}
}
Playing All Three Levels in Sequence
The levels were designed to chain together. Pass all three classes to gameLevelClasses and the engine will advance through them automatically as each level’s continue flag is set to false.
%%js
// GAME_RUNNER: Play all three levels back to back — Space Level, Alien Maze, then Alien Chase. Use Arrow Keys for Level 1, WASD for Levels 2 and 3.
import GameControl from '/assets/js/GameEnginev1/essentials/GameControl.js';
import GameLevelSpacelevel3 from '/assets/js/adventureGame/GameLevelSpacelevel3.js';
import GameLevel2 from '/assets/js/adventureGame/GameLevel2.js';
import GameLevelstuck_final from '/assets/js/adventureGame/GameLevelstuck_final.js';
export const gameLevelClasses = [GameLevelSpacelevel3, GameLevel2, GameLevelstuck_final];
export { GameControl };
Image Asset Reference
All levels resolve assets via gameEnv.path. Ensure the following files exist in your repo before publishing:
| Asset | Path |
|---|---|
| Alien planet background | images/gamebuilder/bg/alien_planet.jpg |
| Astronaut player sprite | images/gamebuilder/sprites/astro.png |
| Chill Guy NPC (Level 1) | images/gamify/chillguy.png |
| R2 robot NPC (Level 2) | images/gamify/r2_idle.png |
| Alien slime NPC (Level 3) | images/gamebuilder/sprites/slime.png |
Build and Test
After adding or editing this notebook, run make to convert it to an interactive HTML page:
make
# Then open: http://localhost:4000/adventure-game-levels
Checklist before publishing:
- Each game-runner cell renders a canvas with Play / Stop / Reset controls.
- Level transitions work (NPC interact or ESC key advances to next level).
- Level 2 startup popup and victory screen appear and close correctly.
- Level 3 HUD timer counts down; CAUGHT and WIN overlays display correctly.
hide_edit: truecells hide the code editor and show only the game canvas.- All five image assets resolve without 404 errors (check browser console).