// Lighting & Shadow System - Dynamic lighting and shadows class LightingSystem { constructor(scene) { this.scene = scene; this.shadows = new Map(); // Entity → Shadow sprite this.lights = new Map(); // Source → Light circle console.log('💡 LightingSystem initialized'); } // Create shadow for an entity (player, NPC, etc.) createShadow(entity, offsetY = 10, width = 30, height = 15) { if (!entity || !entity.sprite) return null; const shadow = this.scene.add.ellipse( entity.sprite.x, entity.sprite.y + offsetY, width, height, 0x000000, 0.3 ); shadow.setDepth(entity.sprite.depth - 1); // Always below entity this.shadows.set(entity, { shadow, offsetY, width, height }); return shadow; } // Update shadow position (call in entity update) updateShadow(entity) { const data = this.shadows.get(entity); if (!data || !entity.sprite) return; const { shadow, offsetY } = data; shadow.setPosition(entity.sprite.x, entity.sprite.y + offsetY); // Adjust shadow opacity based on time of day if (this.scene.weatherSystem) { const hour = this.scene.weatherSystem.getCurrentHour(); let opacity = 0.3; if (hour >= 5 && hour < 7) { // Dawn - weak shadow opacity = 0.1 + ((hour - 5) / 2) * 0.2; } else if (hour >= 7 && hour < 18) { // Day - strong shadow opacity = 0.3; } else if (hour >= 18 && hour < 20) { // Dusk - fading shadow opacity = 0.3 - ((hour - 18) / 2) * 0.2; } else { // Night - very weak shadow opacity = 0.1; } shadow.setAlpha(opacity); } } // Remove shadow removeShadow(entity) { const data = this.shadows.get(entity); if (data && data.shadow) { data.shadow.destroy(); } this.shadows.delete(entity); } // Create light source (torch, campfire, etc.) createLight(x, y, radius = 100, color = 0xffee88, alpha = 0.3, flicker = false) { const light = this.scene.add.circle(x, y, radius, color, alpha); light.setBlendMode(Phaser.BlendModes.ADD); light.setDepth(999990); // Above most things const lightData = { light, radius, color, baseAlpha: alpha, flicker, flickerTimer: 0 }; this.lights.set(light, lightData); return light; } // Create player torch (follows player at night) createPlayerTorch(player) { if (!player || !player.sprite) return null; const torch = this.scene.add.circle( player.sprite.x, player.sprite.y, 80, 0xffee88, 0 ); torch.setBlendMode(Phaser.BlendModes.ADD); torch.setDepth(999990); this.lights.set(torch, { light: torch, radius: 80, color: 0xffee88, baseAlpha: 0.35, flicker: true, flickerTimer: 0, followPlayer: player }); return torch; } // Update all lights update(delta) { const isNight = this.scene.weatherSystem ? this.scene.weatherSystem.isNight() : false; for (const [light, data] of this.lights) { // Follow player if assigned if (data.followPlayer && data.followPlayer.sprite) { light.setPosition( data.followPlayer.sprite.x, data.followPlayer.sprite.y ); // Only show torch at night if (isNight) { light.setAlpha(data.baseAlpha); } else { light.setAlpha(0); // Hidden during day } } // Flicker effect if (data.flicker) { data.flickerTimer += delta; if (data.flickerTimer > 50) { // Every 50ms data.flickerTimer = 0; const flicker = data.baseAlpha + (Math.random() * 0.1 - 0.05); if (isNight || !data.followPlayer) { light.setAlpha(Phaser.Math.Clamp(flicker, 0, 1)); } } } } // Update all shadows for (const [entity, data] of this.shadows) { this.updateShadow(entity); } } // Remove light removeLight(light) { const data = this.lights.get(light); if (data && data.light) { data.light.destroy(); } this.lights.delete(light); } // Create campfire effect (static light with particles) createCampfire(x, y) { // Light glow const light = this.createLight(x, y, 120, 0xff6600, 0.4, true); // Smoke particles (if ParticleEffects exists) if (this.scene.particleEffects) { // Add smoke rising from campfire // (Implement in ParticleEffects system) } return light; } // Clean up destroy() { // Remove all shadows for (const [entity, data] of this.shadows) { this.removeShadow(entity); } // Remove all lights for (const [light, data] of this.lights) { this.removeLight(light); } console.log('💡 LightingSystem destroyed'); } }