CS111 College Ready

This notebook explains the code in Aquatic For Reference.js using CSSE topics like functions, arrays, booleans, conditionals, classes, constructors, methods, strings, data abstraction, math expressions, variables, and iteration. Each section below connects one CSSE topic to a real code pattern from the Aquatic level file. Before the topic-by-topic breakdown, the notebook now includes a small playable aquatic runner and a preview of the assets currently wired into the published site.

Quick Aquatic Game Runner

Use this runner at the top to test a compact Aquatic-style loop before going lesson-by-lesson.

Playable Aquatic Game Runner
Status: ready (uses Aquatic For Reference logic)
This runner directly loads GameLevelAquaticGameLevel from assets/js/GameEnginev1.1/GameLevelAquaticGameLevel.js (Aquatic For Reference implementation).

Interactive Rubric Dashboard

Interactive Rubric Dashboard

Search + filter Objective jump links Progress memory
Review completion
0 / 7 checked

CS 111 Course Alignment Rubric

Required Evidence for College Credit

Students must demonstrate competency in all CS 111 learning objectives through their game project. Below is the alignment between CS 111 requirements and project deliverables, with evidence pulled from the Aquatic game level implementation.

Learning Objective Project Evidence Required Assessment Method
Object-Oriented Programming    
Writing Classes Create minimum 2 custom character classes extending base classes. Evidence: class Player extends Character, class Npc extends Character, class Shark extends Enemy in assets/js/GameEnginev1/essentials/Player.js, assets/js/GameEnginev1/essentials/Npc.js, assets/js/GameEnginev1/Shark.js. Code review: class declarations and extends usage
Methods & Parameters Implement methods with parameters. Evidence: applyPlayerDamage(damage, x, y, source) and applyMermaidBossDamage(damage, hitX, hitY) in assets/js/GameEnginev1/GameLevelAquaticGameLevel.js. Code review: method signatures with 2+ parameters
Instantiation & Objects Instantiate game objects in level configuration/runtime. Evidence: const guardian = new Npc(guardianData, this.gameEnv); and this.gameEnv.gameObjects.push(guardian); in assets/js/GameEnginev1/GameLevelAquaticGameLevel.js. Code review: GameLevel setup and runtime object registration
Inheritance (Basic) Create class hierarchy with 2+ levels. Evidence: GameObject -> Character -> Player and Character -> Npc -> Shark. Code review: inheritance chain and shared behavior
Method Overriding Override parent methods (update(), interaction handling, behavior methods). Evidence: child entity update and interaction methods in player/NPC/enemy classes. Code review: polymorphic implementations
Constructor Chaining Use super() to chain constructors. Evidence: super(data, gameEnv) patterns in entity constructors. Code review: super(data, gameEnv) calls
Control Structures    
Iteration Use loops for game object arrays and attack phases. Evidence: thresholds.forEach((threshold) => { ... }), update loops, projectile iteration. Code review: for, forEach, while
Conditionals Implement collision checks and state transitions. Evidence: quest/boss transitions such as if (q1.completed && !q2.accepted) { ... }. Code review: if/else branches
Nested Conditions Multi-stage combat logic. Evidence: if (state.phaseTwoUnlocked && now >= state.nextLaserAt && state.phaseThreeUnlocked) { ... }. Code review: multi-level conditional logic
Data Types    
Numbers Position, HP, cooldown, and timing tracking. Evidence: const hpRatio = this.bossState.hp / this.bossState.maxHp;. Code review: numeric properties and math usage
Strings Character IDs, paths, and labels. Evidence: const aquaticSpriteStorageKey = 'aquatic_selected_sprite_v1';. Code review: string literals and concatenation/template usage
Booleans Flags for active/completed states. Evidence: this.levelCompleted = false;, this.bossState.active = true;. Code review: boolean state transitions
Arrays Game object collections and threshold lists. Evidence: const thresholds = [0.75, 0.5, 0.25];. Code review: array operations
Objects (JSON) Config/state object literals. Evidence: const guardianData = { orientation: { ... }, attack: { ... } };. Code review: object literal structure
Operators    
Mathematical Physics/combat calculations. Evidence: this.bossState.maxHp * threshold, vector and distance calculations in attacks. Code review: +, -, *, / usage
String Operations Path assembly and identifiers. Evidence: const backgroundAssetPath = path + '/images/gamebuilder/bg';. Code review: concatenation/template literals
Boolean Expressions Compound game-state checks. Evidence: &&, ||, ! in phase gates and quest flow. Code review: compound conditions
Input/Output    
Keyboard Input WASD/keyboard mapping and handlers. Evidence: this.keypress = data?.keypress || { up: 87, left: 65, down: 83, right: 68 }; and keydown listeners. Testing: key event handlers respond correctly
Canvas Rendering Draw/update lifecycle for entities. Evidence: update() { this.draw(); } and sprite rendering in character classes. Code review: render lifecycle methods
GameEnv Configuration Canvas/runtime setup and class registration. Evidence: this.gameEnv.create(); and level constructor wiring. Code review: GameEnv setup + GameLevel init
API Integration Fetch-based external communication. Evidence: await fetch(${this.game.javaURI}/bank/${personId}/npcProgress, this.fetchOptions);. Code review: fetch calls with error handling
Asynchronous I/O Non-blocking runtime functions. Evidence: async handleMoodClick(mood) { const response = await fetch(...); }. Code review: async/await flow
JSON Parsing Parse API payloads. Evidence: const result = await response.json();. Code review: response parsing and property access
Documentation    
Code Comments Intent comments in complex logic. Evidence: // Initialize touch controls for mobile devices. Code review: meaningful comment usage
Mini-Lesson Documentation Notebook sections and rubric mapping for instruction. Evidence: this notebook’s rubric + objective sections. Portfolio review: published mini-lesson
Code Highlights Annotated snippets under each rubric objective. Evidence: objective-specific code blocks in this notebook. Portfolio review: highlighted explanations
Debugging    
Console Debugging Runtime diagnostics. Evidence: console.warn('Unable to play aquatic boss theme', err);. Code review: strategic logging/warnings
Hit Box Visualization Collision-distance validation. Evidence: if (hitDistance < 30) { applyPlayerDamage(...); }. Demo: collision boundary verification
Source-Level Debugging Breakpoint-friendly state guards. Evidence: if (this.bossState.active || this.bossState.introPlayed) return;. Demo: stepping through flow in Sources
Network Debugging Request status checks. Evidence: if (!response.ok) throw new Error('Failed to send mood');. Demo: inspect requests and responses
Application Debugging Local/session state verification. Evidence: localStorage.setItem(...), sessionStorage.setItem(...). Demo: inspect storage state
Element Inspection DOM/canvas inspection logic. Evidence: if (this.canvas?.parentNode) { this.canvas.parentNode.removeChild(this.canvas); }. Demo: inspect DOM/canvas lifecycle
Testing & Verification    
Gameplay Testing Validate quest/combat flow. Evidence: dialogue progression and boss-state transitions in Aquatic level scripts. Live demo: complete flow without blockers
Integration Testing Verify backend-connected paths. Evidence: await fetch(${this.game.javaURI}/createStats, { method: 'POST', body: JSON.stringify({ stats, gname, uid }) });. Demo: successful integrated requests
API Error Handling Graceful failure handling. Evidence: try/catch around fetch with fallback status UI (this.showStatus('Network error', true);). Code review: explicit error handling

1 — Object-Oriented Programming

1.1 Writing Classes

A class is a blueprint for creating objects. extends builds an inheritance chain so classes can reuse behavior. this.classes tells the engine what to create at startup.

Code Runner Challenge

OOP coverage for 1.1 to 1.6

View IPYNB Source
// Player class extends Character, so Player inherits movement/collision/sprite behavior.
class Player extends Character {
  // Constructor runs when a new Player is created in the level class list.
  constructor(data = null, gameEnv = null) {
    // super(...) calls Character constructor first; required before using this.
    super(data, gameEnv);

    // Player identity in Aquatic (fallback if data.id is missing).
    this.id = data?.id ?? 'player';

    // Default WASD key mapping used by movement listeners.
    this.keypress = data?.keypress || { up: 87, left: 65, down: 83, right: 68 };

    // Tracks currently pressed keys for continuous movement.
    this.pressedKeys = {};
  }
}

// NPC class extends Character so it can share sprite and interaction lifecycle.
class Npc extends Character {
  constructor(data = null, gameEnv = null) {
    super(data, gameEnv);
  }
}

// Shark class extends Enemy (Enemy extends Character), forming a multi-level chain.
class Shark extends Enemy {
  constructor(data = null, gameEnv = null) {
    super(data, gameEnv);
    // Enemy-state flag used in collision/combat logic.
    this.playerDestroyed = false;
  }
}

// Aquatic level class: this.classes tells the engine exactly what objects to instantiate.
class GameLevelAquaticGameLevel {
  constructor(gameEnv) {
    this.gameEnv = gameEnv;
    this.classes = [
      { class: GameEnvBackground, data: bgData },
      { class: Player, data: playerData },
      { class: Npc, data: mermaidNpc },
      { class: Npc, data: slimeNpc },
      { class: Npc, data: kirbyNpc },
      { class: Npc, data: sharkNpc }
    ];
  }
}
Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

1.2 Methods & Parameters

A method is a class function that uses this instance state. Parameters let one method handle many callers.

applyPlayerDamage(damage, x, y, source) {
  if (!this.bossState.active) return;
  // damage and hit position are parameter-driven
}

applyMermaidBossDamage(damage, hitX, hitY) {
  if (!this.mermaidBossState.active) return;
  // same logic shape, different target state
}

collisionChecks() {
  for (const gameObj of this.gameEnv.gameObjects) {
    if (gameObj instanceof Player) {
      this.isCollision(gameObj);
      if (this.collisionData.hit) return true;
    }
  }
  return false;
}

1.3 Instantiation & Objects

Instantiation uses new ClassName(...) to create independent runtime objects. Aquatic level setup uses both class instances and object-literal configuration.

const guardianData = {
  orientation: { rows: 6, columns: 6 },
  attack: { row: 4, start: 0, columns: 5 }
};

const guardian = new Npc(guardianData, this.gameEnv);
this.gameEnv.gameObjects.push(guardian);

this.classes = [
  { class: GameEnvBackground, data: image_data_aquatic }
];

1.4 Inheritance

Inheritance lets child classes automatically use parent fields/methods without rewriting everything.

class GameObject {
  constructor(gameEnv) {
    this.gameEnv = gameEnv;
    gameEnv.gameObjects.push(this);
  }
}

class Character extends GameObject {
  constructor(data = null, gameEnv = null) {
    super(gameEnv);
    this.velocity = { x: 0, y: 0 };
  }
}

class Player extends Character {
  constructor(data = null, gameEnv = null) {
    super(data, gameEnv);
    this.keypress = data?.keypress || { up: 87, left: 65, down: 83, right: 68 };
  }
}

1.5 Method Overriding

Overriding happens when a child defines the same method name as a parent. super.methodName() keeps parent behavior and extends it.

update() {
  super.update();
  if (!this.playerDestroyed && this.collisionChecks()) {
    this.handleCollisionEvent();
  }
  this.stayWithinCanvas();
}

handleCollisionReaction(other) {
  const touchPoints = this.collisionData?.touchPoints?.this;
  if (touchPoints?.top) this.velocity.y = Math.min(0, this.velocity.y);
  if (touchPoints?.bottom) this.velocity.y = Math.max(0, this.velocity.y);
  if (touchPoints?.left) this.velocity.x = Math.min(0, this.velocity.x);
  if (touchPoints?.right) this.velocity.x = Math.max(0, this.velocity.x);
}

1.6 Constructor Chaining

super() in child constructors calls parent setup first. JavaScript requires this before using this.

constructor(data = null, gameEnv = null) {
  super(data, gameEnv);
  this.pressedKeys = {};
}

constructor(data = null, gameEnv = null) {
  super(gameEnv);
  this.canvas = document.createElement('canvas');
  this.velocity = { x: 0, y: 0 };
}

constructor(gameEnv) {
  this.gameEnv = gameEnv;
  this.canvas = document.createElement('canvas');
  gameEnv.gameObjects.push(this);
}

Use this section as the OOP evidence reference, then continue with the existing sections for Control Structures, Data Types, Operators, Input/Output, Documentation, Debugging, and Testing.

2 — Control Structures

2.1 Iteration

Code evidence (Aquatic):

// Each threshold represents a boss HP phase trigger (75%, 50%, 25%).
thresholds.forEach((threshold) => {
  // Compare current HP to a percentage of max HP.
  if (this.bossState.hp <= this.bossState.maxHp * threshold) {
    // Spawn reinforcements when that phase is reached.
    summonRushingSharks();
  }
});

How this works in my Aquatic game:

  • The loop checks each HP threshold (75%, 50%, 25%).
  • When Megalodon HP drops below a threshold, shark reinforcements are spawned.
  • This creates phase-based combat escalation.

2.2 Conditionals

Code evidence (Aquatic):

// Only show Quest 2 prompt after Quest 1 is complete.
if (q1.completed && !q2.accepted) {
  // Dialogue branch advances story progression.
  this.dialogueSystem.showDialogue('Will you take Aquatic Quest #2?', 'Slime', null);
}

How this works in my Aquatic game:

  • The game only offers Quest 2 after Quest 1 is complete.
  • It prevents showing wrong dialogue at the wrong time.
  • This keeps quest progression logic consistent.

2.3 Nested Conditions

Code evidence (Aquatic):

// Laser requires: phase unlocked + cooldown reached + late-phase flag.
if (state.phaseTwoUnlocked && now >= state.nextLaserAt && state.phaseThreeUnlocked) {
  // Start laser with configured charge duration.
  startMermaidBossAbility('laser', state.laserChargeMs);
}

How this works in my Aquatic game:

  • Mermaid laser requires multiple conditions at once: phase unlock + cooldown time.
  • This prevents ability spam and preserves intended boss pacing.

3 — Data Types

3.1 Numbers

Code evidence (Aquatic):

// Convert absolute HP into a ratio so behavior can scale by percent.
// Example: 50/100 = 0.5, which can unlock mid-fight phase logic.
const hpRatio = this.bossState.hp / this.bossState.maxHp;

How this works in my Aquatic game:

  • Converts boss health into a ratio for phase checks and UI decisions.
  • Allows behavior to scale by percent, not hardcoded HP only.

3.2 Strings

Code evidence (Aquatic):

// Storage key name used for persisting selected player sprite.
// This exact key is reused when writing and reading localStorage values.
const aquaticSpriteStorageKey = 'aquatic_selected_sprite_v1';

How this works in my Aquatic game:

  • This string is the storage key used to remember selected player sprite.
  • Keeps player customization persistent across sessions.

3.3 Booleans

Code evidence (Aquatic):

// Menu starts hidden when gameplay begins.
this.frontMenuActive = false;

// Boss logic gates open once encounter is activated.
// Many attack/update branches check this flag before running.
this.bossState.active = true;

How this works in my Aquatic game:

  • frontMenuActive toggles menu state.
  • bossState.active enables boss combat logic only when encounter starts.

3.4 Arrays

Code evidence (Aquatic):

// Array of selectable character presets for the Aquatic level.
// Each object stores a stable key (used by logic) and a label (used by UI text).
const aquaticSpriteOptions = [
  { key: 'scuba-diver', label: 'Scuba Diver' },
  { key: 'boy', label: 'Boy' }
];

How this works in my Aquatic game:

  • Stores available character choices in one data structure.
  • UI can render options and switch sprites from this list.

3.5 Objects (JSON)

Code evidence (Aquatic):

// Object literal groups guardian animation configuration.
// Nested fields let renderer/animation code read structured data by action name.
const guardianData = {
  orientation: { rows: 6, columns: 6 },
  attack: { row: 4, start: 0, columns: 5 }
};

How this works in my Aquatic game:

  • Groups sprite/animation config for a guardian NPC.
  • Makes NPC setup data-driven rather than hardcoding values across methods.

4 — Operators

4.1 Mathematical Operators

Code evidence (Aquatic):

// Multiply max HP by threshold to compute phase breakpoint.
// If max HP is 200 and threshold is 0.5, trigger point becomes 100 HP.
if (this.bossState.hp <= this.bossState.maxHp * threshold) {
  summonRushingSharks();
}

How this works in my Aquatic game:

  • Multiplies max HP by threshold to compute trigger points.
  • Uses <= to activate phase actions when HP reaches that level.

4.2 String Operations

Code evidence (Aquatic):

// Build sprite path using string concatenation.
// This keeps file paths dynamic across local and deployed environments.
const spriteAssetPath = path + '/images/gamebuilder/sprites';

// Build unique collectible id using template literal.
// i changes each loop, so IDs become starfish_0, starfish_1, etc.
const itemId = `starfish_${i}`;

How this works in my Aquatic game:

  • Concatenation builds asset folder paths.
  • Template literals generate unique collectible IDs.

4.3 Boolean Expressions

Code evidence (Aquatic):

// Compound condition ensures laser can run only in valid phase/timing state.
// All three checks must be true for this branch to execute.
if (state.phaseTwoUnlocked && now >= state.nextLaserAt && state.phaseThreeUnlocked) {
  startMermaidBossAbility('laser', state.laserChargeMs);
}

How this works in my Aquatic game:

  • Compound boolean logic ensures ability fires only in valid game state.
  • Reduces bugs from partial or premature phase triggers.

5 — Input/Output

5.1 Keyboard Input

Code evidence (Aquatic):

// Default WASD controls used when custom key data is absent.
// 87=W (up), 65=A (left), 83=S (down), 68=D (right).
this.keypress = data?.keypress || { up: 87, left: 65, down: 83, right: 68 };

// Keydown listener routes keyboard input into movement logic.
// bind(this) preserves class context inside handleKeyDown.
addEventListener('keydown', this.handleKeyDown.bind(this));

How this works in my Aquatic game:

  • Maps WASD keycodes to movement directions.
  • Listener captures real-time key presses for player control.

5.2 Canvas Rendering

Code evidence (Aquatic):

update() {
  // Draw is called each frame through the update lifecycle.
  // This keeps sprite position/animation synced with current state.
  this.draw();
}

How this works in my Aquatic game:

  • Every frame calls draw through update lifecycle.
  • Keeps character and boss visuals synced with game state.

5.3 GameEnv Configuration

Code evidence (Aquatic):

// Create initializes game canvas/context and runtime object systems.
// This is the startup handoff that makes the scene render and update.
this.gameEnv.create();

How this works in my Aquatic game:

  • Initializes runtime environment, canvas, and object loop.
  • Without this call, gameplay rendering and updates cannot start.

5.4 API Integration

Code evidence (Aquatic):

// Fetch backend NPC progress tied to current person/player id.
// fetchOptions usually includes method, headers, and auth/session context.
const response = await fetch(`${this.game.javaURI}/bank/${personId}/npcProgress`, this.fetchOptions);

How this works in my Aquatic game:

  • Sends/reads backend progress data tied to player profile.
  • Connects in-game actions with persistent external systems.

5.5 Asynchronous I/O

Code evidence (Aquatic):

// Async handler keeps UI responsive while POST request completes.
// await pauses this function only, not the entire render/game loop.
async handleMoodClick(mood) {
  const response = await fetch(this.endpoint, { method: 'POST' });
}

How this works in my Aquatic game:

  • Prevents UI/game loop blocking during network requests.
  • Allows responses to be handled after request completion.

5.6 JSON Parsing

Code evidence (Aquatic):

// Parse JSON payload into JavaScript object for game logic use.
// After parsing, fields like result.success or result.stats can be read safely.
const result = await response.json();

How this works in my Aquatic game:

  • Converts backend response payload into usable JS object data.
  • Enables quest/mood/progress logic to read structured fields.

6 — Documentation

6.1 Code Comments

Code evidence (Aquatic):

// Initialize touch controls for mobile devices.
// This gives phone/tablet players on-screen movement and interaction inputs.
this.touchControls = new TouchControls(gameEnv, this.touchOptions);

How this works in my Aquatic game:

  • Comment explains why touch controls are created here.
  • Helps reviewers quickly understand mobile input design.

6.2 Mini-Lesson Documentation

Code evidence (Aquatic notebook):

## CS 111 Course Alignment Rubric
### Required Evidence for College Credit

How this works in my Aquatic game portfolio:

  • Organizes evidence in rubric order for grading.
  • Connects gameplay code to CS111 objectives clearly.

6.3 Code Highlights

Code evidence (Aquatic):

// Create boss NPC instance from configured boss data.
// This line proves class-based object creation in a real combat flow.
const boss = new Npc(bossData, this.gameEnv);

// Register boss in game object list so update/draw loop processes it.
// Without push, boss would exist but never be updated or rendered by engine loop.
this.gameEnv.gameObjects.push(boss);

How this works in my Aquatic game:

  • Highlighted snippet proves instantiation + runtime registration.
  • Shows exactly where boss entities enter the update/draw pipeline.

7 — Debugging

7.1 Console Debugging

Console logging traces execution by printing values at key transitions: quest acceptance, boss spawn, phase changes, and request failures. Avoid logging every frame inside update loops.

// Log once when quest progression changes.
if (q1.completed && !q2.accepted) {
  console.log('[Aquatic] Quest transition: Q1 complete, prompting Q2');
}

// Log when boss state transitions for verification.
if (!this.bossState.active && shouldStartBoss) {
  console.log(`[Aquatic] Boss start: hp=${this.bossState.hp}, maxHp=${this.bossState.maxHp}`);
}

// Log API failures with status code and endpoint context.
if (!response.ok) {
  console.warn(`[Aquatic] API request failed: status=${response.status}`);
}

7.2 Hit Box Visualization

Hit box visualization overlays collision circles/boxes so hit detection can be tuned against sprites. Use the same radii as collision logic to avoid mismatch.

// Debug-only helper: visualize player and boss hit radii.
function drawHitBoxes(ctx, player, boss) {
  ctx.save();
  ctx.lineWidth = 1;

  // Player radius (green)
  ctx.strokeStyle = 'rgba(0,255,0,0.7)';
  ctx.beginPath();
  ctx.arc(player.x, player.y, 20, 0, Math.PI * 2);
  ctx.stroke();

  // Boss radius (red)
  if (boss) {
    ctx.strokeStyle = 'rgba(255,60,0,0.7)';
    ctx.beginPath();
    ctx.arc(boss.x, boss.y, boss.r, 0, Math.PI * 2);
    ctx.stroke();
  }
  ctx.restore();
}

7.3 Source-Level Debugging (DevTools Breakpoints)

A breakpoint pauses execution at an exact line so you can inspect live state values (bossState, phase flags, cooldown timers) before/after updates.

  1. Open DevTools -> Sources.
  2. Navigate to assets/js/GameEnginev1/GameLevelAquaticGameLevel.js.
  3. Place breakpoint on a phase-gate line such as if (state.phaseTwoUnlocked && now >= state.nextLaserAt && state.phaseThreeUnlocked).
  4. Trigger boss combat and wait for pause.
  5. Inspect state, now, and nextLaserAt in Scope.
  6. Step over line-by-line to confirm transitions.

7.4 Network Debugging (Fetch / CORS)

The Network tab shows every fetch request. For Aquatic, this is useful for debugging npcProgress, mood, and stats endpoints.

  1. Open DevTools -> Network -> filter Fetch/XHR.
  2. Trigger a game action that calls fetch(...).
  3. In Headers, verify request URL and method.
  4. In Payload, verify JSON body fields for stats/progress.
  5. In Response, verify success object or error payload.
  6. For CORS failures, update server response headers (Access-Control-Allow-Origin).

7.5 Application Debugging (Session & Storage)

The Application tab is used to validate local/session storage and authentication cookies used by gameplay persistence.

  1. Open DevTools -> Application.
  2. Check Cookies for valid active session values.
  3. Check Expiration and SameSite behavior if authenticated requests fail.
  4. Under Local Storage, verify keys such as aquatic_selected_sprite_v1.
  5. Under Session Storage, verify any temporary gameplay state values if used.

7.6 Element Inspection (Canvas & DOM)

The Elements inspector confirms the Aquatic canvas/HUD is appended correctly and styles are applied as expected.

  1. Right-click game canvas -> Inspect.
  2. Confirm canvas is attached under expected parent container.
  3. Verify parent has proper positioning for absolute child elements.
  4. Verify HUD elements update (textContent, style width/health bars).
  5. If canvas is invisible or offset, inspect computed layout and z-index.

Each topic is now separated with one focused code evidence block, inline comments, and one direct Aquatic-specific explanation.