Input/Output - API Integration & Async I/O
How I implement keyboard input, API calls, async/await, and JSON parsing
Input/Output: Keyboard, APIs, Async, JSON
Requirements
- Keyboard Input - WASD controls
- API Integration - NPC AI backend calls
- Asynchronous I/O - async/await for image loading
- 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