CS111 Evidence: Input/Output
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) andkeyup(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 likedrawImage()to render image sprites or backgrounds, andclearRect()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
asyncallows you to use theawaitkeyword 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 likeconst { 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.xover 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';
}
}