Control Structures - Conditionals & Loops
How I use if/else, nested conditions, and loops for game logic
Control Structures: Conditionals, Loops, & Nested Conditions
Requirements
- Use loops for game object arrays and animation frames
- Implement conditionals for collision detection and state transitions
- Use nested conditions for complex game logic
Evidence
Conditionals (if/else)
Ghost.js - Conditional Logic for Following Player
getPlayer() {
return this.gameEnv?.gameObjects?.find(obj => obj instanceof Player) || null; // ← Conditional OR
}
followPlayer(player) {
if (!player) return; // ← Guard clause: conditional check
const ghostCenter = this.getCenter();
const playerCenter = typeof player.getCenter === 'function' // ← Type check conditional
? player.getCenter()
: { x: player.x || 0, y: player.y || 0 };
const dx = playerCenter.x - ghostCenter.x;
const dy = playerCenter.y - ghostCenter.y;
const distance = Math.hypot(dx, dy);
if (distance <= this.followStopDistance) { // ← Conditional: distance check
this.velocity.x = 0;
this.velocity.y = 0;
return; // ← Early return if condition met
}
// Continue following if distance > followStopDistance
const baseSpeed = player?.xVelocity || (this.gameEnv?.innerWidth || 800) / 2000;
const speed = Math.max(0.3, baseSpeed * this.followSpeedFactor);
}
How it meets the requirement:
- Guard Clause:
if (!player) returnprevents null reference errors - Type Checking: Uses ternary conditional to handle different player object types
- Distance Condition: Stops movement when within
followStopDistance
DeathBarrier.js - Nested Conditionals for Collision Detection
update() {
super.update();
if (this._hasTriggeredDeath) return; // ← First condition: prevent duplicate triggers
const player = this.gameEnv?.gameObjects?.find(obj => obj.constructor?.name === 'Player');
if (!player || !player.canvas || !this.canvas) return; // ← Multiple AND conditions
this.isCollision(player);
if (this.collisionData?.hit) { // ← Second level condition: check collision
// NESTED CONDITIONS - Third level: grace period logic
const timeSinceLevelStart = new Date() - DeathBarrier.levelStartTime;
if (timeSinceLevelStart < 500) { // ← Nested condition: grace period active
console.log('[MazeDebug] Grace period active:', timeSinceLevelStart, 'ms');
return; // Exit without triggering death
}
// If grace period passed, trigger death
this._hasTriggeredDeath = true;
player.isDead = true;
try {
showDeathScreen(player, 'You got lost in the maze.');
} catch (error) {
console.error('DeathBarrier failed to show death screen:', error);
this._hasTriggeredDeath = false;
player.isDead = false;
}
}
}
How it meets the requirement:
- Multiple AND Conditions:
if (!player || !player.canvas || !this.canvas) - Nested Conditions: Grace period check inside collision check
- State Management: Uses boolean flags to track collision state
Ghost.js - Direction Logic with Nested Conditionals
followPlayer(player) {
// ... distance calculations ...
const nx = dx / distance;
const ny = dy / distance;
this.position.x += nx * speed;
this.position.y += ny * speed;
// NESTED CONDITIONALS: determine direction based on x/y distances
if (Math.abs(dx) >= Math.abs(dy)) { // ← First condition: horizontal movement greater
this.direction = dx >= 0 ? 'right' : 'left'; // ← Nested ternary: positive/negative x
} else { // ← Else: vertical movement greater
this.direction = dy >= 0 ? 'down' : 'up'; // ← Nested ternary: positive/negative y
}
}
How it meets the requirement:
- Nested Conditions: if/else with ternary operators inside
- Complex Logic: Compares two values to determine animation direction
Loops (for, forEach, Array methods)
GameLevelOutside.js - Starfield Animation Loop
const starLayers = [
{ count: 140, speed: 0.25, size: [0.6, 1.4], alpha: [0.2, 0.5] },
{ count: 80, speed: 0.6, size: [1.0, 2.2], alpha: [0.4, 0.8] },
{ count: 35, speed: 1.1, size: [1.6, 3.4], alpha: [0.5, 0.9] }
];
// ← Array.map() loop: transform each layer into star state
const starState = starLayers.map(layer => ({
speed: layer.speed,
stars: Array.from({ length: layer.count }, () => ({ // ← Array.from() loop
x: Math.random(),
y: Math.random(),
r: layer.size[0] + Math.random() * (layer.size[1] - layer.size[0]),
a: layer.alpha[0] + Math.random() * (layer.alpha[1] - layer.alpha[0])
}))
}));
// ← forEach loop: update and draw each star
const drawStars = () => {
starState.forEach(layer => { // ← For each layer
layer.stars.forEach(star => { // ← For each star in layer (nested loop)
star.y += layer.speed / h; // Update position
if (star.y > 1) { // Reset if off-screen
star.y = 0;
star.x = Math.random();
}
starCtx.fillStyle = `rgba(200, 220, 255, ${star.a})`;
starCtx.beginPath();
starCtx.arc(star.x * w, star.y * h, star.r, 0, Math.PI * 2);
starCtx.fill();
});
});
};
How it meets the requirement:
- Array.map(): Transform layer configuration into star state
- Array.from(): Create array of random stars for each layer
- forEach() Loop: Iterate through layers and stars for drawing
- Nested Loops: Multiple levels of iteration for animation
GameLevelMaze.js - Multiple Loops for Barrier Creation
// All death barriers defined in configuration
const dbarrier_1 = { id: 'dbarrier_1', x: 498 / 505 * width, ... };
const dbarrier_2 = { id: 'dbarrier_2', x: 0 / 505 * width, ... };
// ... more barriers ...
// ← Array of objects that will be looped through by game engine
this.classes = [
{ class: GameEnvBackground, data: bgData },
{ class: Player, data: sprite_data_mc },
{ class: Npc, data: mortyData },
{ class: DeathBarrier, data: dbarrier_1 }, // ← Will be instantiated in a loop
{ class: DeathBarrier, data: dbarrier_2 },
{ class: DeathBarrier, data: dbarrier_3 },
// ... 16 more barriers ...
{ class: DeathBarrier, data: dbarrier_19 }
];
// Game engine internally iterates:
// for (let config of this.classes) {
// let obj = new config.class(config.data, gameEnv);
// }
How it meets the requirement:
- Array Structure: Array of configuration objects for game engine to loop through
- 19 Barrier Instances: Demonstrates understanding of how loops instantiate multiple objects
Summary
✅ Conditionals (if/else) - Guard clauses, type checking, state validation
✅ Nested Conditions - Grace period + collision check, direction determination
✅ Loops (forEach) - Iterate through game objects and stars
✅ Array Methods - map(), from() for transforming arrays
✅ Complex Logic - Combines loops and conditions for game mechanics