Seek Game Level
Breakdown of arrays and booleans used in `GameLevelSeek.js`.
Overview
This notebook breaks down the CS conecpts used in GameLevelSeek.js.
Note: the game file is written in JavaScript, not Java. The ideas map directly to Java: arrays are lists of items, and booleans are true or false flags that control logic.
Seek Game
Seek Game — CS111 Code Review
I built a hide-and-seek game where you navigate a tag playground to find Kirby hidden somewhere on the map. Below I break down every CS111 concept using real code from the game.
Control Structures
Iteration — for, forEach, while loops
The game’s class list is built using an array literal that iterates over every game object when the engine initializes the level:
Challenge
Play the Seek level — Navigate the tag playground and find Kirby! Use WASD to move.
Multiple barrier objects are defined one after another — a pattern that could be refactored with a forEach loop over an array of raw coordinates:
[dbarrier_1, dbarrier_2, dbarrier_3, dbarrier_4,
dbarrier_5, dbarrier_6, dbarrier_7, dbarrier_8]
.forEach(b => this.classes.push({ class: Barrier, data: b }));
Conditionals — if/else
The NPC’s reaction function uses an if/else to decide whether to show a full dialogue popup or fall back to a simple console log:
reaction: function() {
if (this.dialogueSystem) {
this.showReactionDialogue();
} else {
console.log(this.greeting);
}
}
Nested Conditions — multi-level conditionals
The onDialogueClose callback uses nested conditionals to safely navigate the object chain before stopping the level:
onDialogueClose: function() {
const gameControl = this.gameEnv?.gameControl;
if (gameControl?.currentLevel) {
gameControl.currentLevel.continue = false;
}
}
The outer check confirms gameControl exists; only then does the inner check confirm currentLevel is present before mutating it — a two-level guard preventing runtime errors.
Data Types
Numbers — position, velocity, score tracking
Every game object is precisely placed and sized using numeric properties:
SCALE_FACTOR: 5,
STEP_FACTOR: 1000,
ANIMATION_RATE: 50,
INIT_POSITION: { x: 32, y: 300 },
pixels: { height: 612, width: 408 },
Barrier positions are also pure numbers that map directly onto the background image:
const dbarrier_1 = { x: 232, y: 218, width: 83, height: 78, ... };
Strings — character names, sprite paths, game states
Sprite image paths are built by concatenating the engine-provided path string with a local file path string:
src: path + "/images/gamebuilder/sprites/boysprite.png"
src: path + "/images/gamebuilder/sprites/kirby.png"
src: path + "/images/gamebuilder/bg/tagplayground.png"
The NPC’s greeting and dialogue are also stored as strings:
greeting: 'Oh you found me',
dialogues: ['Oh you found me'],
Booleans — flags like isOver, isPaused
The visible property on every barrier is a boolean that controls whether the hitbox outline is drawn on screen:
const dbarrier_1 = { ..., visible: false, ... };
The fromOverlay flag is another boolean that tells the engine these barriers were placed using the visual overlay tool rather than typed by hand:
fromOverlay: true
Arrays — game object collections, level data
The NPC’s dialogue lines are stored in an array, allowing the dialogue system to cycle through multiple messages:
dialogues: ['Oh you found me'],
The this.classes array is the central data structure of the entire level — it holds every object the game engine will instantiate:
this.classes = [
{ class: GameEnvBackground, data: bgData },
{ class: Player, data: playerData },
{ class: Npc, data: npcData1 },
// 8 Barrier entries...
];
Objects (JSON) — configuration objects, sprite data
Every game entity is configured as a JavaScript object. The player object, for example, bundles position, animation, sprite layout, and keypress bindings all in one place:
const playerData = {
id: 'playerData',
src: path + "/images/gamebuilder/sprites/boysprite.png",
SCALE_FACTOR: 5,
INIT_POSITION: { x: 32, y: 300 },
pixels: { height: 612, width: 408 },
orientation: { rows: 4, columns: 3 },
down: { row: 0, start: 0, columns: 3 },
keypress: { up: 87, left: 65, down: 83, right: 68 }
};
Operators
Mathematical — physics calculations
The NPC sprite orientation rows use Math.min to clamp row indices so they never exceed the available rows in the sprite sheet (which only has 1 row):
right: { row: Math.min(1, 1 - 1), start: 0, columns: 3 },
left: { row: Math.min(2, 1 - 1), start: 0, columns: 3 },
up: { row: Math.min(3, 1 - 1), start: 0, columns: 3 },
The player’s diagonal rotation angles use Math.PI divided by a constant to calculate a small tilt in radians:
downRight: { row: 1, start: 0, columns: 3, rotate: Math.PI / 16 },
downLeft: { row: 0, start: 0, columns: 3, rotate: -Math.PI / 16 },
String Operations — template literals, concatenation
Sprite source paths are assembled with the + concatenation operator, dynamically combining the engine’s base path with each asset’s local path:
src: path + "/images/gamebuilder/sprites/boysprite.png"
src: path + "/images/gamebuilder/bg/tagplayground.png"
Boolean Expressions — &&, ||, !
The onDialogueClose function uses optional chaining (?.) which short-circuits like a && — only proceeding if each step in the chain is truthy:
const gameControl = this.gameEnv?.gameControl;
if (gameControl?.currentLevel) {
gameControl.currentLevel.continue = false;
}
The interact and reaction functions both guard their dialogue call with a truthiness check on this.dialogueSystem:
interact: function() {
if (this.dialogueSystem) { this.showReactionDialogue(); }
}
Reflection
Building this seek game forced me to think about data structures in a completely new way. The this.classes array is the backbone of the whole level — without it, nothing gets drawn. Every barrier is a JSON object with numeric coordinates, boolean visibility flags, and string IDs. The NPC uses nested conditionals to safely close the level when you find it, and Math.min prevents sprite row indices from going out of bounds. Seeing how a single array of objects can power an entire interactive level made the connection between data types and real programs click for me in a way that reading about them never did.
Play the Seek Game
%%js
// GAME_RUNNER: Play the Seek level — Navigate the tag playground and find Kirby! Use WASD to move.
import GameControl from '/assets/js/GameEnginev1/essentials/GameControl.js';
import GameLevelSeek from '/assets/js/GameEnginev1/GameLevelSeek.js';
export const gameLevelClasses = [GameLevelSeek];
export { GameControl };