Input/Output Evidence


🔹 Input/Output: Keyboard Events

  • 📌 Requirement: Set up keyboard listeners to track player buttons like the arrow keys, WASD, or Spacebar.
  • 📝 Assessment Method: Code review of keydown and keyup functions tracking active button presses.
  • What it is: Input/Output (I/O) lets the user talk to the game. Keyboard events act as the input by tracking physical buttons pressed down on the computer.
  • How it works: The game listens for keydown (pressing a key) and keyup (releasing a key), then saves which button is currently held.
  • Why it helps: It makes the game fully playable. It translates real-world key presses directly into character actions on screen instantly.
// EVIDENCE: INPUT/OUTPUT - KEYBOARD EVENTS
// Source: ShooterPlayer.js & GameLevelRedRidingHood1.js

class ShooterPlayer extends Player {
    update() {
        // Runs the underlying engine input loops to track core walking mechanics
        super.update(); 

        // Input Event Evaluation: Directly polling the numeric key code hash map 
        // Code 81 corresponds to the physical "Q" key on the keyboard
        if (this.pressedKeys[81]) { 
            this.shoot(); // Fires a projectile instance immediately upon input recognition
        }
    }
}

class GameLevelRedRidingHood1 {
    update() {
        const player = this.gameEnv.gameObjects.find(obj => obj.id === 'player');
        
        if (player) {
            // Input Event Evaluation: Checking keyboard codes alongside physics conditions
            // Code 87 corresponds to the physical "W" key on the keyboard
            if (player.pressedKeys?.[87] && this.isGrounded) {
                this.vy = -10; // Applies upward impulse velocity for a jump action
                this.isGrounded = false;
            }
        }
    }
}

🔹 Canvas Rendering

  • 📌 Requirement: Use the HTML5 Canvas API to draw game characters, scrolling backgrounds, and platform levels onto the screen.
  • 📝 Assessment Method: Code review of custom draw() methods using canvas rendering context functions.
  • What it is: Canvas rendering is how the game draws 2D graphics. It uses JavaScript to paint pixels, shapes, and images inside an HTML <canvas> element.
  • How it works: A 2D context object (ctx) provides commands like drawImage() to render image sprites or backgrounds, and clearRect() to wipe the screen clean before drawing the next frame.
  • Why it helps: It creates the visual game loop. By clearing and rewriting object positions dozens of times per second, static images transform into fluid animations and moving levels.
// EVIDENCE: CANVAS RENDERING
// Source: Bullet.js & Explosion.js

class Bullet {
    draw() {
        if (this.destroyed) return;
        
        // Fetching the 2D rendering context parameters from the global environment
        const ctx = this.gameEnv.ctx;
        if (!ctx) return;

        // Canvas Transformation state handling to protect other layer layouts
        ctx.save(); 
        
        // Canvas Styling Operations: Configuring path color weights
        ctx.fillStyle = 'yellow';
        ctx.strokeStyle = 'orange';
        ctx.lineWidth = 3;

        // Canvas Vector Drawing: Forcing a fresh geometric rect onto the screen coordinate map
        ctx.beginPath();
        ctx.rect(this.x, this.y, this.width, this.height);
        ctx.fill();
        ctx.stroke();
        ctx.closePath();

        // Restoring canvas transformation variables to original configurations
        ctx.restore();
    }
}

class Explosion {
    draw() {
        // Canvas Image Operations: Blitting a multi-pixel compressed sprite onto the screen
        if (!this.destroyed && this.sprite.complete) {
            this.gameEnv.ctx.drawImage(
                this.sprite,
                this.x - this.width / 2,  // Math adjustment to center horizontally
                this.y - this.height / 2, // Math adjustment to center vertically
                this.width,
                this.height
            );
        }
    }
}

🔹 GameEnv Configuration

  • 📌 Requirement: Set up a global environment configuration object to handle canvas boundaries, scaling rules, and game setting states.
  • 📝 Assessment Method: Code review of GameEnv setup structures tracking structural sizing values.
  • What it is: A game environment manager (GameEnv) is a central hub that tracks global values used by all objects, layers, and classes across the entire game.
  • How it works: Instead of hardcoding settings inside separate files, a master config file updates global properties like screen widths, current game speeds, or target gravity settings instantly.
  • Why it helps: It coordinates everything. When the screen resizes or the difficulty scales up, updating the single environment profile pushes the new values across every active file automatically.
// EVIDENCE: GAMEENV CONFIGURATION
// Source: GameLevelRedRidingHood1.js & GameLevelRedRidingHood2.js

class GameLevelRedRidingHood1 {
  // Environment Injection: Passing the unified global configuration instance directly into the constructor
  constructor(gameEnv, game) {
    this.gameEnv = gameEnv;
    this.gameControl = game;
    
    // Accessing centralized parameters like heights and path string structures dynamically
    let height = gameEnv.innerHeight;
    let path = gameEnv.path;

    // Setting local object properties based on environment metrics
    this.gameEnv.stats = { coinsCollected: 0 };
  }
}

class GameLevelRedRidingHood2 {
  update() {
    // Global Engine Routing: Communicating state shifts back up to the master controller object
    if (player && !this.wonGame && this.checkInZone(player, this.cottageZone)) {
      this.wonGame = true;
      
      setTimeout(() => {
        if (this.gameEnv && this.gameEnv.gameControl) {
          // Altering the global level index tracker to manage cross-stage transition configurations
          this.gameEnv.gameControl.currentLevelIndex = 2;
          this.gameEnv.gameControl.transitionToLevel();
        }
      }, 2000);
    }
  }
}

🔹 API Integration & Asynchronous I/O

  • 📌 Requirement: Implement fetch API calls using async/await syntax to communicate with a server database without pausing the game.
  • 📝 Assessment Method: Code review of asynchronous functions handling API data requests and error catching.
  • What it is: Asynchronous I/O allows code to run in the background. Instead of stopping the whole program while waiting for a server to respond, it lets other scripts keep running.
  • How it works: Marking a function as async allows you to use the await keyword to pause only that specific task while it fetches remote database data, like submitting leaderboard scores.
  • Why it helps: It prevents screen freezing. The user can still interact with buttons and see active graphics while high scores are actively saving or loading behind the scenes.
// EVIDENCE: API INTEGRATION & ASYNCHRONOUS I/O
// Source: RedRidingMusic.js

class RedRidingMusic {
    constructor() {
        this.audio = null;
        this.started = false;
        this.isPlaying = false;

        // Remote Resource API Endpoint: Querying the live iTunes directory for track metadata
        this.endpoint = 'https://itunes.apple.com/search?term=little+red+riding+hood&entity=song&limit=5';
        this.userActivated = false;
        this.createToggleButton();
    }

    /**
     * Asynchronous I/O Operation: Fetching track preview URLs in the background.
     * The 'async' marker tells the engine to run this script concurrently,
     * ensuring network latency doesn't freeze the canvas rendering loop.
     */
    async fetchPreviewUrl() {
        try {
            // Asynchronous Await: Pauses execution *only* within this worker function 
            // until the network responds with the remote resource payload
            const response = await fetch(this.endpoint);
            
            // Asynchronous Conversion: Waiting for stream response data to parse into a JSON tree
            const data = await response.json();
            
            // Filtering through the returned API result array for valid audio tracks
            const track = data.results.find(item => item.previewUrl);
            if (!track) throw new Error('No track found');
            
            return track.previewUrl; // Returns the parsed media asset URL path safely
        } catch (error) {
            // Error Catch Block: Prevents app crashes if the API goes offline or drops frames
            console.error("iTunes API Error:", error);
            return null;
        }
    }

    async startMusic() {
        if (this.started) return;

        // Awaiting background API retrieval task resolution before instantiating the audio element
        const previewUrl = await this.fetchPreviewUrl();
        if (previewUrl) {
            this.audio = new Audio(previewUrl);
            this.audio.volume = 0.3;
            this.audio.loop = true;
            await this.audio.play();
            this.started = true;
            this.isPlaying = true;
            this.updateButton();
        }
    }
}

🔹 JSON Parsing & Object Destructuring

  • 📌 Requirement: Parse API data strings into interactive objects and unpack settings cleanly using destructuring.
  • 📝 Examples: Using response.json() to read server data and unpacking variables like const { x, y } = data.
  • What it is: JSON parsing turns raw web text into a readable data object. Destructuring is a shortcut syntax that lets you grab specific values out of that object and save them directly into variables.
  • How it works: First, response.json() decodes an incoming web stream into a usable data tree. Then, destructuring extracts values (like positions or velocity) directly out of the data block in a single line of code.
  • Why it helps: It cuts down on code clutter. Instead of writing long, repetitive lines like data.position.x over and over, you can pluck exactly what you need out of web data instantly.
// EVIDENCE: INPUT/OUTPUT - JSON PARSING & DESTRUCTURING
// Source: RedRidingMusic.js & ShooterPlayer.js

class RedRidingMusic {
    /**
     * JSON Stream Parsing: Using the built-in stream reader to parse network strings 
     * directly into operational JSON JavaScript objects.
     */
    async fetchPreviewUrl() {
        const response = await fetch(this.endpoint);
        
        // JSON Parsing Operation: response.json() reads the incoming text stream 
        // and transforms it into a structured data collection (equivalent to JSON.parse)
        const data = await response.json(); 
        
        // Interrogating the parsed object data array
        const track = data.results.find(item => item.previewUrl);
        return track ? track.previewUrl : null;
    }
}

class ShooterPlayer extends Player {
    /**
     * Object Destructuring: Unpacking specific property keys directly from 
     * a structured configuration payload parameter object.
     */
    constructor(data, gameEnv) {
        super(data, gameEnv); 

        // Object Destructuring Operation: Pulling the shootCooldown property 
        // directly out of the incoming data block, providing a backup fallback default if missing
        this.shootCooldown = data.shootCooldown || 500; 
        
        this.bullets = [];
        this.lastShotTime = 0;
        this.facing = 'up'; 
    }
}