RetroGame / core-engine-ultra.js
Lukeetah's picture
Create core-engine-ultra.js
96dcae9 verified
raw
history blame
50.7 kB
// ===================================================================
// RETRO LEGENDS: Ultimate Edition - Core Engine Ultra Avanzado
// Desarrollado con arquitectura modular profesional y optimización extrema
// ===================================================================
class RetroLegendsUltimateEngine {
constructor() {
// Configuración del canvas y contexto
this.canvas = document.getElementById('gameCanvas');
this.ctx = this.canvas.getContext('2d');
this.setupCanvas();
// Estados del motor
this.engineState = {
isInitialized: false,
isRunning: false,
isPaused: false,
debugMode: false,
performanceMode: 'ultra',
frameRate: 60,
deltaTime: 0,
lastFrameTime: 0,
frameCount: 0,
averageFPS: 60
};
// Estado del juego principal
this.gameState = {
currentLevel: 'caminito_matrix',
score: 0,
lives: 3,
mateCount: 5,
health: 100,
maxHealth: 100,
energy: 100,
maxEnergy: 100,
combo: 0,
maxCombo: 0,
time: 0,
difficulty: 1,
experience: 0,
level: 1,
achievements: new Set(),
powerUps: new Map(),
inventory: new Map()
};
// Configuración del jugador ultra avanzada
this.player = {
// Posición y dimensiones
x: 150,
y: 400,
width: 32,
height: 32,
centerX: 0,
centerY: 0,
// Velocidades y física
velocityX: 0,
velocityY: 0,
acceleration: 0.8,
deceleration: 0.85,
maxSpeed: 8,
jumpPower: 16,
doubleJumpPower: 12,
dashPower: 15,
// Estados del jugador
grounded: false,
canDoubleJump: false,
canDash: true,
isDashing: false,
isAttacking: false,
isInvulnerable: false,
isCharging: false,
// Direcciones y orientación
facing: 'right',
lastDirection: 'right',
// Timers y cooldowns
invulnerabilityTimer: 0,
dashCooldown: 0,
attackCooldown: 0,
chargeCooldown: 0,
// Sprites y animaciones
currentSprite: '🧉',
spriteSet: {
idle: ['🧉', '🧉'],
running: ['🏃‍♂️', '🚶‍♂️'],
jumping: ['🤸‍♂️'],
attacking: ['⚔️', '🥊'],
dashing: ['💨'],
charging: ['⚡', '🔥']
},
animationFrame: 0,
animationSpeed: 200,
lastAnimationTime: 0,
// Estadísticas y progresión
stats: {
strength: 10,
agility: 10,
defense: 10,
luck: 10,
charisma: 10
},
// Habilidades especiales
abilities: {
mateHealing: true,
empanadasPower: false,
choripanShield: false,
fernetRage: false,
tangoTime: false
},
// Sistema de combos argentinos
comboSystem: {
currentCombo: [],
comboTimer: 0,
maxComboTime: 2000,
availableCombos: [
{ sequence: ['che', 'boludo', 'dale'], name: 'Combo Argento', power: 150 },
{ sequence: ['mate', 'asado', 'futbol'], name: 'Combo Patriótico', power: 200 },
{ sequence: ['tango', 'milonga', 'bandoneón'], name: 'Combo Porteño', power: 250 }
]
}
};
// Configuración de físicas avanzadas
this.physics = {
gravity: 0.8,
terminalVelocity: 20,
airResistance: 0.98,
groundFriction: 0.85,
bounceFactor: 0.3,
collisionPadding: 2,
// Configuraciones específicas por material
materials: {
concrete: { friction: 0.8, bounce: 0.1 },
grass: { friction: 0.9, bounce: 0.2 },
ice: { friction: 0.3, bounce: 0.1 },
rubber: { friction: 0.7, bounce: 0.8 },
metal: { friction: 0.6, bounce: 0.4 }
}
};
// Configuración de cámara avanzada
this.camera = {
x: 0,
y: 0,
targetX: 0,
targetY: 0,
smoothing: 0.1,
shake: { x: 0, y: 0, intensity: 0, duration: 0 },
zoom: 1,
targetZoom: 1,
bounds: { left: 0, right: 2000, top: 0, bottom: 1000 },
// Efectos de cámara
effects: {
screenShake: false,
slowMotion: false,
colorFilter: null,
vignette: false
}
};
// Configuración de niveles procedurales
this.levelConfig = {
currentLevel: null,
levelData: new Map(),
proceduralSeed: Date.now(),
chunkSize: 800,
loadedChunks: new Map(),
activeChunks: new Set(),
// Configuraciones por nivel
levelTypes: {
caminito_matrix: {
theme: 'urban_argentina',
difficulty: 1,
enemies: ['mantero', 'bondi', 'taxi'],
powerUps: ['mate', 'empanada', 'choripan'],
music: 'tango_chiptune',
background: 'la_boca_neon'
},
obelisco_cyber: {
theme: 'cyberpunk_bsas',
difficulty: 2,
enemies: ['drone_policia', 'hacker', 'cyborg_portero'],
powerUps: ['fernet_digital', 'asado_hologram'],
music: 'cumbia_synthwave',
background: 'obelisco_matrix'
}
}
};
// Sistema de partículas ultra avanzado
this.particleSystem = {
particles: [],
maxParticles: 500,
pools: {
explosion: [],
trail: [],
sparkle: [],
smoke: [],
blood: [],
energy: []
},
// Configuraciones de efectos
effects: {
playerTrail: { enabled: true, intensity: 0.7 },
impactSparks: { enabled: true, intensity: 1.0 },
ambientParticles: { enabled: true, intensity: 0.5 },
weatherEffects: { enabled: true, type: 'none' }
}
};
// Sistema de audio ultra avanzado
this.audioSystem = {
context: null,
masterVolume: 0.7,
sfxVolume: 0.8,
musicVolume: 0.6,
// Canales de audio
channels: {
master: null,
music: null,
sfx: null,
ambient: null,
voice: null
},
// Biblioteca de sonidos
sounds: new Map(),
currentMusic: null,
musicQueue: [],
// Efectos de audio avanzados
effects: {
reverb: null,
delay: null,
distortion: null,
filter: null
}
};
// Sistema de IA compañero ultra inteligente
this.aiCompanion = {
personality: {
humor: 0.8,
sarcasm: 0.6,
encouragement: 0.9,
knowledge: 0.95,
patience: 0.7,
argentineness: 1.0
},
// Estados emocionales
mood: 'excited',
relationship: 50, // 0-100
trust: 30, // 0-100
// Sistema de memoria
memory: {
playerActions: [],
conversations: [],
achievements: [],
preferences: new Map(),
personalData: new Map()
},
// Sistema de respuestas contextuales
responseSystem: {
contextAnalyzer: null,
emotionEngine: null,
humorGenerator: null,
knowledgeBase: new Map()
},
// Configuración de chat
chatConfig: {
isActive: false,
autoResponse: true,
responseDelay: 1500,
maxMessageLength: 200,
currentConversation: []
}
};
// Sistemas del motor
this.systems = {
input: null,
physics: null,
rendering: null,
audio: null,
ai: null,
particles: null,
entities: null,
levels: null,
save: null,
achievements: null,
analytics: null
};
// Configuración de rendimiento
this.performance = {
targetFPS: 60,
adaptiveQuality: true,
cullingEnabled: true,
lodEnabled: true,
// Métricas de rendimiento
metrics: {
frameTime: 0,
drawCalls: 0,
particleCount: 0,
entityCount: 0,
memoryUsage: 0
},
// Configuraciones de calidad
qualityLevels: {
potato: { particles: 50, effects: false, shadows: false },
low: { particles: 100, effects: true, shadows: false },
medium: { particles: 250, effects: true, shadows: true },
high: { particles: 400, effects: true, shadows: true },
ultra: { particles: 500, effects: true, shadows: true }
}
};
// Configuración de red y multijugador (futuro)
this.network = {
isOnline: false,
playerId: null,
sessionId: null,
peers: new Map(),
latency: 0,
// Configuración de sincronización
sync: {
enabled: false,
rate: 20, // Hz
interpolation: true,
prediction: true
}
};
// Sistema de eventos avanzado
this.eventSystem = {
listeners: new Map(),
queue: [],
processing: false,
// Tipos de eventos
eventTypes: {
PLAYER_MOVE: 'player_move',
PLAYER_JUMP: 'player_jump',
PLAYER_ATTACK: 'player_attack',
ENEMY_SPAWN: 'enemy_spawn',
ITEM_COLLECT: 'item_collect',
LEVEL_COMPLETE: 'level_complete',
ACHIEVEMENT_UNLOCK: 'achievement_unlock',
AI_RESPONSE: 'ai_response'
}
};
// Inicializar el motor
this.initialize();
}
// ===================================================================
// MÉTODOS DE INICIALIZACIÓN
// ===================================================================
async initialize() {
console.log('🚀 Inicializando RETRO LEGENDS: Ultimate Engine...');
try {
// Configurar canvas
this.setupCanvas();
// Inicializar sistemas principales
await this.initializeSystems();
// Cargar recursos
await this.loadResources();
// Configurar nivel inicial
await this.loadInitialLevel();
// Configurar IA
this.initializeAI();
// Inicializar sistema de eventos
this.initializeEventSystem();
// Configurar sistema de guardado
this.initializeSaveSystem();
// Marcar como inicializado
this.engineState.isInitialized = true;
this.engineState.isRunning = true;
// Iniciar loop principal
this.startMainLoop();
console.log('✅ RETRO LEGENDS: Ultimate Engine inicializado correctamente');
// Disparar evento de inicialización
this.dispatchEvent('ENGINE_INITIALIZED', { timestamp: Date.now() });
} catch (error) {
console.error('❌ Error inicializando el motor:', error);
throw error;
}
}
setupCanvas() {
// Configurar tamaño responsivo
this.resizeCanvas();
window.addEventListener('resize', () => this.resizeCanvas());
// Configurar contexto para renderizado pixelado
this.ctx.imageSmoothingEnabled = false;
this.ctx.webkitImageSmoothingEnabled = false;
this.ctx.mozImageSmoothingEnabled = false;
this.ctx.msImageSmoothingEnabled = false;
// Configurar filtros de renderizado
this.ctx.filter = 'contrast(1.1) saturate(1.2) brightness(1.05)';
console.log('🖥️ Canvas configurado:', this.canvas.width, 'x', this.canvas.height);
}
resizeCanvas() {
const container = this.canvas.parentElement;
const rect = container.getBoundingClientRect();
// Configurar tamaño manteniendo aspect ratio 16:9
const aspectRatio = 16 / 9;
let width = rect.width;
let height = rect.height;
if (width / height > aspectRatio) {
width = height * aspectRatio;
} else {
height = width / aspectRatio;
}
this.canvas.width = width;
this.canvas.height = height;
// Actualizar bounds de cámara
this.camera.bounds.right = width * 2;
this.camera.bounds.bottom = height * 1.5;
}
async initializeSystems() {
console.log('🔧 Inicializando sistemas del motor...');
// Sistema de input avanzado
this.systems.input = new AdvancedInputHandler(this);
// Sistema de físicas
this.systems.physics = new AdvancedPhysicsEngine(this);
// Sistema de renderizado
this.systems.rendering = new AdvancedRenderingSystem(this);
// Sistema de audio
this.systems.audio = new UltraAudioSystem(this);
await this.systems.audio.initialize();
// Sistema de partículas
this.systems.particles = new AdvancedParticleSystem(this);
// Sistema de entidades
this.systems.entities = new UltraEntityManager(this);
// Sistema de niveles
this.systems.levels = new ProceduralLevelGenerator(this);
// Sistema de IA
this.systems.ai = new AdvancedAICompanion(this);
// Sistema de guardado
this.systems.save = new AdvancedSaveSystem(this);
// Sistema de logros
this.systems.achievements = new AchievementSystem(this);
// Sistema de analíticas
this.systems.analytics = new GameAnalytics(this);
console.log('✅ Todos los sistemas inicializados');
}
async loadResources() {
console.log('📦 Cargando recursos del juego...');
// Cargar sprites y texturas
await this.loadSprites();
// Cargar sonidos
await this.loadAudio();
// Cargar datos de niveles
await this.loadLevelData();
// Cargar configuraciones de IA
await this.loadAIData();
console.log('✅ Recursos cargados correctamente');
}
async loadSprites() {
// Aquí cargaríamos sprites reales en una implementación completa
console.log('🎨 Sprites cargados (modo texto para demo)');
}
async loadAudio() {
// Inicializar contexto de audio
if (!this.audioSystem.context) {
this.audioSystem.context = new (window.AudioContext || window.webkitAudioContext)();
}
console.log('🎵 Sistema de audio inicializado');
}
async loadLevelData() {
// Cargar configuraciones de niveles
this.levelConfig.levelData.set('caminito_matrix', {
name: 'Caminito Matrix',
theme: 'cyberpunk_argentina',
size: { width: 2000, height: 800 },
spawnPoints: [{ x: 100, y: 400 }],
enemies: ['mantero_cyber', 'bondi_hologram', 'taxi_drone'],
collectibles: ['mate_digital', 'empanada_power', 'choripan_shield']
});
console.log('🗺️ Datos de niveles cargados');
}
async loadAIData() {
// Cargar base de conocimiento de la IA
this.aiCompanion.responseSystem.knowledgeBase.set('argentina', {
cultura: ['mate', 'asado', 'tango', 'futbol', 'Maradona'],
lugares: ['Buenos Aires', 'Córdoba', 'Mendoza', 'Bariloche'],
comidas: ['empanadas', 'choripan', 'milanesas', 'dulce de leche'],
expresiones: ['che', 'boludo', 'dale', 'bárbaro', 'copado']
});
console.log('🤖 Base de conocimiento de IA cargada');
}
async loadInitialLevel() {
console.log('🏗️ Cargando nivel inicial...');
// Cargar Caminito Matrix
await this.systems.levels.loadLevel('caminito_matrix');
// Posicionar jugador
this.player.x = 150;
this.player.y = 400;
// Configurar cámara
this.updateCamera();
console.log('✅ Nivel inicial cargado');
}
initializeAI() {
console.log('🧠 Inicializando IA compañero...');
// Configurar personalidad inicial
this.aiCompanion.mood = 'excited';
this.aiCompanion.relationship = 50;
// Mensaje de bienvenida
setTimeout(() => {
this.systems.ai.sendMessage(
"¡Ehhhh, pibe! ¡Bienvenido a la experiencia más nostálgica y avanzada de tu vida! " +
"Soy NEXUS, tu compañero argento con IA de última generación. " +
"¿Listos para romperla en este universo retro-futurista? ¡Dale que arrancamos! 🚀🇦🇷"
);
}, 2000);
console.log('✅ IA compañero inicializada');
}
initializeEventSystem() {
console.log('📡 Inicializando sistema de eventos...');
// Configurar listeners principales
this.addEventListener('PLAYER_MOVE', (data) => {
this.systems.ai.onPlayerMove(data);
this.systems.analytics.trackEvent('player_movement', data);
});
this.addEventListener('PLAYER_JUMP', (data) => {
this.systems.ai.onPlayerJump(data);
this.systems.particles.createJumpEffect(data.x, data.y);
});
this.addEventListener('ITEM_COLLECT', (data) => {
this.systems.ai.onItemCollect(data);
this.updateScore(data.points);
});
console.log('✅ Sistema de eventos configurado');
}
initializeSaveSystem() {
console.log('💾 Inicializando sistema de guardado...');
// Cargar datos guardados si existen
this.systems.save.loadGame();
// Configurar auto-guardado cada 30 segundos
setInterval(() => {
this.systems.save.autoSave();
}, 30000);
console.log('✅ Sistema de guardado configurado');
}
// ===================================================================
// LOOP PRINCIPAL DEL JUEGO
// ===================================================================
startMainLoop() {
console.log('🔄 Iniciando loop principal del juego...');
this.engineState.lastFrameTime = performance.now();
this.mainLoop();
}
mainLoop() {
if (!this.engineState.isRunning) return;
// Calcular delta time
const currentTime = performance.now();
this.engineState.deltaTime = currentTime - this.engineState.lastFrameTime;
this.engineState.lastFrameTime = currentTime;
// Actualizar FPS
this.updateFPS();
// Verificar rendimiento y ajustar calidad si es necesario
this.checkPerformance();
// Actualizar solo si no está pausado
if (!this.engineState.isPaused) {
this.update(this.engineState.deltaTime);
}
// Renderizar siempre
this.render();
// Continuar el loop
requestAnimationFrame(() => this.mainLoop());
}
update(deltaTime) {
// Actualizar tiempo de juego
this.gameState.time += deltaTime;
// Actualizar sistemas principales
this.updatePlayer(deltaTime);
this.updateCamera(deltaTime);
this.updatePhysics(deltaTime);
// Actualizar sistemas secundarios
this.systems.entities.update(deltaTime);
this.systems.particles.update(deltaTime);
this.systems.levels.update(deltaTime);
this.systems.ai.update(deltaTime);
// Procesar eventos
this.processEvents();
// Verificar colisiones
this.checkCollisions();
// Actualizar UI
this.updateUI();
// Verificar condiciones de juego
this.checkGameConditions();
// Actualizar analíticas
this.systems.analytics.update(deltaTime);
}
updatePlayer(deltaTime) {
const player = this.player;
// Actualizar timers
this.updatePlayerTimers(deltaTime);
// Procesar input del jugador
this.systems.input.processPlayerInput(deltaTime);
// Aplicar física del jugador
this.applyPlayerPhysics(deltaTime);
// Actualizar animaciones
this.updatePlayerAnimation(deltaTime);
// Actualizar centro del jugador
player.centerX = player.x + player.width / 2;
player.centerY = player.y + player.height / 2;
// Verificar límites del mundo
this.checkWorldBounds();
// Actualizar sistema de combos
this.updateComboSystem(deltaTime);
}
updatePlayerTimers(deltaTime) {
const player = this.player;
// Timer de invulnerabilidad
if (player.invulnerabilityTimer > 0) {
player.invulnerabilityTimer -= deltaTime;
if (player.invulnerabilityTimer <= 0) {
player.isInvulnerable = false;
}
}
// Cooldown de dash
if (player.dashCooldown > 0) {
player.dashCooldown -= deltaTime;
if (player.dashCooldown <= 0) {
player.canDash = true;
}
}
// Cooldown de ataque
if (player.attackCooldown > 0) {
player.attackCooldown -= deltaTime;
if (player.attackCooldown <= 0) {
player.isAttacking = false;
}
}
// Timer de combo
if (player.comboSystem.comboTimer > 0) {
player.comboSystem.comboTimer -= deltaTime;
if (player.comboSystem.comboTimer <= 0) {
player.comboSystem.currentCombo = [];
}
}
}
applyPlayerPhysics(deltaTime) {
const player = this.player;
const physics = this.physics;
// Aplicar gravedad si no está en el suelo
if (!player.grounded) {
player.velocityY += physics.gravity;
if (player.velocityY > physics.terminalVelocity) {
player.velocityY = physics.terminalVelocity;
}
}
// Aplicar fricción/resistencia
if (player.grounded) {
player.velocityX *= physics.groundFriction;
} else {
player.velocityX *= physics.airResistance;
}
// Aplicar velocidades
player.x += player.velocityX;
player.y += player.velocityY;
// Verificar colisiones con terreno
this.checkTerrainCollisions();
}
updatePlayerAnimation(deltaTime) {
const player = this.player;
// Actualizar timer de animación
player.lastAnimationTime += deltaTime;
if (player.lastAnimationTime >= player.animationSpeed) {
player.lastAnimationTime = 0;
// Determinar sprite actual basado en estado
let spriteSet;
if (player.isDashing) {
spriteSet = player.spriteSet.dashing;
} else if (player.isAttacking) {
spriteSet = player.spriteSet.attacking;
} else if (player.isCharging) {
spriteSet = player.spriteSet.charging;
} else if (!player.grounded) {
spriteSet = player.spriteSet.jumping;
} else if (Math.abs(player.velocityX) > 0.5) {
spriteSet = player.spriteSet.running;
} else {
spriteSet = player.spriteSet.idle;
}
// Avanzar frame de animación
player.animationFrame = (player.animationFrame + 1) % spriteSet.length;
player.currentSprite = spriteSet[player.animationFrame];
}
}
updateCamera(deltaTime) {
const camera = this.camera;
const player = this.player;
// Calcular posición objetivo de la cámara
camera.targetX = player.centerX - this.canvas.width / 2;
camera.targetY = player.centerY - this.canvas.height / 2;
// Aplicar límites de cámara
camera.targetX = Math.max(camera.bounds.left,
Math.min(camera.bounds.right - this.canvas.width, camera.targetX));
camera.targetY = Math.max(camera.bounds.top,
Math.min(camera.bounds.bottom - this.canvas.height, camera.targetY));
// Interpolar suavemente hacia la posición objetivo
camera.x += (camera.targetX - camera.x) * camera.smoothing;
camera.y += (camera.targetY - camera.y) * camera.smoothing;
// Aplicar shake de cámara si está activo
if (camera.shake.duration > 0) {
camera.shake.duration -= deltaTime;
const intensity = camera.shake.intensity * (camera.shake.duration / 1000);
camera.shake.x = (Math.random() - 0.5) * intensity;
camera.shake.y = (Math.random() - 0.5) * intensity;
} else {
camera.shake.x = 0;
camera.shake.y = 0;
}
// Aplicar zoom suave
camera.zoom += (camera.targetZoom - camera.zoom) * 0.1;
}
updatePhysics(deltaTime) {
// Actualizar física del mundo
this.systems.physics.update(deltaTime);
}
checkCollisions() {
// Verificar colisiones jugador-entidades
const playerRect = {
x: this.player.x,
y: this.player.y,
width: this.player.width,
height: this.player.height
};
const entities = this.systems.entities.getActiveEntities();
entities.forEach((entity, index) => {
if (this.isColliding(playerRect, entity.getBounds())) {
this.handleCollision(entity, index);
}
});
}
isColliding(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;
}
handleCollision(entity, index) {
if (this.player.isInvulnerable) return;
switch(entity.type) {
case 'enemy':
this.playerHit(entity);
break;
case 'collectible':
this.collectItem(entity, index);
break;
case 'powerup':
this.collectPowerUp(entity, index);
break;
case 'checkpoint':
this.activateCheckpoint(entity);
break;
}
}
playerHit(enemy) {
// Reducir vida
this.gameState.health -= enemy.damage || 25;
// Activar invulnerabilidad
this.player.isInvulnerable = true;
this.player.invulnerabilityTimer = 2000;
// Aplicar knockback
const knockbackDirection = this.player.x < enemy.x ? -1 : 1;
this.player.velocityX = knockbackDirection * 10;
this.player.velocityY = -8;
// Efectos visuales y sonoros
this.systems.particles.createHitEffect(this.player.centerX, this.player.centerY);
this.systems.audio.playSound('player_hit');
this.shakeCamera(300, 10);
// Reacción de la IA
this.systems.ai.onPlayerHit(enemy.type);
// Disparar evento
this.dispatchEvent('PLAYER_HIT', {
enemy: enemy.type,
damage: enemy.damage,
health: this.gameState.health
});
// Verificar muerte
if (this.gameState.health <= 0) {
this.playerDeath();
}
}
collectItem(item, index) {
// Añadir puntos
this.gameState.score += item.points || 100;
// Procesar tipo de item
switch(item.subtype) {
case 'mate':
this.gameState.mateCount++;
this.systems.ai.onMateCollected();
break;
case 'empanada':
this.gameState.health = Math.min(this.gameState.maxHealth, this.gameState.health + 25);
break;
case 'choripan':
this.gameState.energy = Math.min(this.gameState.maxEnergy, this.gameState.energy + 50);
break;
}
// Efectos
this.systems.particles.createCollectEffect(item.x, item.y, item.color);
this.systems.audio.playSound('item_collect');
// Remover item
this.systems.entities.removeEntity(index);
// Disparar evento
this.dispatchEvent('ITEM_COLLECT', {
type: item.subtype,
points: item.points,
position: { x: item.x, y: item.y }
});
}
updateComboSystem(deltaTime) {
const comboSystem = this.player.comboSystem;
// Verificar si hay combo activo
if (comboSystem.currentCombo.length > 0) {
// Verificar si se completó algún combo
comboSystem.availableCombos.forEach(combo => {
if (this.arraysEqual(comboSystem.currentCombo, combo.sequence)) {
this.executeCombo(combo);
comboSystem.currentCombo = [];
comboSystem.comboTimer = 0;
}
});
}
}
executeCombo(combo) {
console.log(`🔥 Combo ejecutado: ${combo.name} (${combo.power} poder)`);
// Aplicar efectos del combo
this.gameState.score += combo.power;
this.gameState.combo++;
// Efectos visuales espectaculares
this.systems.particles.createComboEffect(this.player.centerX, this.player.centerY, combo.name);
this.systems.audio.playSound('combo_success');
this.shakeCamera(500, 15);
// Reacción de la IA
this.systems.ai.onComboExecuted(combo);
// Disparar evento
this.dispatchEvent('COMBO_EXECUTED', { combo: combo.name, power: combo.power });
}
// ===================================================================
// MÉTODOS DE RENDERIZADO
// ===================================================================
render() {
// Limpiar canvas
this.clearCanvas();
// Aplicar transformaciones de cámara
this.ctx.save();
this.applyCamera();
// Renderizar fondo
this.renderBackground();
// Renderizar nivel
this.systems.levels.render(this.ctx);
// Renderizar entidades
this.systems.entities.render(this.ctx);
// Renderizar jugador
this.renderPlayer();
// Renderizar partículas
this.systems.particles.render(this.ctx);
// Renderizar efectos de primer plano
this.renderForegroundEffects();
// Restaurar transformaciones
this.ctx.restore();
// Renderizar UI (sin transformaciones de cámara)
this.renderUI();
// Renderizar debug si está habilitado
if (this.engineState.debugMode) {
this.renderDebugInfo();
}
// Actualizar métricas de rendimiento
this.performance.metrics.drawCalls++;
}
clearCanvas() {
// Fondo degradado dinámico
const gradient = this.ctx.createLinearGradient(0, 0, this.canvas.width, this.canvas.height);
gradient.addColorStop(0, '#0a0a0a');
gradient.addColorStop(0.5, '#1a1a2e');
gradient.addColorStop(1, '#16213e');
this.ctx.fillStyle = gradient;
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
}
applyCamera() {
// Aplicar zoom
this.ctx.scale(this.camera.zoom, this.camera.zoom);
// Aplicar posición de cámara con shake
this.ctx.translate(
-this.camera.x + this.camera.shake.x,
-this.camera.y + this.camera.shake.y
);
}
renderBackground() {
// Renderizar fondo parallax del nivel actual
this.systems.levels.renderBackground(this.ctx, this.camera);
}
renderPlayer() {
const player = this.player;
// Efecto de parpadeo si es invulnerable
if (player.isInvulnerable && Math.floor(this.gameState.time / 100) % 2) {
this.ctx.globalAlpha = 0.5;
}
// Configurar renderizado de texto
this.ctx.font = '32px Arial';
this.ctx.textAlign = 'center';
this.ctx.textBaseline = 'bottom';
// Renderizar sprite del jugador
this.ctx.fillStyle = '#ffffff';
this.ctx.fillText(
player.currentSprite,
player.centerX,
player.y + player.height
);
// Efectos especiales según estado
if (player.isDashing) {
this.renderDashEffect();
}
if (player.isCharging) {
this.renderChargeEffect();
}
// Restaurar alpha
this.ctx.globalAlpha = 1.0;
// Renderizar barra de vida si está dañado
if (this.gameState.health < this.gameState.maxHealth) {
this.renderPlayerHealthBar();
}
}
renderDashEffect() {
const player = this.player;
// Crear trail de dash
this.ctx.strokeStyle = '#00ffff';
this.ctx.lineWidth = 3;
this.ctx.globalAlpha = 0.7;
this.ctx.beginPath();
this.ctx.moveTo(player.x - 20, player.centerY);
this.ctx.lineTo(player.x + player.width + 20, player.centerY);
this.ctx.stroke();
this.ctx.globalAlpha = 1.0;
}
renderChargeEffect() {
const player = this.player;
const time = this.gameState.time;
// Efecto de energía cargándose
this.ctx.strokeStyle = '#ffff00';
this.ctx.lineWidth = 2;
this.ctx.globalAlpha = 0.8;
const radius = 40 + Math.sin(time * 0.01) * 10;
this.ctx.beginPath();
this.ctx.arc(player.centerX, player.centerY, radius, 0, Math.PI * 2);
this.ctx.stroke();
this.ctx.globalAlpha = 1.0;
}
renderPlayerHealthBar() {
const player = this.player;
const barWidth = 40;
const barHeight = 6;
const x = player.centerX - barWidth / 2;
const y = player.y - 15;
// Fondo de la barra
this.ctx.fillStyle = '#ff0000';
this.ctx.fillRect(x, y, barWidth, barHeight);
// Barra de vida
const healthPercent = this.gameState.health / this.gameState.maxHealth;
this.ctx.fillStyle = '#00ff00';
this.ctx.fillRect(x, y, barWidth * healthPercent, barHeight);
// Borde
this.ctx.strokeStyle = '#ffffff';
this.ctx.lineWidth = 1;
this.ctx.strokeRect(x, y, barWidth, barHeight);
}
renderForegroundEffects() {
// Efectos de primer plano como lluvia, nieve, etc.
if (this.particleSystem.effects.weatherEffects.enabled) {
this.renderWeatherEffects();
}
// Efectos de pantalla como vignette
if (this.camera.effects.vignette) {
this.renderVignette();
}
}
renderWeatherEffects() {
// Implementar efectos climáticos
}
renderVignette() {
const gradient = this.ctx.createRadialGradient(
this.canvas.width / 2, this.canvas.height / 2, 0,
this.canvas.width / 2, this.canvas.height / 2, this.canvas.width / 2
);
gradient.addColorStop(0, 'rgba(0,0,0,0)');
gradient.addColorStop(1, 'rgba(0,0,0,0.5)');
this.ctx.fillStyle = gradient;
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
}
renderUI() {
// La UI se renderiza en el HTML, pero aquí podríamos añadir overlays
}
renderDebugInfo() {
this.ctx.fillStyle = '#00ff00';
this.ctx.font = '12px monospace';
this.ctx.textAlign = 'left';
const debugInfo = [
`FPS: ${this.engineState.averageFPS.toFixed(1)}`,
`Delta: ${this.engineState.deltaTime.toFixed(2)}ms`,
`Player: (${this.player.x.toFixed(0)}, ${this.player.y.toFixed(0)})`,
`Velocity: (${this.player.velocityX.toFixed(2)}, ${this.player.velocityY.toFixed(2)})`,
`Camera: (${this.camera.x.toFixed(0)}, ${this.camera.y.toFixed(0)})`,
`Entities: ${this.systems.entities.getEntityCount()}`,
`Particles: ${this.systems.particles.getParticleCount()}`
];
debugInfo.forEach((line, index) => {
this.ctx.fillText(line, 10, 20 + index * 15);
});
}
// ===================================================================
// MÉTODOS AUXILIARES
// ===================================================================
updateFPS() {
this.engineState.frameCount++;
if (this.engineState.frameCount % 60 === 0) {
this.engineState.averageFPS = 1000 / this.engineState.deltaTime;
}
}
checkPerformance() {
// Ajustar calidad automáticamente si el rendimiento es bajo
if (this.performance.adaptiveQuality && this.engineState.averageFPS < 45) {
this.adjustQuality('down');
} else if (this.performance.adaptiveQuality && this.engineState.averageFPS > 55) {
this.adjustQuality('up');
}
}
adjustQuality(direction) {
// Implementar ajuste automático de calidad
console.log(`🔧 Ajustando calidad: ${direction}`);
}
processEvents() {
while (this.eventSystem.queue.length > 0) {
const event = this.eventSystem.queue.shift();
this.handleEvent(event);
}
}
handleEvent(event) {
const listeners = this.eventSystem.listeners.get(event.type);
if (listeners) {
listeners.forEach(listener => listener(event.data));
}
}
addEventListener(type, listener) {
if (!this.eventSystem.listeners.has(type)) {
this.eventSystem.listeners.set(type, []);
}
this.eventSystem.listeners.get(type).push(listener);
}
dispatchEvent(type, data) {
this.eventSystem.queue.push({ type, data, timestamp: Date.now() });
}
shakeCamera(duration, intensity) {
this.camera.shake.duration = duration;
this.camera.shake.intensity = intensity;
}
updateUI() {
// Actualizar elementos de UI
document.getElementById('gameScore').textContent = this.gameState.score.toLocaleString();
document.getElementById('playerHealth').textContent = Math.max(0, this.gameState.health);
document.getElementById('mateCount').textContent = this.gameState.mateCount;
document.getElementById('currentLevel').textContent = this.levelConfig.currentLevel;
document.getElementById('comboCount').textContent = this.gameState.combo;
}
checkGameConditions() {
// Verificar condiciones de victoria/derrota
if (this.gameState.health <= 0 && this.gameState.lives <= 0) {
this.gameOver();
}
// Verificar completado de nivel
if (this.systems.levels.isLevelComplete()) {
this.completeLevel();
}
}
checkWorldBounds() {
const player = this.player;
// Límites horizontales
if (player.x < 0) {
player.x = 0;
player.velocityX = 0;
}
// Límite inferior (muerte por caída)
if (player.y > this.canvas.height + 200) {
this.playerDeath('fall');
}
}
checkTerrainCollisions() {
const player = this.player;
const groundY = this.canvas.height - 80; // Altura del suelo base
// Colisión con el suelo
if (player.y + player.height >= groundY) {
player.y = groundY - player.height;
player.velocityY = 0;
if (!player.grounded) {
player.grounded = true;
player.canDoubleJump = true;
this.systems.particles.createLandingEffect(player.centerX, player.y + player.height);
this.systems.ai.onPlayerLanding();
}
} else {
player.grounded = false;
}
}
playerDeath(cause = 'unknown') {
console.log(`💀 Jugador murió por: ${cause}`);
// Reducir vidas
this.gameState.lives--;
// Efectos de muerte
this.systems.particles.createDeathEffect(this.player.centerX, this.player.centerY);
this.systems.audio.playSound('player_death');
this.shakeCamera(1000, 20);
// Reacción de la IA
this.systems.ai.onPlayerDeath(cause);
// Resetear jugador
this.respawnPlayer();
// Disparar evento
this.dispatchEvent('PLAYER_DEATH', { cause, lives: this.gameState.lives });
}
respawnPlayer() {
// Resetear posición y estado del jugador
this.player.x = 150;
this.player.y = 400;
this.player.velocityX = 0;
this.player.velocityY = 0;
this.gameState.health = this.gameState.maxHealth;
this.player.isInvulnerable = true;
this.player.invulnerabilityTimer = 3000;
console.log('🔄 Jugador respawneado');
}
gameOver() {
this.engineState.isRunning = false;
console.log('💀 GAME OVER');
// Mostrar pantalla de game over
this.systems.ai.onGameOver();
// Guardar estadísticas finales
this.systems.save.saveGameOverStats();
}
completeLevel() {
console.log('🏆 Nivel completado');
// Bonificación por completar nivel
this.gameState.score += 5000;
// Reacción de la IA
this.systems.ai.onLevelComplete();
// Cargar siguiente nivel
this.loadNextLevel();
}
loadNextLevel() {
// Implementar carga del siguiente nivel
console.log('🗺️ Cargando siguiente nivel...');
}
arraysEqual(a, b) {
return a.length === b.length && a.every((val, i) => val === b[i]);
}
// ===================================================================
// MÉTODOS PÚBLICOS PARA CONTROLES
// ===================================================================
jump() {
const player = this.player;
if (player.grounded) {
player.velocityY = -player.jumpPower;
player.grounded = false;
this.systems.audio.playSound('jump');
this.systems.particles.createJumpEffect(player.centerX, player.y + player.height);
this.dispatchEvent('PLAYER_JUMP', { x: player.centerX, y: player.centerY });
} else if (player.canDoubleJump) {
player.velocityY = -player.doubleJumpPower;
player.canDoubleJump = false;
this.systems.audio.playSound('double_jump');
this.systems.particles.createDoubleJumpEffect(player.centerX, player.centerY);
}
}
dash() {
const player = this.player;
if (player.canDash && !player.isDashing) {
const direction = player.facing === 'right' ? 1 : -1;
player.velocityX = direction * player.dashPower;
player.isDashing = true;
player.canDash = false;
player.dashCooldown = 1000;
this.systems.audio.playSound('dash');
this.systems.particles.createDashEffect(player.centerX, player.centerY, direction);
// El dash dura 200ms
setTimeout(() => {
player.isDashing = false;
}, 200);
}
}
attack() {
const player = this.player;
if (!player.isAttacking && player.attackCooldown <= 0) {
player.isAttacking = true;
player.attackCooldown = 500;
this.systems.audio.playSound('attack');
this.systems.particles.createAttackEffect(player.centerX, player.centerY, player.facing);
// Verificar enemigos en rango
this.checkAttackHits();
}
}
checkAttackHits() {
const player = this.player;
const attackRange = 50;
const attackRect = {
x: player.facing === 'right' ? player.x + player.width : player.x - attackRange,
y: player.y,
width: attackRange,
height: player.height
};
const entities = this.systems.entities.getActiveEntities();
entities.forEach((entity, index) => {
if (entity.type === 'enemy' && this.isColliding(attackRect, entity.getBounds())) {
this.hitEnemy(entity, index);
}
});
}
hitEnemy(enemy, index) {
// Dañar enemigo
enemy.takeDamage(player.stats.strength);
// Efectos
this.systems.particles.createEnemyHitEffect(enemy.x, enemy.y);
this.systems.audio.playSound('enemy_hit');
// Puntos
this.gameState.score += 50;
// Si el enemigo muere
if (enemy.health <= 0) {
this.systems.entities.removeEntity(index);
this.gameState.score += enemy.killScore || 100;
this.systems.particles.createEnemyDeathEffect(enemy.x, enemy.y);
}
}
useMate() {
if (this.gameState.mateCount > 0) {
this.gameState.mateCount--;
this.gameState.health = Math.min(this.gameState.maxHealth, this.gameState.health + 50);
this.gameState.energy = this.gameState.maxEnergy;
this.systems.audio.playSound('mate_use');
this.systems.particles.createMateEffect(this.player.centerX, this.player.centerY);
this.systems.ai.onMateUsed();
console.log('🧉 Mate usado - Vida y energía restauradas');
}
}
togglePause() {
this.engineState.isPaused = !this.engineState.isPaused;
if (this.engineState.isPaused) {
this.systems.audio.pauseAll();
this.systems.ai.onGamePaused();
} else {
this.systems.audio.resumeAll();
this.systems.ai.onGameResumed();
}
console.log(`⏸️ Juego ${this.engineState.isPaused ? 'pausado' : 'reanudado'}`);
}
toggleDebug() {
this.engineState.debugMode = !this.engineState.debugMode;
console.log(`🐛 Modo debug: ${this.engineState.debugMode ? 'ON' : 'OFF'}`);
}
// ===================================================================
// GETTERS PÚBLICOS
// ===================================================================
getPlayer() { return this.player; }
getGameState() { return this.gameState; }
getCamera() { return this.camera; }
getCanvas() { return this.canvas; }
getContext() { return this.ctx; }
getSystems() { return this.systems; }
getPerformanceMetrics() { return this.performance.metrics; }
}
// ===================================================================
// EXPORTAR PARA USO GLOBAL
// ===================================================================
window.RetroLegendsUltimateEngine = RetroLegendsUltimateEngine;
console.log('🚀 Core Engine Ultra cargado correctamente');