Class_generator/src/gameHelpers/MarioEducational/enemies/Boss.js
StillHammer 325b97060c Add LEDU Chinese course content and documentation
Add comprehensive Chinese reading course (乐读) with 4 chapters of vocabulary, texts, and exercises. Include architecture documentation for module development and progress tracking system.

Content:
- LEDU book metadata with 12 chapter outline
- Chapter 1: Food culture (民以食为天) - 45+ vocabulary, etiquette
- Chapter 2: Shopping (货比三家) - comparative shopping vocabulary
- Chapter 3: Sports & fitness (生命在于运动) - exercise habits
- Chapter 4: Additional vocabulary and grammar

Documentation:
- Architecture principles and patterns
- Module creation guide (Game, DRS, Progress)
- Interface system (C++ style contracts)
- Progress tracking and prerequisites

Game Enhancements:
- MarioEducational helper classes (Physics, Renderer, Sound, Enemies)
- VocabularyModule TTS improvements
- Updated CLAUDE.md with project status

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-15 07:25:53 +08:00

255 lines
8.3 KiB
JavaScript

/**
* Boss.js
* Colossal Boss enemy for level 6
* Large immobile boss with turrets and special attacks
*/
export class Boss {
/**
* Generate the colossal boss for level 6
* @param {Object} level - Level data
* @param {number} levelWidth - Width of the level
* @param {number} canvasHeight - Canvas height
* @returns {Object} - Boss data with turrets
*/
static generate(level, levelWidth, canvasHeight) {
console.log(`👹 Generating Colossal Boss for level 6!`);
// Boss positioned in center-right of level to block the path
const bossX = levelWidth * 0.6; // 60% through the level
const bossY = canvasHeight - 250; // Standing on ground
const bossWidth = 150;
const bossHeight = 200;
const boss = {
x: bossX,
y: bossY,
width: bossWidth,
height: bossHeight,
health: 5, // Takes 5 hits
maxHealth: 5,
color: '#2F4F4F', // Dark slate gray
type: 'colossus',
active: true,
// Collision boxes (knees for damage)
leftKnee: {
x: bossX + 20,
y: bossY + bossHeight - 60,
width: 40,
height: 40
},
rightKnee: {
x: bossX + bossWidth - 60,
y: bossY + bossHeight - 60,
width: 40,
height: 40
},
// Boss behavior
lastTurretShot: Date.now(),
turretCooldown: 2000, // Turrets fire every 2 seconds
lastMinionLaunch: Date.now(),
minionCooldown: 4000, // Launch minions every 4 seconds
// Visual
eyeColor: '#FF0000', // Red glowing eyes
isDamaged: false,
damageFlashTimer: 0,
enraged: false // Becomes enraged at low health
};
// Generate turrets on the boss (2 turrets)
const turrets = [
{
x: bossX + 30,
y: bossY + 50,
width: 25,
height: 25,
color: '#8B4513',
type: 'turret',
lastShot: Date.now(),
shootCooldown: 2500 // Individual cooldown
},
{
x: bossX + bossWidth - 55,
y: bossY + 50,
width: 25,
height: 25,
color: '#8B4513',
type: 'turret',
lastShot: Date.now(),
shootCooldown: 3000 // Slightly different timing
}
];
console.log(`👹 Colossal Boss spawned at x=${bossX.toFixed(0)}, health=${boss.health}`);
console.log(`🔫 ${turrets.length} turrets mounted on boss`);
return { boss, turrets };
}
/**
* Update boss behavior
* @param {Object} boss - Boss object
* @param {Array} turrets - Boss turrets
* @param {Object} mario - Mario object
* @param {Array} projectiles - Projectiles array
* @param {Array} flyingEyes - Flying eyes array (for spawning minions)
* @param {Function} playSound - Sound callback
*/
static update(boss, turrets, mario, projectiles, flyingEyes, playSound) {
if (!boss || !boss.active) return;
const currentTime = Date.now();
// Update boss state
if (boss.health < boss.maxHealth / 2) {
boss.enraged = true;
}
// Damage flash animation
if (boss.isDamaged) {
boss.damageFlashTimer--;
if (boss.damageFlashTimer <= 0) {
boss.isDamaged = false;
}
}
// Update turrets - they shoot projectiles at Mario
turrets.forEach(turret => {
if (currentTime - turret.lastShot > turret.shootCooldown) {
// Calculate trajectory to Mario
const dx = mario.x - turret.x;
const dy = mario.y - turret.y;
const distance = Math.sqrt(dx * dx + dy * dy);
const speed = boss.enraged ? 6 : 4; // Faster when enraged
const velocityX = (dx / distance) * speed;
const velocityY = (dy / distance) * speed;
projectiles.push({
x: turret.x + turret.width / 2,
y: turret.y + turret.height / 2,
velocityX: velocityX,
velocityY: velocityY,
radius: 10,
color: boss.enraged ? '#FF0000' : '#FF8C00', // Red when enraged, orange normally
type: 'boss_projectile',
life: 300
});
turret.lastShot = currentTime;
if (playSound) playSound('enemy_defeat');
console.log(`🔫 Boss turret fired at Mario!`);
}
});
// Spawn flying eye minions periodically
if (boss.enraged && currentTime - boss.lastMinionLaunch > boss.minionCooldown) {
// Spawn a flying eye minion
const minionX = boss.x + boss.width / 2;
const minionY = boss.y + 50;
flyingEyes.push({
x: minionX,
y: minionY,
width: 25,
height: 25,
velocityX: (Math.random() - 0.5) * 2,
velocityY: -3, // Fly upward initially
color: '#8B0000', // Dark red for minions
pupilColor: '#000000',
type: 'flying_eye_minion',
health: 1,
maxHealth: 1,
chaseDistance: 300,
chaseSpeed: 3,
idleSpeed: 1,
lastDirectionChange: Date.now(),
directionChangeInterval: 2000,
isChasing: false,
dashCooldown: 0,
dashDuration: 0,
isDashing: false,
dashSpeed: 6,
lastDashTime: Date.now(),
dashInterval: 4000,
blinkTimer: 0,
isBlinking: false
});
boss.lastMinionLaunch = currentTime;
if (playSound) playSound('powerup');
console.log(`👁️ Boss spawned a flying eye minion!`);
}
}
/**
* Damage the boss
* @param {Object} boss - Boss object
* @param {Function} playSound - Sound callback
* @returns {boolean} - True if boss was defeated
*/
static damage(boss, playSound) {
if (!boss || !boss.active) return false;
boss.health--;
boss.isDamaged = true;
boss.damageFlashTimer = 15; // Flash for 15 frames
if (playSound) playSound('enemy_defeat');
console.log(`👹 Boss damaged! Health: ${boss.health}/${boss.maxHealth}`);
if (boss.health <= 0) {
boss.active = false;
console.log(`👹 BOSS DEFEATED!`);
return true;
}
return false;
}
/**
* Check collision between Mario and boss knees (weak points)
* @param {Object} mario - Mario object
* @param {Object} boss - Boss object
* @returns {boolean} - True if Mario hit a knee from above
*/
static checkKneeCollision(mario, boss) {
if (!boss || !boss.active) return false;
// Check if Mario is jumping down onto knees
const isFalling = mario.velocityY > 0;
// Check left knee
const hitLeftKnee = this._isCollidingRectRect(mario, boss.leftKnee) && isFalling;
// Check right knee
const hitRightKnee = this._isCollidingRectRect(mario, boss.rightKnee) && isFalling;
return hitLeftKnee || hitRightKnee;
}
/**
* Check collision between Mario and boss body (damage to Mario)
* @param {Object} mario - Mario object
* @param {Object} boss - Boss object
* @returns {boolean} - True if Mario touched boss body
*/
static checkBodyCollision(mario, boss) {
if (!boss || !boss.active) return false;
return this._isCollidingRectRect(mario, boss);
}
/**
* Rectangle-Rectangle collision detection
*/
static _isCollidingRectRect(rect1, rect2) {
return rect1.x < rect2.x + rect2.width &&
rect1.x + rect1.width > rect2.x &&
rect1.y < rect2.y + rect2.height &&
rect1.y + rect1.height > rect2.y;
}
}
export default Boss;