Castle Game
Explore the castle and free the prisoner.
CS111 Requirements
| Section Name | Description | Evidence of Implementation |
|---|---|---|
| Object Oriented Programming (OOP) | ||
| Writing Classes | Creating class definitions to encapsulate data and behavior | Writing Classes |
| Methods & Parameters | Defining functions within classes that accept input parameters | Methods & Parameters |
| Instantiation & Objects | Creating instances of classes and working with object instances | Instantiation & Objects |
| Inheritance (Basic) | Creating subclasses that inherit properties and methods from parent classes | Inheritance (Basic) |
| Method Overriding | Redefining methods in subclasses to provide specific implementations | Method Overriding |
| Constructor Chaining | Calling parent class constructors from child class constructors | Constructor Chaining |
| Control Structures | ||
| Iteration | Iterating through a list using loops | Iteration |
| Conditionals | Using if, else if, else statements | Conditionals |
| Nested Conditions | Using nested if-else statements | Nested Conditions |
| Data Types | ||
| Numbers | Number can be used for positions, indexes, etc. | Numbers |
| Strings | Strings can be used for dialogue and paths | Strings |
| Booleans | Booleans can be used for conditions | Booleans |
| Arrays | Arrays can be used for lists | Arrays |
| Objects (JSON) | Objects can be used for data structures | Objects (JSON) |
| Operators | ||
| Mathematical | Mathematical operators can be used for calculations | Mathematical |
| String Operations | String operators can be used for string manipulation | String Operations |
| Boolean Expressions | Boolean expressions can be used for conditions | Boolean Expressions |
| Input/Output (IO) | ||
| Keyboard Input | Capturing user input from the keyboard | Keyboard Input |
| Canvas Rendering | Drawing graphics and animations on a canvas element | Canvas Rendering |
| GameEnv Configuration | Setting up game environment with configuration options | GameEnv Configuration |
| API Integration | Integrating external APIs for data or functionality | |
| Asynchronous I/O | Handling asynchronous operations like API calls or timers | Asynchronous I/O |
| JSON Parsing | Parsing JSON data for configuration or data exchange | JSON Parsing |
| Documentation | ||
| Code Comments | Adding comments to explain classes and methods | Code Comments |
| Mini-Lesson Documentation | Create comic/visual post with embedded runtime game demo | Mini-Lesson Documentation |
| Code Highlights | Annotate key code snippets in documentation (OOP, APIs, collision) | Code Highlights |
| Debugging | ||
| Console Debugging | Using console.log() and other debugging techniques to identify and fix issues | Console Debugging |
| Hit Box Visualization | Using visual debugging to understand collision detection | |
| Source-Level Debugging | Using browser developer tools to step through code and inspect variables | Source-Level Debugging |
| Network Debugging | Using browser developer tools to inspect network requests and responses | |
| Application Debugging | Using browser developer tools to inspect application state and behavior | Application Debugging |
| Element Inspection | Using browser developer tools to inspect HTML elements and their properties | Element Inspection |
| Testing & Verification | ||
| Gameplay Testing | Testing game mechanics, controls, and overall user experience | Gameplay Testing |
| Integration Testing | Testing the interaction between different components of the game | Integration Testing |
| API Error Handling | Handling errors when integrating external APIs |
Each Programming Concept Demonstrated is shown below.
OOP Evidence
Writing Classes
// GameLevelFortress.js - Main game level class
class GameLevelFortress {
constructor(gameEnv) {
this.gameEnv = gameEnv;
this.scytheSpawnTimer = -300;
this.scytheSpawnInterval = 120;
// ... initialization code
}
}
// UnifiedScythe.js - Enemy projectile class
class UnifiedScythe extends Enemy {
constructor(gameEnv, type = 'regular', spawnX = null, spawnY = null) {
const typeConfig = UnifiedScythe.getTypeConfig(type, path, width, spawnX, spawnY, gameEnv);
super(scytheData, gameEnv);
// ... scythe-specific initialization
}
}
Methods & Parameters
// Interceptor.js - Methods with parameters for targeting
findNearestScythe() {
const scythes = this.gameEnv.gameObjects.filter(obj =>
obj.constructor.name === 'UnifiedScythe' && obj.scytheType === 'regular' && obj.canBeIntercepted()
);
// ... distance calculation logic
}
handleInterception(scythe) {
this.hasIntercepted = true;
this.revComplete = true;
// ... interception logic with scythe parameter
}
Instantiation & Objects
// GameLevelFortress.js - Creating object instances
constructor(gameEnv) {
// Creating player instance
this.classes = [
{ class: Player, data: sprite_data_mc },
{ class: Npc, data: sprite_data_helpful_npc },
{ class: Barrier, data: barrier_data }
];
// Creating scythe instances dynamically
const scythe = new UnifiedScythe(this.gameEnv, 'regular');
this.gameEnv.gameObjects.push(scythe);
}
Inheritance (Basic)
// UnifiedScythe.js inherits from Enemy class
class UnifiedScythe extends Enemy {
constructor(gameEnv, type = 'regular', spawnX = null, spawnY = null) {
super(scytheData, gameEnv); // Calling parent constructor
// ... child-specific initialization
}
}
// Interceptor.js inherits from Character class
class Interceptor extends Character {
constructor(gameEnv, spawnX, spawnY) {
super({ id: 'interceptor' }, gameEnv);
// ... interceptor-specific initialization
}
}
Method Overriding
// UnifiedScythe.js overrides parent update method
update() {
if (this.revComplete) return;
// Check lifespan for timed scythes
if (this.lifespan && this.creationTime) {
const currentTime = Date.now();
if (currentTime - this.creationTime >= this.lifespan) {
this.revComplete = true;
this.destroy();
return;
}
}
// Custom motion update
this.updateMotion();
super.update(); // Call parent update
}
Constructor Chaining
// UnifiedScythe.js - Constructor chaining with super()
constructor(gameEnv, type = 'regular', spawnX = null, spawnY = null) {
const scytheData = {
id: `${type}_scythe_${Math.random().toString(36).substr(2, 9)}`,
src: path + "/images/mansionGame/scythe.png",
// ... configuration
};
super(scytheData, gameEnv); // Chain to parent constructor
// Continue with child-specific initialization
this.scytheType = type;
this.setTypeFlags();
}
IO Evidence
Keyboard Input
// GameLevelFortress.js - Keyboard event handling
setupInterceptorControls() {
this.boundFireInterceptor = this.fireInterceptor.bind(this);
document.addEventListener('keydown', this.boundFireInterceptor);
}
fireInterceptor(event) {
if ((event.code === 'Space' || event.keyCode === 32) ||
(event.code === 'KeyI' || event.keyCode === 73)) {
event.preventDefault();
// Create interceptor at player position
const interceptor = new Interceptor(this.gameEnv, spawnX, spawnY);
this.gameEnv.gameObjects.push(interceptor);
}
}
Canvas Rendering
// UnifiedScythe.js - Canvas drawing with effects
draw() {
this.canvas.width = this.width;
this.canvas.height = this.height;
this.ctx.save();
this.ctx.translate(this.canvas.width / 2, this.canvas.height / 2);
this.ctx.rotate(this.rotationAngle);
// Add glow effects
if (this.glowColor) {
this.ctx.shadowColor = this.glowColor;
this.ctx.shadowBlur = 40;
}
this.ctx.drawImage(this.spriteSheet, 0, 0, this.spriteSheet.naturalWidth,
this.spriteSheet.naturalHeight, -this.width / 2, -this.height / 2,
this.width, this.height);
this.ctx.restore();
}
GameEnv Configuration
// GameLevelFortress.js - Environment setup
constructor(gameEnv) {
let width = gameEnv.innerWidth;
let height = gameEnv.innerHeight;
let path = gameEnv.path;
// Configure game environment
this.gameEnv.scoreConfig = {
counterVar: 'finalScore',
counterLabel: 'Score',
scoreVar: 'finalScore'
};
// Initialize scoring system
this.gameEnv.stats = {
scythesDestroyed: 0,
survivalTime: 0,
finalScore: 0,
gameName: 'FortressGame'
};
}
Asynchronous I/O
// GameLevelFortress.js - Async operations with timers and promises
initializeLeaderboard() {
// Async score manager initialization
this.gameEnv.initScoreManager().then(() => {
console.log('Score manager initialized successfully');
if (this.gameEnv.scoreManager) {
this.gameEnv.scoreManager.toggleScoreDisplay();
}
}).catch(error => {
console.warn('Failed to initialize score manager:', error);
});
}
// Timer-based async operations
update() {
this.gameTimer++;
// Update survival time every 60 frames (1 second)
if (this.gameTimer % 60 === 0) {
this.updateSurvivalTime();
}
}
JSON Parsing
// GameLevelFortress.js - JSON-like object configuration
const sprite_data_mc = {
id: 'Knight',
greeting: "Hi, I am a Knight.",
src: sprite_src_mc,
SCALE_FACTOR: MC_SCALE_FACTOR,
STEP_FACTOR: 500,
ANIMATION_RATE: 100,
INIT_POSITION: { x: 0.5 * width, y: 0.8 * height },
pixels: { height: 432, width: 234 },
orientation: { rows: 4, columns: 3 },
keypress: { up: 87, left: 65, down: 83, right: 68 }
};
Documentation Evidence
Code Comments
/**
* Represents the Fortress game level with all game objects and systems
* @class GameLevelFortress
*/
class GameLevelFortress {
/**
* Constructs the Fortress game level with all game objects and systems
* @param {Object} gameEnv - The game environment containing width, height, path, and other properties
*/
constructor(gameEnv) {
/**
* Timer for scythe spawning - increments each frame
* @type {number}
*/
this.scytheSpawnTimer = -300; // Delay the first spawn
/**
* Interval for scythe spawning (120 frames = 2 seconds at 60 FPS)
* @type {number}
*/
this.scytheSpawnInterval = 120;
}
}
Mini-Lesson Documentation
Spline Barrier Mini-Lesson Documentation
Platformer Mini-Lesson Documentation
Code Highlights
Key code snippets highlighted throughout the implementation:
- OOP: Class inheritance with
UnifiedScythe extends Enemy - Collision Detection: Distance-based collision algorithms
- Event Handling: Keyboard and touch input processing
- Animation: Canvas rendering with rotation and effects
Debugging Evidence
Console Debugging
// GameLevelFortress.js - Console logging for debugging
console.log('Scythe destroyed! New score:', this.gameEnv.stats.finalScore);
console.log('Level completed! Final scores:', this.scores);
console.warn('Could not find level with onScytheDestroyed method');
console.error('Error creating DialogueSystem:', error);
// Interceptor.js - Debug logging
console.log('SuperScythe spawned at top of screen with 4 key!');
console.warn('No player found for interceptor firing');
Source-Level Debugging
// GameLevelFortress.js - Error handling with try-catch
try {
const audioElements = document.querySelectorAll('audio');
audioElements.forEach(audio => {
try { if (!audio.paused) audio.pause(); } catch (e) { }
});
} catch (e) { /* ignore */ }
// UnifiedScythe.js - Conditional debugging
if (players.length === 0) {
console.error("No player found in game environment");
return { x: 0, y: 0 };
}
Application Debugging
// GameLevelFortress.js - State inspection
initializeScoring() {
// Initialize stats object if it doesn't exist
if (!this.gameEnv.stats) {
this.gameEnv.stats = {};
}
// Set initial scores for debugging
this.gameEnv.stats.scythesDestroyed = 0;
this.gameEnv.stats.survivalTime = 0;
this.gameEnv.stats.finalScore = 0;
}
// Interceptor.js - Runtime state checking
checkScytheInterception() {
if (this.hasIntercepted) return; // Prevent duplicate interceptions
// Debug: Check if scythes exist
const scythes = this.gameEnv.gameObjects.filter(obj =>
obj.constructor.name === 'UnifiedScythe' && obj.scytheType === 'regular'
);
if (scythes.length === 0) return; // No targets available
}
Element Inspection
// DialogueSystem.js - DOM element creation and inspection
createDialogueBox() {
this.dialogueBox = document.createElement("div");
this.dialogueBox.id = "custom-dialogue-box-" + this.id;
// Set styles for inspection
Object.assign(this.dialogueBox.style, {
position: "absolute",
bottom: "20px",
left: "50%",
zIndex: "9999",
display: "none" // Initially hidden for debugging
});
}
// GameLevelFortress.js - Element manipulation for debugging
createTimerDisplay() {
this.timerElement = document.createElement('div');
this.timerElement.id = 'game-timer';
// Style for easy inspection in dev tools
this.timerElement.style.position = 'absolute';
this.timerElement.style.zIndex = '10000';
this.timerElement.style.backgroundColor = 'rgba(0,0,0,0.5)';
}
Testing Evidence
Gameplay Testing
// GameLevelFortress.js - Gameplay mechanics testing
update() {
// Test scythe spawning system
this.scytheSpawnTimer++;
if (this.scytheSpawnTimer >= this.scytheSpawnInterval) {
const numScythes = Math.floor(Math.random() * MAX_SCYTHES) + 1;
for (let i = 0; i < numScythes; i++) {
this.spawnScythe(); // Test spawn functionality
}
this.scytheSpawnTimer = 0;
}
}
// Test player collision detection
onLevelCompleted() {
if (!this.levelCompleted) {
this.levelCompleted = true;
this.scores.completionTime = Math.floor((Date.now() - this.startTime) / 1000);
console.log('Level completed! Final scores:', this.scores);
}
}
Integration Testing
// Interceptor.js - Component integration testing
handleInterception(scythe) {
// Test integration between interceptor and scythe
const accuracy = 0.75; // 75% accuracy for testing
const willHit = Math.random() < accuracy;
if (willHit) {
// Test successful integration
this.createInterceptionEffect();
scythe.destroy();
// Test score system integration
if (typeof window !== 'undefined' && window.currentGameLevel &&
window.currentGameLevel.onScytheDestroyed) {
window.currentGameLevel.onScytheDestroyed();
}
}
}
// GameLevelFortress.js - System integration testing
initializeScoring() {
// Test integration between scoring and game environment
this.gameEnv.scoreConfig = {
counterVar: 'finalScore',
counterLabel: 'Score',
scoreVar: 'finalScore'
};
// Test integration with leaderboard
this.gameEnv.initScoreManager().then(() => {
console.log('Score manager initialized successfully');
}).catch(error => {
console.warn('Failed to initialize score manager:', error);
});
}