Documentation & Debugging

Requirements

  1. JSDoc comments for classes and methods
  2. Strategic inline comments explaining logic
  3. Console logging for state tracking
  4. Error handling with try/catch

1. JSDoc Comments - Class Documentation

GameLevelOutside.js - Comprehensive JSDoc

/**
 * GameLevelOutside
 * 
 * Defines the configuration for the Outside mini-game level.
 * This class constructs the objects that will exist in the level,
 * including the background, player, NPC, barrier, and moving target.
 * 
 * Each object is described with a configuration object that determines
 * sprite properties, positioning, animations, and gameplay behavior.
 */
class GameLevelOutside {
    /**
     * Friendly name of the game level
     * @static
     * @type {string}
     */
    static friendlyName = "Level 1: Castle Grounds";

    /**
     * Creates a new Outside level configuration.
     *
     * @param {GameEnvironment} gameEnv - The main game env object
     */
    constructor(gameEnv) {
        const width = gameEnv.innerWidth;
        const height = gameEnv.innerHeight;
        const path = gameEnv.path;
        // ...
    }
}

How it meets the requirement:

  • Class Documentation: Describes purpose and structure
  • @param Tags: Document parameters with types
  • @static: Marks static properties

SpriteSheetCoin.js - Method Documentation

/**
 * SpriteSheetCoin extends the basic Coin class to support image/spritesheet rendering.
 * Instead of a colored circle, you can now display any image asset (gem, star, etc).
 * 
 * @example
 * const gemCoin = new SpriteSheetCoin({
 *   id: 'gem-coin',
 *   INIT_POSITION: { x: 0.5, y: 0.5 },
 *   SCALE_FACTOR: 30,
 *   value: 5,
 *   spriteImagePath: '/images/gem.png',
 *   spriteFrames: { rows: 2, columns: 2, frameIndex: 0 }
 * }, gameEnv);
 */
class SpriteSheetCoin extends Coin {
    /**
     * Load the sprite image asynchronously
     */
    loadImage() {
        const img = new Image();
        // ...
    }

    /**
     * Draw the coin using spritesheet if available, otherwise fall back to colored circle
     */
    draw() {
        // ...
    }

    /**
     * Draw the sprite image on the canvas
     */
    drawSpriteImage() {
        // ...
    }
}

How it meets the requirement:

  • Method Documentation: Each method has JSDoc
  • @example: Shows usage pattern

2. Strategic Inline Comments

DeathBarrier.js - Inline Comments Explaining Logic

class DeathBarrier extends Barrier {
    constructor(data, gameEnv) {
        super(data, gameEnv);
        this._hasTriggeredDeath = false;
        // Store the level start time - all barriers share this for grace period
        if (!DeathBarrier.levelStartTime) {
            DeathBarrier.levelStartTime = new Date();
        }
    }

    update() {
        // Checks for collisions, if triggered then uses the below code
        super.update();

        // If the death is already triggered no need to trigger it again
        if (this._hasTriggeredDeath) return;

        const player = this.gameEnv?.gameObjects?.find(obj => obj.constructor?.name === 'Player');
        if (!player || !player.canvas || !this.canvas) return;

        this.isCollision(player);

        if (this.collisionData?.hit) {
            // Check grace period from level start time
            const timeSinceLevelStart = new Date() - DeathBarrier.levelStartTime;
            // We added a grace period because there was an error where the barrier would kill 
            // the player before they could even play
            if (timeSinceLevelStart < 500) {
                console.log('[MazeDebug] Grace period active:', timeSinceLevelStart, 'ms');
                return;  // we added a grace period to prevent instant death
            }

            this._hasTriggeredDeath = true;
            player.isDead = true;

            // Log collision details for debugging
            console.log('[MazeDebug] DeathBarrier hit player:', this.canvas?.id || this.id || 'unknown');
            console.log('[MazeDebug] Player Position:', player.x, player.y);

            try {
                showDeathScreen(player, 'You got lost in the maze.');
            } catch (error) {
                console.error('DeathBarrier failed to show death screen:', error);
                this._hasTriggeredDeath = false;
                player.isDead = false;
            }
        }
    }
}

How it meets the requirement:

  • Grace Period Logic: Explains why 500ms delay is needed
  • State Management: Comments explain _hasTriggeredDeath purpose

Ghost.js - Collision Logic Comments

handleCollisionEvent() {
    // Prevent duplicate death triggers
    if (this._hasTriggeredDeath || this.playerDestroyed) return;

    const player = this.getPlayer();
    // Check both flags to ensure player is valid and alive
    if (!player || player.isDead) return;

    // Mark collision as handled and player as dead
    this._hasTriggeredDeath = true;
    this.playerDestroyed = true;
    player.isDead = true;

    // Show death screen with appropriate message
    showDeathScreen(player, 'The ghost caught you.');
}

How it meets the requirement:

  • State Flag Comments: Explains collision tracking logic

3. Console Logging - State Tracking

DeathBarrier.js - Strategic console.log

update() {
    if (this._hasTriggeredDeath) return;
    
    const player = this.gameEnv?.gameObjects?.find(obj => obj.constructor?.name === 'Player');
    if (!player || !player.canvas || !this.canvas) return;
    
    this.isCollision(player);
    
    if (this.collisionData?.hit) {
        const timeSinceLevelStart = new Date() - DeathBarrier.levelStartTime;
        
        // ← Track grace period timing
        if (timeSinceLevelStart < 500) {
            console.log('[MazeDebug] Grace period active:', timeSinceLevelStart, 'ms');
            return;
        }
        
        // ← Log collision details
        console.log('[MazeDebug] DeathBarrier hit player:', this.canvas?.id || this.id || 'unknown');
        console.log('[MazeDebug] Player Position:', player.x, player.y);
    }
}

How it meets the requirement:

  • Grace Period Logging: Track timing precision
  • Collision Logging: Identify which barrier hit player
  • Position Logging: Debug player location

SpriteSheetCoin.js - Image Loading Logs

loadImage() {
    const img = new Image();
    
    // ← Track successful image load
    img.onload = () => {
        this.spriteImage = img;
        this.isImageLoaded = true;
        console.log(`SpriteSheetCoin image loaded: ${this.spriteImagePath}`);
    };
    
    // ← Track image load failures
    img.onerror = () => {
        console.warn(`Failed to load SpriteSheetCoin image: ${this.spriteImagePath}`);
        this.isImageLoaded = false;
    };
    
    img.src = this.spriteImagePath;
}

How it meets the requirement:

  • Load Success: Log when sprites are ready
  • Load Failure: Warn when assets fail to load

4. Error Handling - try/catch Blocks

GameLevelMaze.js - NPC Dialog Error Handling

interact: function () {
    // Clear any existing dialogue first to prevent duplicates
    if (this.dialogueSystem && this.dialogueSystem.isDialogueOpen()) {
        this.dialogueSystem.closeDialogue();
    }

    // Create a new dialogue system if needed - lazy initialization
    if (!this.dialogueSystem) {
        try {  // ← TRY: attempt to create DialogueSystem
            this.dialogueSystem = new DialogueSystem();
        } catch (error) {  // ← CATCH: if creation fails
            console.error('Error creating DialogueSystem:', error);
            return;  // Exit gracefully
        }
    }

    const whattosay = "Welcome to the coolest maze this side of the atlantic ocean, escape or get rekt lol"

    try {  // ← TRY: display dialogue
        this.dialogueSystem.showDialogue(
            whattosay,
            "mr portensen",
            this.spriteData.src,
            {
                columns: 3,
                rows: 4,
                frameX: 0,
                frameY: 0,
                frameWidth: 78,
                frameHeight: 108
            }
        );

        this.dialogueSystem.addButtons([
            {
                text: "Enter the maze",
                primary: true,
                action: () => {
                    this.dialogueSystem.closeDialogue();
                    this.destroy();
                }
            }
        ]);

    } catch (error) {  // ← CATCH: if dialogue display fails
        console.error('Error calling showDialogue:', error);
    }
}

How it meets the requirement:

  • try/catch Blocks: Handle potential errors
  • Error Logging: Log caught exceptions
  • Graceful Degradation: Continue game if dialog fails

GameLevelOutside.js - Event Listener Error Handling

reaction: function () {
    if (this.dialogueSystem) {
        this.showReactionDialogue();
    } else {
        console.log(sir_morty_greeting);
    }
},

interact: function () {
    try {  // ← TRY: attempt AI interaction
        AiNpc.showInteraction(this);
    } catch (error) {  // ← CATCH: fallback if API fails
        console.error('Error in AiNpc.showInteraction:', error);
        // Show basic dialogue instead of AI response
        if (this.dialogueSystem) {
            this.dialogueSystem.showDialogue(
                this.greeting,
                this.id,
                this.src
            );
        }
    }
}

How it meets the requirement:

  • API Error Handling: Gracefully fail if backend unavailable
  • Fallback Logic: Show basic response if AI fails

Summary

JSDoc Comments - Class and method documentation with @param, @example
Inline Comments - Explain grace periods, state flags, collision logic
Console Logging

  • Grace period timing tracking
  • Collision detection logging
  • Image loading status
    Error Handling
  • try/catch for DialogueSystem creation
  • try/catch for showDialogue() calls
  • Graceful fallbacks when features fail