diff --git a/index.html b/index.html index caf68e9..0f56940 100644 --- a/index.html +++ b/index.html @@ -71,14 +71,14 @@ - + - + diff --git a/src/scenes/GameScene.js b/src/scenes/GameScene.js index 9dfc2f3..795f4dc 100644 --- a/src/scenes/GameScene.js +++ b/src/scenes/GameScene.js @@ -87,9 +87,10 @@ class GameScene extends Phaser.Scene { this.setupCamera(); // Initialize Time & Stats - console.log('⏳ Initializing Time & Stats...'); - this.timeSystem = new TimeSystem(this); - this.timeSystem.create(); + // Initialize Weather System (Unified: Time + DayNight + Weather) + console.log('🌦️ Initializing Unified Weather System...'); + this.weatherSystem = new WeatherSystem(this); + this.timeSystem = this.weatherSystem; // Alias for compatibility with other systems (e.g. UIScene, Farming) this.statsSystem = new StatsSystem(this); this.inventorySystem = new InventorySystem(this); @@ -97,13 +98,7 @@ class GameScene extends Phaser.Scene { this.farmingSystem = new FarmingSystem(this); this.buildingSystem = new BuildingSystem(this); - // Initialize Weather System - console.log('🌦️ Initializing Weather System...'); - this.weatherSystem = new WeatherSystem(this); - - // Initialize Day/Night Cycle - console.log('🌅 Initializing Day/Night System...'); - this.dayNightSystem = new DayNightSystem(this, this.timeSystem); + // DayNightSystem removed (merged into WeatherSystem) // Initialize Sound Manager console.log('🎵 Initializing Sound Manager...'); @@ -198,11 +193,11 @@ class GameScene extends Phaser.Scene { update(time, delta) { // Update Systems - if (this.timeSystem) this.timeSystem.update(delta); + // TimeSystem update removed (handled by WeatherSystem) if (this.statsSystem) this.statsSystem.update(delta); if (this.interactionSystem) this.interactionSystem.update(delta); if (this.farmingSystem) this.farmingSystem.update(delta); - if (this.dayNightSystem) this.dayNightSystem.update(); + // DayNight update removed (handled by WeatherSystem) if (this.weatherSystem) this.weatherSystem.update(delta); // Update Parallax (foreground grass fading) diff --git a/src/systems/DayNightSystem.js b/src/systems/DayNightSystem.js deleted file mode 100644 index a71c908..0000000 --- a/src/systems/DayNightSystem.js +++ /dev/null @@ -1,95 +0,0 @@ -class DayNightSystem { - constructor(scene, timeSystem) { - this.scene = scene; - this.timeSystem = timeSystem; - - // Visual overlay - this.overlay = null; - this.currentPhase = 'day'; // dawn, day, dusk, night - - this.init(); - } - - init() { - // No local overlay - using UIScene.overlayGraphics - } - - update() { - if (!this.timeSystem) return; - - const hour = this.timeSystem.getCurrentHour(); - const phase = this.getPhase(hour); - - if (phase !== this.currentPhase) { - this.currentPhase = phase; - console.log(`🌅 Time of Day: ${phase} (${hour}:00)`); - } - - this.updateLighting(hour); - } - - getPhase(hour) { - if (hour >= 5 && hour < 7) return 'dawn'; - if (hour >= 7 && hour < 18) return 'day'; - if (hour >= 18 && hour < 20) return 'dusk'; - return 'night'; - } - - updateLighting(hour) { - // Get Shared Overlay from UI Scene - const uiScene = this.scene.scene.get('UIScene'); - if (!uiScene || !uiScene.overlayGraphics) return; - - const graphics = uiScene.overlayGraphics; - - // IMPORTANT: DayNight is the FIRST system to render to overlay, so it MUST CLEAR it. - graphics.clear(); - - const width = uiScene.scale.width; - const height = uiScene.scale.height; - - let color = 0x000033; // Default night blue - let alpha = 0; - - if (hour >= 0 && hour < 5) { - // Deep Night (0-5h) - Dark blue - color = 0x000033; - alpha = 0.6; - } else if (hour >= 5 && hour < 7) { - // Dawn (5-7h) - Orange/Pink gradient - color = 0xFF6B35; - const progress = (hour - 5) / 2; // 0-1 - alpha = 0.6 - (progress * 0.6); // 0.6 -> 0 - } else if (hour >= 7 && hour < 18) { - // Day (7-18h) - No overlay (bright) - alpha = 0; - } else if (hour >= 18 && hour < 20) { - // Dusk (18-20h) - Orange/Purple - color = 0x8B4789; - const progress = (hour - 18) / 2; // 0-1 - alpha = progress * 0.5; // 0 -> 0.5 - } else if (hour >= 20 && hour < 24) { - // Night (20-24h) - Dark blue - color = 0x000033; - const progress = (hour - 20) / 4; // 0-1 - alpha = 0.5 + (progress * 0.1); // 0.5 -> 0.6 - } - - if (alpha > 0) { - graphics.fillStyle(color, alpha); - graphics.fillRect(0, 0, width, height); - } - } - - getCurrentPhase() { - return this.currentPhase; - } - - isNight() { - return this.currentPhase === 'night'; - } - - isDay() { - return this.currentPhase === 'day'; - } -} diff --git a/src/systems/TimeSystem.js b/src/systems/TimeSystem.js deleted file mode 100644 index 99a7282..0000000 --- a/src/systems/TimeSystem.js +++ /dev/null @@ -1,107 +0,0 @@ -class TimeSystem { - constructor(scene) { - this.scene = scene; - - // Konfiguracija - this.fullDaySeconds = 300; // 5 minut za cel dan (real-time) - this.startTime = 8; // Začetek ob 8:00 - - // Stanje - this.gameTime = this.startTime; // 0 - 24 - this.dayCount = 1; - - // Lighting overlay - this.lightOverlay = null; // Ustvarjen bo v GameScene ali tu? Bolje tu če imamo dostop. - } - - create() { - // Overlay za temo - // Uporabimo velik pravokotnik čez cel ekran, ki je fixiran na kamero - // Ampak ker imamo UIScene, je bolje da je overlay v GameScene, ampak nad vsem razen UI. - // Najlažje: canvas tinting ali graphics overlay. - - // Za preprostost: Modificiramo ambient light ali tintamo igralca/teren? - // Phaser 3 ima setTint. - // Najboljši efekt za 2D: Temno moder rectangle z 'MULTIPLY' blend mode čez GameScene. - - const width = this.scene.cameras.main.width * 2; // Malo večji za varnost - const height = this.scene.cameras.main.height * 2; - - this.lightOverlay = this.scene.add.rectangle(0, 0, width, height, 0x000022); - this.lightOverlay.setScrollFactor(0); - this.lightOverlay.setDepth(9000); // Pod UI (UI je v drugi sceni), ampak nad igro - this.lightOverlay.setBlendMode(Phaser.BlendModes.MULTIPLY); - this.lightOverlay.setAlpha(0); // Začetek dan (0 alpha) - } - - update(delta) { - // Povečaj čas - // delta je v ms. - // fullDaySeconds = 24 game hours. - // 1 game hour = fullDaySeconds / 24 seconds. - const seconds = delta / 1000; - const gameHoursPerRealSecond = 24 / this.fullDaySeconds; - - this.gameTime += seconds * gameHoursPerRealSecond; - - if (this.gameTime >= 24) { - this.gameTime -= 24; - this.dayCount++; - console.log(`🌞 Day ${this.dayCount} started!`); - } - - this.updateLighting(); - this.updateUI(); - } - - updateLighting() { - if (!this.lightOverlay) return; - - // Izračunaj svetlobo (Alpha vrednost senc) - // 0 = Dan (Prozoren overlay) - // 0.8 = Polnoč (Temen overlay) - - let alpha = 0; - const t = this.gameTime; - - // Preprosta logika: - // 6:00 - 18:00 = Dan (0 alpha) - // 18:00 - 20:00 = Mrak (prehod 0 -> 0.7) - // 20:00 - 4:00 = Noč (0.7 alpha) - // 4:00 - 6:00 = Jutro (prehod 0.7 -> 0) - - if (t >= 6 && t < 18) { - alpha = 0; // Dan - } else if (t >= 18 && t < 20) { - alpha = ((t - 18) / 2) * 0.7; // Mrak - } else if (t >= 20 || t < 4) { - alpha = 0.7; // Noč - } else if (t >= 4 && t < 6) { - alpha = 0.7 - ((t - 4) / 2) * 0.7; // Jutro - } - - this.lightOverlay.setAlpha(alpha); - } - - updateUI() { - const uiScene = this.scene.scene.get('UIScene'); - if (uiScene && uiScene.clockText) { - const hours = Math.floor(this.gameTime); - const minutes = Math.floor((this.gameTime - hours) * 60); - const timeString = `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`; - uiScene.clockText.setText(`Day ${this.dayCount} - ${timeString}`); - } - } - - getCurrentHour() { - return Math.floor(this.gameTime); - } - - getGameTime() { - return this.gameTime; - } - - getDayCount() { - return this.dayCount; - } -} diff --git a/src/systems/WeatherSystem.js b/src/systems/WeatherSystem.js index a50c757..283e32d 100644 --- a/src/systems/WeatherSystem.js +++ b/src/systems/WeatherSystem.js @@ -1,138 +1,170 @@ class WeatherSystem { constructor(scene) { this.scene = scene; - this.currentWeather = 'clear'; // clear, rain, storm, fog - this.weatherDuration = 0; - this.maxWeatherDuration = 30000; // 30s per weather cycle - // Weather effects containers - this.rainParticles = []; - this.overlay = null; + // --- Time Configuration --- + this.fullDaySeconds = 300; // 5 minutes = 24 game hours + this.gameTime = 8; // Start at 8:00 + this.dayCount = 1; + + // --- Weather Configuration --- + this.currentWeather = 'clear'; + this.weatherDuration = 0; + this.maxWeatherDuration = 10000; // Random duration logic handles this + this.rainParticles = []; // {x, y, speed, length} + + // --- State --- + this.currentPhase = 'day'; this.init(); } init() { - // No local overlay - we use UI Scene + // Start weather cycle this.changeWeather(); } getOverlay() { const uiScene = this.scene.scene.get('UIScene'); - if (uiScene && uiScene.weatherGraphics) { - return uiScene.weatherGraphics; + if (uiScene && uiScene.overlayGraphics) { + return uiScene.overlayGraphics; } return null; } - changeWeather() { - // Clean up old weather - this.clearWeather(); - - // Random new weather - const weathers = ['clear', 'clear', 'rain', 'fog']; // Clear more common - this.currentWeather = weathers[Math.floor(Math.random() * weathers.length)]; - this.weatherDuration = 0; - - console.log(`🌦️ Weather changed to: ${this.currentWeather}`); - - // Apply new weather effects - this.applyWeather(); - } - - applyWeather() { - if (this.currentWeather === 'rain') { - this.startRain(); - // Play rain sound - if (this.scene.soundManager) { - this.scene.soundManager.playRainSound(); - } - } else if (this.currentWeather === 'fog') { - this.applyFog(); - } else if (this.currentWeather === 'storm') { - this.startRain(true); - // Play rain sound (louder?) - if (this.scene.soundManager) { - this.scene.soundManager.playRainSound(); - } - } else { - // Clear weather - stop ambient sounds - if (this.scene.soundManager) { - this.scene.soundManager.stopRainSound(); - } - } - } - - startRain(heavy = false) { - const width = this.scene.scale.width; - const height = this.scene.scale.height; - - // Create rain drops (keep logic for drops) - const dropCount = heavy ? 150 : 100; - - for (let i = 0; i < dropCount; i++) { - const drop = { - x: Math.random() * width, - y: Math.random() * height, - speed: heavy ? Phaser.Math.Between(400, 600) : Phaser.Math.Between(200, 400), - length: heavy ? Phaser.Math.Between(10, 15) : Phaser.Math.Between(5, 10) - }; - this.rainParticles.push(drop); - } - - // No drawing here - handled in renderWeather - } - - applyFog() { - // No drawing here - handled in renderWeather - } - - clearWeather() { - this.rainParticles = []; - // No clearing here - handled by DayNightSystem clearing the frame - } - update(delta) { - this.weatherDuration += delta; + // 1. Update Time + this.updateTime(delta); - // Change weather periodically + // 2. Update Weather Logic (Durations, Changes) + this.updateWeatherLogic(delta); + + // 3. Update Physics (Rain drops) + this.updateWeatherPhysics(delta); + + // 4. Render Atmosphere (Time + Weather) + this.render(); + } + + updateTime(delta) { + const seconds = delta / 1000; + const gameHoursPerRealSecond = 24 / this.fullDaySeconds; + + this.gameTime += seconds * gameHoursPerRealSecond; + + if (this.gameTime >= 24) { + this.gameTime -= 24; + this.dayCount++; + console.log(`🌞 Day ${this.dayCount} started!`); + } + + // Update Phase + const phase = this.getPhase(this.gameTime); + if (phase !== this.currentPhase) { + this.currentPhase = phase; + console.log(`🌅 Time of Day: ${phase} (${Math.floor(this.gameTime)}:00)`); + } + + // Update UI Clock + const uiScene = this.scene.scene.get('UIScene'); + if (uiScene && uiScene.clockText) { + const hours = Math.floor(this.gameTime); + const minutes = Math.floor((this.gameTime - hours) * 60); + const timeString = `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`; + uiScene.clockText.setText(`Day ${this.dayCount} - ${timeString}`); + } + } + + getPhase(hour) { + if (hour >= 5 && hour < 7) return 'dawn'; + if (hour >= 7 && hour < 18) return 'day'; + if (hour >= 18 && hour < 20) return 'dusk'; + return 'night'; + } + + updateWeatherLogic(delta) { + this.weatherDuration += delta; if (this.weatherDuration > this.maxWeatherDuration) { this.changeWeather(); } - - // Always render active weather - if (this.currentWeather !== 'clear') { - this.renderWeather(delta); - } } - renderWeather(delta) { - const overlay = this.getOverlay(); - if (!overlay) return; - - const height = this.scene.scale.height; - const width = this.scene.scale.width; - - // FOG - if (this.currentWeather === 'fog') { - overlay.fillStyle(0xcccccc, 0.4); - overlay.fillRect(0, 0, width, height); - return; - } - - // RAIN / STORM + updateWeatherPhysics(delta) { if (this.currentWeather === 'rain' || this.currentWeather === 'storm') { - // Update physics + const width = this.scene.scale.width; + const height = this.scene.scale.height; + for (const drop of this.rainParticles) { drop.y += (drop.speed * delta) / 1000; + + // Wrap around if (drop.y > height) { drop.y = -10; drop.x = Math.random() * width; } } + } + } - // Darken background for storm/rain (additive to DayNight) + render() { + const overlay = this.getOverlay(); + if (!overlay) return; + + // IMPORTANT: Clear previous frame to avoid buildup + overlay.clear(); + + const width = this.scene.scale.width; + const height = this.scene.scale.height; + + // --- LAYER 1: Day/Night Cycle --- + this.renderDayNight(overlay, width, height); + + // --- LAYER 2: Weather Effects (Fog, Rain darkness) --- + this.renderWeatherEffects(overlay, width, height); + } + + renderDayNight(overlay, width, height) { + const hour = this.gameTime; + + let color = 0x000033; // Default night + let alpha = 0; + + if (hour >= 0 && hour < 5) { // Deep Night + color = 0x000033; alpha = 0.6; + } else if (hour >= 5 && hour < 7) { // Dawn + color = 0xFF6B35; + const progress = (hour - 5) / 2; + alpha = 0.6 - (progress * 0.6); + } else if (hour >= 7 && hour < 18) { // Day + alpha = 0; + } else if (hour >= 18 && hour < 20) { // Dusk + color = 0x8B4789; + const progress = (hour - 18) / 2; + alpha = progress * 0.5; + } else if (hour >= 20 && hour < 24) { // Night + color = 0x000033; + const progress = (hour - 20) / 4; + alpha = 0.5 + (progress * 0.1); + } + + if (alpha > 0) { + overlay.fillStyle(color, alpha); + overlay.fillRect(0, 0, width, height); + } + } + + renderWeatherEffects(overlay, width, height) { + // Fog + if (this.currentWeather === 'fog') { + overlay.fillStyle(0xcccccc, 0.4); + overlay.fillRect(0, 0, width, height); + } + + // Rain / Storm + if (this.currentWeather === 'rain' || this.currentWeather === 'storm') { const isDark = this.currentWeather === 'storm' ? 0.3 : 0.2; + + // Additive darkness for storm overlay.fillStyle(0x000033, isDark); overlay.fillRect(0, 0, width, height); @@ -147,13 +179,65 @@ class WeatherSystem { } } - getCurrentWeather() { - return this.currentWeather; + changeWeather() { + this.clearWeather(); + + const rand = Math.random(); + if (rand < 0.6) { + this.currentWeather = 'clear'; + this.maxWeatherDuration = Phaser.Math.Between(10000, 30000); + } else if (rand < 0.8) { + this.currentWeather = 'rain'; + this.startRain(false); + this.maxWeatherDuration = Phaser.Math.Between(10000, 20000); + } else if (rand < 0.9) { + this.currentWeather = 'storm'; + this.startRain(true); + this.maxWeatherDuration = Phaser.Math.Between(8000, 15000); + } else { + this.currentWeather = 'fog'; + this.maxWeatherDuration = Phaser.Math.Between(10000, 20000); + } + + this.weatherDuration = 0; + console.log(`Weather changed to: ${this.currentWeather}`); } - setWeather(weather) { - this.currentWeather = weather; - this.weatherDuration = 0; - this.applyWeather(); + startRain(heavy) { + const width = this.scene.scale.width; + const height = this.scene.scale.height; + const dropCount = heavy ? 150 : 100; + + for (let i = 0; i < dropCount; i++) { + this.rainParticles.push({ + x: Math.random() * width, + y: Math.random() * height, + speed: heavy ? Phaser.Math.Between(400, 600) : Phaser.Math.Between(200, 400), + length: heavy ? Phaser.Math.Between(10, 15) : Phaser.Math.Between(5, 10) + }); + } + } + + clearWeather() { + this.rainParticles = []; + } + + // --- Getters for Other Systems --- + getCurrentHour() { + return Math.floor(this.gameTime); + } + + getDayCount() { + return this.dayCount; + } + + isNight() { + const hour = this.gameTime; + return hour >= 20 || hour < 5; + } + + isDay() { + const hour = this.gameTime; + return hour >= 7 && hour < 18; } }