Input/Output
Input/Output - CS111 Review
| Back | Index | Next |
|---|---|---|
| Operators | Index | Documentation |
Input / Output
Click a category to see how Heist.exe communicates.
Input / Output in Heist.exe
I/O is how your game receives information and sends it back out. In Heist.exe, the player sends input through the keyboard, the engine receives world config at startup, the music system pulls live data from an API, and the canvas outputs everything the player sees every frame.
flowchart LR
A[β¨οΈ WASD Keyboard] --> B[π Game Loop]
C[βοΈ Level Config<br>SCALE_FACTOR,<br>GRAVITY, hitbox] --> B
D[π iTunes API Response<br>preview track URL] --> B
B --> E[π¨ Canvas Render<br>Gem.draw / Guard.draw]
B --> F[π iTunes API Request<br>heistMusic.fetch]
The Four Systems
Keyboard Events β Input β capture physical key presses and map them to in-game actions
Exactly what it is: The browser detects when the player presses or releases a key, and fires events (keydown, keyup). You listen for these events and respond by updating the playerβs state. A key configuration object maps physical key codes to game actions (up, left, down, right).
From Heist.exe:
// HeistL2.js β lines 23-24: Player keypress configuration
keypress: { up: 87, left: 65, down: 83, right: 68 }
// W=87, A=65, S=83, D=68 β WASD controls
// Passed as part of sprite_data_mc to HeistPlayer constructor
const sprite_data_mc = {
id: 'MC',
name: 'mainplayer',
src: path + "/images/projects/heist-exe/heist-mc.png",
SCALE_FACTOR: 10,
STEP_FACTOR: 500,
ANIMATION_RATE: 50,
INIT_POSITION: { x: 0, y: 200 },
keypress: { up: 87, left: 65, down: 83, right: 68 } // WASD
};
// Game engine listens for keydown/keyup events
// When W (87) is pressed β move player up
// When A (65) is pressed β move player left
GameEnv Config β Input β system-level settings that configure the world before gameplay
Exactly what it is: Before the game loop starts, you pass a configuration object to every entity. This object specifies spawn position, collision box size, animation speed, physics settings, and more. Changes to this config change behavior without touching any code.
From Heist.exe:
// HeistL2.js β sprite_data_guard1 configuration
const sprite_data_guard1 = {
id: 'Guard1',
name: 'guard1',
src: path + "/images/projects/heist-exe/heist-guard.png",
SCALE_FACTOR: 10, // Render size: 10x actual sprite pixels
STEP_FACTOR: 500, // Movement speed in pixels per second
ANIMATION_RATE: 50, // Milliseconds per animation frame
INIT_POSITION: { x: 220, y: 300 }, // Spawn point
pixels: { height: 532, width: 400 }, // Sprite sheet dimensions
hitbox: { widthPercentage: 0.45, heightPercentage: 0.2 } // Collision box
};
// HeistL3.js (Level 3) example: Enable gravity for different feel
const sprite_data_player = {
// ... same as above, but also:
GRAVITY: true // Enable downward acceleration unique to this level
};
Same Player class, different config = different game feel. HeistL1 might have small hitboxes; HeistL3 adds gravity.
API Calls β Input + Output β fetch live data from a server and use it in-game
Exactly what it is: Your code sends an HTTP request to an external server (like iTunes Search) asking for data. The server responds with JSON. You parse that JSON, validate it, and use it in your game. This is bidirectional: you output a request, input a response.
From Heist.exe:
// heistMusic.js: Fetch from iTunes Search API
const endpoint = `https://itunes.apple.com/search?term=${encodeURIComponent(picked)}&entity=song&limit=25`;
const response = await fetch(endpoint); // Output: Send HTTP request
if (!response.ok) {
throw new Error('API request failed (' + response.status + ')');
}
const data = await response.json(); // Input: Parse response body
// Filter results
let pool = [];
data.results.forEach(track => {
if (!track.previewUrl) return; // Must have preview URL
if (track.artistName.match(VOCAL_HINTS)) return; // Skip vocal tracks
pool.push(track);
});
// Pick random valid track
const chosen = pool[Math.floor(Math.random() * pool.length)];
const musicUrl = chosen.previewUrl; // Use live data from iTunes
The iTunes API returns different results each time, so each game session gets different background music.
Canvas Rendering β Output β draw everything the player sees every frame
Exactly what it is: You write drawing commands to the canvas context (this.ctx). Each frame, you draw all visible sprites, overlays, and UI elements. If you want something to appear on screen, you have to draw it. If itβs not drawn, itβs not visible.
From Heist.exe:
// Gem.js β lines 24-36: draw() method
draw() {
if (!this.ctx || this.permanentlyCollected) return; // Don't draw if already collected
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
if (this.gemImage.complete && this.gemImage.naturalWidth > 0) {
// Image loaded β draw the actual sprite
this.ctx.drawImage(this.gemImage, 0, 0, this.canvas.width, this.canvas.height);
} else {
// Fallback while image loads β draw cyan circle so gem is never invisible
this.ctx.fillStyle = '#00FFFF';
const cx = this.canvas.width / 2;
const cy = this.canvas.height / 2;
const r = Math.min(this.canvas.width, this.canvas.height) / 3;
this.ctx.beginPath();
this.ctx.arc(cx, cy, r, 0, Math.PI * 2);
this.ctx.fill();
}
this.setupCanvas();
}
// Guard.js: Drawing happens in update() before collision checks
update() {
this.draw(); // Render guard sprite to screen
// ... then check collision
// ... then move
// ... then call draw() again next frame
}
If the gem image hasnβt loaded yet, the cyan circle fallback keeps the gem visible instead of disappearing.
The core idea: Input updates state. Output draws that state. The game loop runs every frame as the bridge between the two β reading keyboard input, applying physics, then rendering the result.