Files
novafarma/MASTER_DESIGN_RECOVERY/VisualEnhancementSystem.js
2026-01-16 02:43:46 +01:00

625 lines
18 KiB
JavaScript

/**
* VISUAL ENHANCEMENT SYSTEM
* Central system for managing visual effects, animations, and polish
*/
class VisualEnhancementSystem {
constructor(scene) {
this.scene = scene;
this.enabled = true;
// Sub-systems
this.animatedTextures = new Map();
this.weatherEffects = [];
this.lightSources = [];
this.shadows = [];
this.particles = [];
// Settings
this.settings = {
animatedTextures: true,
weatherEffects: true,
dynamicLighting: true,
shadows: true,
fogOfWar: false,
particleQuality: 'high', // low, medium, high, ultra
animationQuality: 'high',
screenShake: true,
transitions: true
};
// Animation timers
this.waterAnimTime = 0;
this.treeAnimTime = 0;
this.fireAnimTime = 0;
this.loadSettings();
this.init();
console.log('✅ Visual Enhancement System initialized');
}
init() {
this.initAnimatedTextures();
this.initWeatherEffects();
this.initLightingSystem();
this.initShadowSystem();
this.initParticleSystem();
}
// ========== ANIMATED TEXTURES ==========
initAnimatedTextures() {
if (!this.settings.animatedTextures) return;
// Create water animation frames
this.createWaterAnimation();
// Create fire animation
this.createFireAnimation();
// Create tree leaf animation
this.createTreeAnimation();
console.log('🎬 Animated textures initialized');
}
createWaterAnimation() {
// Water flow animation (4 frames)
const frames = [];
for (let i = 0; i < 4; i++) {
const graphics = this.scene.add.graphics();
graphics.fillStyle(0x4488ff, 1);
graphics.fillRect(0, 0, 64, 64);
// Add wave pattern
graphics.lineStyle(2, 0x6699ff, 0.5);
for (let y = 0; y < 64; y += 8) {
const offset = Math.sin((y + i * 16) * 0.1) * 4;
graphics.lineBetween(0, y + offset, 64, y + offset);
}
graphics.generateTexture('water_anim_' + i, 64, 64);
graphics.destroy();
frames.push('water_anim_' + i);
}
this.animatedTextures.set('water', {
frames,
currentFrame: 0,
speed: 200 // ms per frame
});
}
createFireAnimation() {
// Fire flickering (3 frames)
const frames = [];
const colors = [0xff6600, 0xff8800, 0xffaa00];
for (let i = 0; i < 3; i++) {
const graphics = this.scene.add.graphics();
graphics.fillStyle(colors[i], 1);
graphics.fillCircle(16, 16, 12 + i * 2);
graphics.generateTexture('fire_anim_' + i, 32, 32);
graphics.destroy();
frames.push('fire_anim_' + i);
}
this.animatedTextures.set('fire', {
frames,
currentFrame: 0,
speed: 150
});
}
createTreeAnimation() {
// Tree leaf rustling (subtle movement)
console.log('🌳 Tree animation ready');
}
updateAnimatedTextures(delta) {
if (!this.settings.animatedTextures) return;
this.waterAnimTime += delta;
this.fireAnimTime += delta;
// Update water
const water = this.animatedTextures.get('water');
if (water && this.waterAnimTime > water.speed) {
water.currentFrame = (water.currentFrame + 1) % water.frames.length;
this.waterAnimTime = 0;
}
// Update fire
const fire = this.animatedTextures.get('fire');
if (fire && this.fireAnimTime > fire.speed) {
fire.currentFrame = (fire.currentFrame + 1) % fire.frames.length;
this.fireAnimTime = 0;
}
}
// ========== WEATHER EFFECTS ==========
initWeatherEffects() {
if (!this.settings.weatherEffects) return;
console.log('🌦️ Weather effects initialized');
}
createSnowEffect() {
const emitter = this.scene.add.particles(0, 0, 'particle_white', {
x: { min: 0, max: this.scene.cameras.main.width },
y: -10,
speedY: { min: 50, max: 100 },
speedX: { min: -20, max: 20 },
scale: { min: 0.3, max: 0.8 },
alpha: { min: 0.5, max: 1 },
lifespan: 10000,
frequency: 50,
quantity: 2
});
emitter.setScrollFactor(0);
this.weatherEffects.push(emitter);
return emitter;
}
createRainEffect() {
const emitter = this.scene.add.particles(0, 0, 'particle_white', {
x: { min: 0, max: this.scene.cameras.main.width },
y: -10,
speedY: { min: 400, max: 600 },
speedX: { min: -50, max: -30 },
scaleX: 0.1,
scaleY: 0.5,
alpha: 0.6,
lifespan: 2000,
frequency: 10,
quantity: 5,
tint: 0x88ccff
});
emitter.setScrollFactor(0);
this.weatherEffects.push(emitter);
return emitter;
}
createLightningFlash() {
const flash = this.scene.add.rectangle(
this.scene.cameras.main.centerX,
this.scene.cameras.main.centerY,
this.scene.cameras.main.width,
this.scene.cameras.main.height,
0xffffff,
0.8
);
flash.setScrollFactor(0);
flash.setDepth(10000);
this.scene.tweens.add({
targets: flash,
alpha: 0,
duration: 200,
onComplete: () => flash.destroy()
});
}
createFogEffect() {
// Atmospheric fog overlay - covers entire screen
const fogOverlay = this.scene.add.graphics();
fogOverlay.setScrollFactor(0);
fogOverlay.setDepth(8000); // Above game, below UI
fogOverlay.setAlpha(0.4); // Semi-transparent
// Create fog particles for movement effect
const fogParticles = this.scene.add.particles(0, 0, 'particle_white', {
x: { min: 0, max: this.scene.cameras.main.width },
y: { min: 0, max: this.scene.cameras.main.height },
speedX: { min: -10, max: 10 },
speedY: { min: -5, max: 5 },
scale: { min: 2, max: 4 },
alpha: { min: 0.1, max: 0.3 },
lifespan: 10000,
frequency: 100,
quantity: 3,
tint: 0xcccccc,
blendMode: 'SCREEN'
});
fogParticles.setScrollFactor(0);
fogParticles.setDepth(8001);
// Animated fog overlay
let fogTime = 0;
const updateFog = () => {
fogTime += 0.01;
fogOverlay.clear();
const cam = this.scene.cameras.main;
// Draw multiple layers of fog for depth
for (let layer = 0; layer < 3; layer++) {
const offset = Math.sin(fogTime + layer) * 50;
const alpha = 0.1 + layer * 0.05;
fogOverlay.fillStyle(0xffffff, alpha);
// Draw wavy fog shapes
for (let i = 0; i < 5; i++) {
const x = (i * cam.width / 4) + offset;
const y = (layer * 100) + Math.cos(fogTime + i) * 30;
fogOverlay.fillCircle(x, y, 200 + layer * 50);
}
}
};
// Update fog animation every frame
this.scene.events.on('update', updateFog);
this.weatherEffects.push({
overlay: fogOverlay,
particles: fogParticles,
update: updateFog,
destroy: () => {
fogOverlay.destroy();
fogParticles.destroy();
this.scene.events.off('update', updateFog);
}
});
console.log('🌫️ Atmospheric fog effect created');
return { overlay: fogOverlay, particles: fogParticles };
}
// ========== LIGHTING SYSTEM ==========
initLightingSystem() {
if (!this.settings.dynamicLighting) return;
this.lightingLayer = this.scene.add.layer();
this.lightingLayer.setDepth(5000);
console.log('💡 Lighting system initialized');
}
addLight(x, y, radius = 100, color = 0xffaa00, intensity = 0.6) {
if (!this.settings.dynamicLighting) return null;
// Create radial gradient light
const light = this.scene.add.graphics();
const gradient = light.createRadialGradient(
radius, radius, 0,
radius, radius, radius
);
gradient.addColorStop(0, `rgba(${(color >> 16) & 0xff}, ${(color >> 8) & 0xff}, ${color & 0xff}, ${intensity})`);
gradient.addColorStop(1, 'rgba(0, 0, 0, 0)');
light.fillStyle(color, intensity);
light.fillCircle(radius, radius, radius);
light.setPosition(x - radius, y - radius);
light.setBlendMode(Phaser.BlendModes.ADD);
light.setDepth(5001);
const lightObj = {
graphics: light,
x, y, radius, color, intensity,
flickering: false
};
this.lightSources.push(lightObj);
return lightObj;
}
addTorch(x, y) {
const torch = this.addLight(x, y, 80, 0xff6600, 0.5);
if (torch) {
torch.flickering = true;
}
return torch;
}
updateLighting(delta) {
if (!this.settings.dynamicLighting) return;
// Update flickering lights
for (const light of this.lightSources) {
if (light.flickering) {
const flicker = 0.4 + Math.random() * 0.2;
light.graphics.setAlpha(flicker);
}
}
// Update ambient lighting based on time of day
if (this.scene.weatherSystem) {
const time = this.scene.weatherSystem.gameTime;
const isNight = time < 6 || time > 18;
if (isNight) {
// Darker at night
this.scene.cameras.main.setAlpha(0.7);
} else {
this.scene.cameras.main.setAlpha(1.0);
}
}
}
// ========== SHADOW SYSTEM ==========
initShadowSystem() {
if (!this.settings.shadows) return;
console.log('🌑 Shadow system initialized');
}
addShadow(entity, offsetX = 0, offsetY = 10, width = 40, height = 15) {
if (!this.settings.shadows) return null;
const shadow = this.scene.add.ellipse(
entity.x + offsetX,
entity.y + offsetY,
width,
height,
0x000000,
0.3
);
shadow.setDepth(0);
const shadowObj = { entity, shadow, offsetX, offsetY };
this.shadows.push(shadowObj);
return shadow;
}
updateShadows() {
if (!this.settings.shadows) return;
// Get time of day for shadow opacity
let opacity = 0.3;
if (this.scene.weatherSystem) {
const time = this.scene.weatherSystem.gameTime;
// Darker shadows at noon, lighter at dawn/dusk
opacity = 0.2 + Math.abs(Math.sin((time / 24) * Math.PI * 2)) * 0.3;
}
// Update shadow positions
for (const { entity, shadow, offsetX, offsetY } of this.shadows) {
if (entity.sprite) {
shadow.x = entity.sprite.x + offsetX;
shadow.y = entity.sprite.y + offsetY;
shadow.setAlpha(opacity);
}
}
}
// ========== PARTICLE SYSTEM ==========
initParticleSystem() {
// Create particle textures
this.createParticleTextures();
console.log('✨ Particle system initialized');
}
createParticleTextures() {
// White particle
const white = this.scene.add.graphics();
white.fillStyle(0xffffff, 1);
white.fillCircle(4, 4, 4);
white.generateTexture('particle_white', 8, 8);
white.destroy();
// Sparkle
const sparkle = this.scene.add.graphics();
sparkle.fillStyle(0xffff00, 1);
sparkle.fillCircle(3, 3, 3);
sparkle.generateTexture('particle_sparkle', 6, 6);
sparkle.destroy();
// Heart
const heart = this.scene.add.graphics();
heart.fillStyle(0xff0066, 1);
heart.fillCircle(3, 3, 3);
heart.fillCircle(5, 3, 3);
heart.fillTriangle(1, 4, 7, 4, 4, 8);
heart.generateTexture('particle_heart', 8, 8);
heart.destroy();
}
createHeartParticles(x, y) {
const emitter = this.scene.add.particles(x, y, 'particle_heart', {
speed: { min: 20, max: 50 },
angle: { min: -120, max: -60 },
scale: { start: 1, end: 0 },
alpha: { start: 1, end: 0 },
lifespan: 1000,
quantity: 5,
blendMode: 'ADD'
});
this.scene.time.delayedCall(1000, () => emitter.destroy());
return emitter;
}
createSparkleEffect(x, y) {
const emitter = this.scene.add.particles(x, y, 'particle_sparkle', {
speed: { min: 10, max: 30 },
scale: { start: 1, end: 0 },
alpha: { start: 1, end: 0 },
lifespan: 800,
quantity: 10,
blendMode: 'ADD'
});
this.scene.time.delayedCall(800, () => emitter.destroy());
return emitter;
}
createCheckmarkEffect(x, y) {
const checkmark = this.scene.add.text(x, y, '✓', {
fontSize: '32px',
color: '#00ff00',
fontStyle: 'bold'
});
checkmark.setOrigin(0.5);
checkmark.setDepth(10000);
this.scene.tweens.add({
targets: checkmark,
y: y - 50,
alpha: 0,
scale: 2,
duration: 1000,
ease: 'Power2',
onComplete: () => checkmark.destroy()
});
}
// ========== SCREEN EFFECTS ==========
screenShake(intensity = 10, duration = 300) {
if (!this.settings.screenShake) return;
this.scene.cameras.main.shake(duration, intensity / 1000);
}
screenFlash(color = 0xffffff, duration = 200) {
this.scene.cameras.main.flash(duration,
(color >> 16) & 0xff,
(color >> 8) & 0xff,
color & 0xff
);
}
fadeOut(duration = 500, callback) {
if (!this.settings.transitions) {
if (callback) callback();
return;
}
this.scene.cameras.main.fadeOut(duration, 0, 0, 0);
if (callback) {
this.scene.cameras.main.once('camerafadeoutcomplete', callback);
}
}
fadeIn(duration = 500) {
if (!this.settings.transitions) return;
this.scene.cameras.main.fadeIn(duration, 0, 0, 0);
}
// ========== BUILDING EFFECTS ==========
createConstructionEffect(x, y) {
// Dust particles during construction
const emitter = this.scene.add.particles(x, y, 'particle_white', {
speed: { min: 20, max: 40 },
scale: { start: 0.5, end: 0 },
alpha: { start: 0.5, end: 0 },
lifespan: 1000,
quantity: 3,
frequency: 100,
tint: 0x996633
});
return emitter;
}
createSmokeEffect(x, y) {
// Chimney smoke
const emitter = this.scene.add.particles(x, y, 'particle_white', {
speedY: { min: -30, max: -50 },
speedX: { min: -10, max: 10 },
scale: { start: 0.3, end: 1 },
alpha: { start: 0.5, end: 0 },
lifespan: 2000,
frequency: 500,
quantity: 1,
tint: 0x888888
});
return emitter;
}
// ========== FARM AUTOMATION VISUALS ==========
createPowerGridEffect(x1, y1, x2, y2) {
// Electric arc between power sources
const graphics = this.scene.add.graphics();
graphics.lineStyle(2, 0x00ffff, 0.8);
// Draw lightning-like connection
const steps = 5;
const points = [];
for (let i = 0; i <= steps; i++) {
const t = i / steps;
const x = x1 + (x2 - x1) * t + (Math.random() - 0.5) * 10;
const y = y1 + (y2 - y1) * t + (Math.random() - 0.5) * 10;
points.push({ x, y });
}
graphics.beginPath();
graphics.moveTo(points[0].x, points[0].y);
for (let i = 1; i < points.length; i++) {
graphics.lineTo(points[i].x, points[i].y);
}
graphics.strokePath();
// Fade out
this.scene.tweens.add({
targets: graphics,
alpha: 0,
duration: 200,
onComplete: () => graphics.destroy()
});
}
createMutantGlow(entity, color = 0x00ff00) {
// Radioactive glow for mutants
const glow = this.scene.add.circle(
entity.x,
entity.y,
30,
color,
0.3
);
glow.setBlendMode(Phaser.BlendModes.ADD);
glow.setDepth(entity.depth - 1);
// Pulsing animation
this.scene.tweens.add({
targets: glow,
scale: { from: 1, to: 1.2 },
alpha: { from: 0.3, to: 0.1 },
duration: 1000,
yoyo: true,
repeat: -1
});
return glow;
}
// ========== UPDATE ==========
update(delta) {
this.updateAnimatedTextures(delta);
this.updateLighting(delta);
this.updateShadows();
}
// ========== SETTINGS ==========
saveSettings() {
localStorage.setItem('novafarma_visual_enhancements', JSON.stringify(this.settings));
}
loadSettings() {
const saved = localStorage.getItem('novafarma_visual_enhancements');
if (saved) {
this.settings = { ...this.settings, ...JSON.parse(saved) };
}
}
destroy() {
if (this.lightingLayer) this.lightingLayer.destroy();
for (const { shadow } of this.shadows) {
shadow.destroy();
}
for (const effect of this.weatherEffects) {
effect.destroy();
}
console.log('✨ Visual Enhancement System destroyed');
}
}