Input/Output: Keyboard, APIs, Async, JSON

Requirements

  1. Keyboard Input - WASD controls
  2. API Integration - NPC AI backend calls
  3. Asynchronous I/O - async/await for image loading
  4. JSON Parsing - Parse API responses

1. Keyboard Input - WASD Control Configuration

GameLevelOutside.js - Keyboard Setup

const sprite_data_mc = {
    id: 'Knight',
    greeting: "Hi, I am a Knight.",
    src: sprite_src_mc,
    SCALE_FACTOR: MC_SCALE_FACTOR,
    STEP_FACTOR: 1500,
    ANIMATION_RATE: 40,
    // ... other properties ...
    keypress: { 
        up: 87,      // ← W key code
        left: 65,    // ← A key code
        down: 83,    // ← S key code
        right: 68    // ← D key code
    }  // ← Configuration for WASD controls
};  // ← Game engine uses this for event listeners

How it meets the requirement:

  • Keyboard Event Listeners: Game engine reads keypress config and sets up event handlers
  • WASD Input: W=87, A=65, S=83, D=68 (ASCII keycodes)

GameLevelMaze.js - Keyboard Controls

const sprite_data_mc = {
    id: 'Knight',
    // ... sprite properties ...
    keypress: { 
        up: 87,      // W
        left: 65,    // A
        down: 83,    // S
        right: 68    // D
    }
};  // ← Player can navigate maze with WASD

How it meets the requirement:

  • Keyboard Input: WASD configuration for maze navigation

2. API Integration - NPC AI Interaction

GameLevelOutside.js - AI NPC with Backend Integration

const sir_morty_data = {
    id: "Sir Morty",
    greeting: "Hello! I'm Sir Morty!",
    src: sir_morty,
    expertise: "default",              // ← Backend topic area
    chatHistory: [],                   // ← Conversation memory
    dialogues: [                       // ← Random greetings
        "Enter the castle if you dare!",
        "The Dark Knight awaits inside.",
        "I heard there's a treasure in the castle.",
        "Beware of the traps in the castle!",
        "The castle has stood for centuries."
    ],
    knowledgeBase: {                   // ← JSON for backend context
        default: [
            {
                question: "What is inside the castle?",
                answer: "Inside the castle lays a prisoner who has been locked away for years..."
            },
            {
                question: "Who are you?",
                answer: "I am Sir Morty, a brave knight of the castle..."
            },
            {
                question: "How do I win the game?",
                answer: "To win the game, you need to successfully navigate through the castle grounds..."
            }
        ]
    },
    // ← Orchestrator: Handle player interaction (E key press)
    interact: function () {
        // Delegate to AiNpc utility for full AI conversation interface
        AiNpc.showInteraction(this);  // ← Call to API service
    }
};  // ← Configuration includes AI backend integration

How it meets the requirement:

  • API Integration: AiNpc.showInteraction() sends data to backend
  • Knowledge Base: JSON structure for AI context
  • Chat History: Array to store conversation state

3. Asynchronous I/O - Async Image Loading

SpriteSheetCoin.js - Async Image Loading with Callbacks

class SpriteSheetCoin extends Coin {
    constructor(data = null, gameEnv = null) {
        super(data, gameEnv);
        this.spriteImagePath = data?.spriteImagePath || null;
        this.spriteImage = null;
        this.isImageLoaded = false;
        // ...
        if (this.spriteImagePath) {
            this.loadImage();  // ← Call async load
        }
    }

    /**
     * Load the sprite image asynchronously
     */
    loadImage() {
        const img = new Image();  // ← Create async image loader
        
        // ← ASYNC: onload callback fires when image loads
        img.onload = () => {
            this.spriteImage = img;      // ← Store loaded image
            this.isImageLoaded = true;   // ← Set flag
            console.log(`SpriteSheetCoin image loaded: ${this.spriteImagePath}`);
        };
        
        // ← ASYNC: onerror callback fires on load failure
        img.onerror = () => {
            console.warn(`Failed to load SpriteSheetCoin image: ${this.spriteImagePath}`);
            this.isImageLoaded = false;
        };
        
        img.src = this.spriteImagePath;  // ← Trigger async load
    }

    /**
     * Draw the coin using spritesheet if available
     */
    draw() {
        if (!this.ctx) return;
        if (this.collected) return;
        
        // ← Check if async load completed
        if (this.isImageLoaded && this.spriteImage) {
            this.drawSpriteImage();  // ← Use loaded image
        } else if (this.fallbackToCircle) {
            this.drawCircle();  // ← Fallback while loading
        }
    }
}

How it meets the requirement:

  • Image onload: Async callback when image loads
  • Error Handling: Fallback rendering if load fails
  • Non-blocking: Game continues while image loads

GameLevelOutside.js - Async/Await for Transitions

const runTransitionDialogue = async () => {  // ← ASYNC function
    for (let i = 0; i < transitionDialogues.length; i++) {
        await typeLine(transitionDialogues[i]);    // ← AWAIT typing animation
        await sleep(lineHoldMs);                   // ← AWAIT pause between lines
        await eraseLine();                         // ← AWAIT erase animation
        await sleep(120);
    }
};

(async () => {  // ← IIFE async
    // Keep sync with fade-in so both effects complete before changing levels
    await Promise.all([  // ← AWAIT multiple async operations
        runTransitionDialogue(),
        sleep(fadeInMs)
    ]);

    // ... level transition code ...
    
    // Clean up current level properly
    if (gameControl.currentLevel) {
        gameControl.currentLevel.destroy();
    }

    // Change the level classes to GameLevelArchery
    gameControl.levelClasses = [GameLevelArchery];
    gameControl.currentLevelIndex = 0;
    gameControl.isPaused = false;

    // Fade out overlay
    setTimeout(() => {
        fadeOverlay.style.transition = `opacity ${fadeOutMs}ms ease-in-out`;
        fadeOverlay.style.opacity = '0';
        
        setTimeout(() => {
            // Remove overlays
            gameControl.transitionToLevel();  // ← Start next level
        }, fadeOutMs + 150);
    }, 200);
})();

How it meets the requirement:

  • async Functions: Async/await syntax for asynchronous operations
  • await Keywords: Wait for animations and transitions
  • Promise.all(): Wait for multiple async operations

4. JSON Parsing - Knowledge Base & Configuration

GameLevelOutside.js - JSON Knowledge Base for AI

const sir_morty_data = {
    id: "Sir Morty",
    chatHistory: [],  // ← Will store parsed JSON responses
    knowledgeBase: {   // ← JSON structure for backend
        default: [
            {  // ← JSON object
                question: "What is inside the castle?",           // STRING key/value
                answer: "Inside the castle lays a prisoner..."   // STRING key/value
            },
            {
                question: "Who are you?",
                answer: "I am Sir Morty, a brave knight..."
            },
            {
                question: "How do I win the game?",
                answer: "To win the game, you need to successfully navigate..."
            },
            {
                question: "Any tips for the archery challenge?",
                answer: "In the archery challenge, timing and precision are key..."
            },
            {
                question: "What can you tell me about the Dark Knight?",
                answer: "The Dark Knight is a formidable opponent..."
            }
        ]  // ← Array of JSON objects
    },
    interact: function () {
        // Backend receives this knowledgeBase JSON
        // Backend sends back: { response: "...", confidence: 0.95 }
        // Frontend parses JSON response and displays to user
        AiNpc.showInteraction(this);
    }
};

How it meets the requirement:

  • JSON Structure: Nested objects and arrays
  • API Communication: Send JSON to backend, receive parsed responses
  • Data Access: Parse Q&A pairs from knowledge base

Summary

Keyboard Input - WASD key configuration with keycodes
API Integration - AiNpc.showInteraction() calls backend service
Asynchronous I/O

  • Image.onload callbacks for sprite loading
  • async/await for level transitions
  • Promise.all() for parallel operations
    JSON Parsing
  • Knowledge base structure
  • Q&A pair objects
  • Backend response parsing