Files
novafarma/src/systems/BuildingVisualsSystem.js
2025-12-13 00:02:38 +01:00

635 lines
17 KiB
JavaScript

/**
* BUILDING VISUALS & GENETICS SYSTEM
* Advanced animations for farm automation buildings and genetics lab
*/
class BuildingVisualsSystem {
constructor(scene) {
this.scene = scene;
this.enabled = true;
// Building animations
this.buildings = new Map();
this.conveyorBelts = [];
this.windmills = [];
this.silos = [];
// Genetics lab
this.geneticsLab = null;
this.dnaHelixAnimation = null;
this.mutationVats = [];
// Settings
this.settings = {
buildingAnimations: true,
particleEffects: true,
geneticsUI: true,
animationSpeed: 1.0
};
this.loadSettings();
this.init();
console.log('✅ Building Visuals System initialized');
}
init() {
console.log('🏭 Building animations ready');
}
// ========== AUTO-PLANTER ==========
createAutoPlanter(x, y) {
if (!this.settings.buildingAnimations) return null;
const planter = {
x, y,
arm: null,
seed: null,
isPlanting: false
};
// Create mechanical arm
const arm = this.scene.add.graphics();
arm.lineStyle(4, 0x888888, 1);
arm.lineBetween(0, 0, 0, 30); // Vertical arm
arm.lineBetween(0, 30, 20, 30); // Horizontal extension
arm.setPosition(x, y);
arm.setDepth(100);
planter.arm = arm;
this.buildings.set(`planter_${x}_${y}`, planter);
return planter;
}
animatePlanting(planter, targetX, targetY) {
if (!planter || planter.isPlanting) return;
planter.isPlanting = true;
// Arm extends down
this.scene.tweens.add({
targets: planter.arm,
y: planter.y + 20,
duration: 500,
ease: 'Power2',
onComplete: () => {
// Drop seed
this.createSeedParticle(targetX, targetY);
// Arm retracts
this.scene.tweens.add({
targets: planter.arm,
y: planter.y,
duration: 500,
ease: 'Power2',
onComplete: () => {
planter.isPlanting = false;
}
});
}
});
}
createSeedParticle(x, y) {
const seed = this.scene.add.circle(x, y - 20, 3, 0x8B4513);
seed.setDepth(99);
this.scene.tweens.add({
targets: seed,
y: y,
duration: 300,
ease: 'Bounce.easeOut',
onComplete: () => {
// Puff of dirt
if (this.scene.visualEnhancements) {
this.scene.visualEnhancements.createSparkleEffect(x, y);
}
seed.destroy();
}
});
}
// ========== AUTO-HARVESTER ==========
createAutoHarvester(x, y) {
if (!this.settings.buildingAnimations) return null;
const harvester = {
x, y,
blades: [],
isHarvesting: false,
rotation: 0
};
// Create spinning blades
for (let i = 0; i < 4; i++) {
const blade = this.scene.add.graphics();
blade.lineStyle(3, 0xC0C0C0, 1);
blade.lineBetween(0, 0, 15, 0);
blade.setPosition(x, y);
blade.setRotation((Math.PI / 2) * i);
blade.setDepth(100);
harvester.blades.push(blade);
}
this.buildings.set(`harvester_${x}_${y}`, harvester);
return harvester;
}
animateHarvesting(harvester, cropX, cropY) {
if (!harvester || harvester.isHarvesting) return;
harvester.isHarvesting = true;
// Spin blades
for (const blade of harvester.blades) {
this.scene.tweens.add({
targets: blade,
rotation: blade.rotation + Math.PI * 4,
duration: 1000,
ease: 'Linear'
});
}
// Move to crop
this.scene.tweens.add({
targets: harvester.blades,
x: cropX,
y: cropY,
duration: 500,
ease: 'Power2',
onComplete: () => {
// Harvest effect
this.createHarvestEffect(cropX, cropY);
// Return to base
this.scene.tweens.add({
targets: harvester.blades,
x: harvester.x,
y: harvester.y,
duration: 500,
ease: 'Power2',
onComplete: () => {
harvester.isHarvesting = false;
}
});
}
});
}
createHarvestEffect(x, y) {
// Crop particles
const emitter = this.scene.add.particles(x, y, 'particle_white', {
speed: { min: 30, max: 60 },
scale: { start: 0.5, end: 0 },
alpha: { start: 1, end: 0 },
lifespan: 800,
quantity: 10,
tint: 0xFFD700
});
this.scene.time.delayedCall(800, () => emitter.destroy());
}
// ========== CONVEYOR BELT ==========
createConveyorBelt(x, y, width, direction = 'right') {
if (!this.settings.buildingAnimations) return null;
const belt = {
x, y, width, direction,
items: [],
speed: 50 // pixels per second
};
// Create belt graphics
const graphics = this.scene.add.graphics();
graphics.fillStyle(0x444444, 1);
graphics.fillRect(x, y, width, 20);
// Moving lines to show direction
for (let i = 0; i < width; i += 20) {
const line = this.scene.add.rectangle(
x + i,
y + 10,
10,
2,
0x888888
);
line.setDepth(99);
// Animate line movement
const targetX = direction === 'right' ? x + width : x;
this.scene.tweens.add({
targets: line,
x: targetX,
duration: (width / belt.speed) * 1000,
repeat: -1,
ease: 'Linear'
});
}
belt.graphics = graphics;
this.conveyorBelts.push(belt);
return belt;
}
addItemToBelt(belt, itemSprite) {
if (!belt) return;
belt.items.push(itemSprite);
itemSprite.setPosition(belt.x, belt.y + 10);
itemSprite.setDepth(100);
// Move item along belt
const targetX = belt.direction === 'right'
? belt.x + belt.width
: belt.x;
this.scene.tweens.add({
targets: itemSprite,
x: targetX,
duration: (belt.width / belt.speed) * 1000,
ease: 'Linear',
onComplete: () => {
// Remove from belt
const index = belt.items.indexOf(itemSprite);
if (index > -1) {
belt.items.splice(index, 1);
}
}
});
}
// ========== WINDMILL ==========
createWindmill(x, y) {
if (!this.settings.buildingAnimations) return null;
const windmill = {
x, y,
blades: null,
powerGlow: null,
isPowered: false,
rotation: 0
};
// Create blades
const blades = this.scene.add.graphics();
blades.lineStyle(4, 0x8B4513, 1);
// Draw 4 blades
for (let i = 0; i < 4; i++) {
const angle = (Math.PI / 2) * i;
const endX = Math.cos(angle) * 30;
const endY = Math.sin(angle) * 30;
blades.lineBetween(0, 0, endX, endY);
}
blades.setPosition(x, y);
blades.setDepth(100);
windmill.blades = blades;
// Power glow
const glow = this.scene.add.circle(x, y, 40, 0x00ffff, 0);
glow.setBlendMode(Phaser.BlendModes.ADD);
glow.setDepth(99);
windmill.powerGlow = glow;
// Rotate blades
this.scene.tweens.add({
targets: blades,
rotation: Math.PI * 2,
duration: 3000 / this.settings.animationSpeed,
repeat: -1,
ease: 'Linear'
});
this.windmills.push(windmill);
return windmill;
}
setPowerState(windmill, powered) {
if (!windmill) return;
windmill.isPowered = powered;
if (powered) {
// Glow on
this.scene.tweens.add({
targets: windmill.powerGlow,
alpha: 0.4,
duration: 500
});
// Particle trail
if (this.settings.particleEffects) {
const emitter = this.scene.add.particles(
windmill.x,
windmill.y,
'particle_white',
{
speed: 20,
scale: { start: 0.3, end: 0 },
alpha: { start: 0.6, end: 0 },
lifespan: 1000,
frequency: 200,
quantity: 1,
tint: 0x00ffff
}
);
windmill.particleEmitter = emitter;
}
} else {
// Glow off
this.scene.tweens.add({
targets: windmill.powerGlow,
alpha: 0,
duration: 500
});
// Stop particles
if (windmill.particleEmitter) {
windmill.particleEmitter.destroy();
windmill.particleEmitter = null;
}
}
}
// ========== STORAGE SILO ==========
createStorageSilo(x, y, capacity = 1000) {
if (!this.settings.buildingAnimations) return null;
const silo = {
x, y,
capacity,
currentAmount: 0,
fillIndicator: null,
fillBar: null
};
// Silo structure
const structure = this.scene.add.graphics();
structure.fillStyle(0x666666, 1);
structure.fillRect(x - 20, y - 60, 40, 60);
structure.fillCircle(x, y - 60, 20);
structure.setDepth(100);
silo.structure = structure;
// Fill indicator (inside silo)
const fillBar = this.scene.add.rectangle(
x,
y,
36,
0,
0xFFD700,
0.8
);
fillBar.setOrigin(0.5, 1);
fillBar.setDepth(101);
silo.fillBar = fillBar;
// Percentage text
const text = this.scene.add.text(x, y - 70, '0%', {
fontSize: '12px',
color: '#ffffff',
fontStyle: 'bold'
});
text.setOrigin(0.5);
text.setDepth(102);
silo.text = text;
this.silos.push(silo);
return silo;
}
updateSiloFill(silo, amount) {
if (!silo) return;
silo.currentAmount = Phaser.Math.Clamp(amount, 0, silo.capacity);
const percentage = (silo.currentAmount / silo.capacity) * 100;
const fillHeight = (percentage / 100) * 56; // Max height
// Animate fill
this.scene.tweens.add({
targets: silo.fillBar,
height: fillHeight,
duration: 500,
ease: 'Power2'
});
// Update text
silo.text.setText(`${Math.round(percentage)}%`);
}
// ========== GENETICS LAB ==========
createGeneticsLab(x, y) {
if (!this.settings.geneticsUI) return null;
const lab = {
x, y,
dnaHelix: null,
vats: [],
isActive: false
};
// Lab structure
const structure = this.scene.add.rectangle(x, y, 80, 60, 0x333333);
structure.setStrokeStyle(2, 0x00ff00);
structure.setDepth(100);
lab.structure = structure;
this.geneticsLab = lab;
return lab;
}
showDNAHelixAnimation(x, y) {
if (!this.settings.geneticsUI) return null;
// Create DNA helix
const helix = this.scene.add.container(x, y);
helix.setDepth(200);
// Two strands
const strand1 = [];
const strand2 = [];
for (let i = 0; i < 20; i++) {
const yPos = i * 10 - 100;
const angle = (i / 20) * Math.PI * 4;
const x1 = Math.cos(angle) * 15;
const x2 = Math.cos(angle + Math.PI) * 15;
const dot1 = this.scene.add.circle(x1, yPos, 3, 0x00ff00);
const dot2 = this.scene.add.circle(x2, yPos, 3, 0x00ffff);
helix.add(dot1);
helix.add(dot2);
strand1.push(dot1);
strand2.push(dot2);
// Connecting lines
if (i % 3 === 0) {
const line = this.scene.add.graphics();
line.lineStyle(1, 0xffffff, 0.5);
line.lineBetween(x1, yPos, x2, yPos);
helix.add(line);
}
}
// Rotate helix
this.scene.tweens.add({
targets: helix,
rotation: Math.PI * 2,
duration: 4000,
repeat: -1,
ease: 'Linear'
});
// Pulse effect
this.scene.tweens.add({
targets: helix,
scale: { from: 1, to: 1.1 },
duration: 2000,
yoyo: true,
repeat: -1
});
this.dnaHelixAnimation = helix;
return helix;
}
hideDNAHelixAnimation() {
if (this.dnaHelixAnimation) {
this.dnaHelixAnimation.destroy();
this.dnaHelixAnimation = null;
}
}
createMutationVat(x, y) {
if (!this.settings.geneticsUI) return null;
const vat = {
x, y,
container: null,
liquid: null,
bubbles: null,
isActive: false
};
// Vat container
const container = this.scene.add.graphics();
container.fillStyle(0x444444, 1);
container.fillRect(x - 20, y - 40, 40, 40);
container.lineStyle(2, 0x666666);
container.strokeRect(x - 20, y - 40, 40, 40);
container.setDepth(100);
vat.container = container;
// Liquid
const liquid = this.scene.add.rectangle(
x,
y - 20,
36,
36,
0x00ff00,
0.6
);
liquid.setDepth(101);
vat.liquid = liquid;
this.mutationVats.push(vat);
return vat;
}
activateMutationVat(vat) {
if (!vat || vat.isActive) return;
vat.isActive = true;
// Bubbling effect
const emitter = this.scene.add.particles(
vat.x,
vat.y - 40,
'particle_white',
{
speedY: { min: -30, max: -50 },
speedX: { min: -5, max: 5 },
scale: { start: 0.2, end: 0 },
alpha: { start: 0.8, end: 0 },
lifespan: 1000,
frequency: 200,
quantity: 2,
tint: 0x00ff00
}
);
vat.bubbles = emitter;
// Lightning effect
if (this.settings.particleEffects) {
this.createLightningEffect(vat.x, vat.y - 60);
}
// Liquid glow pulse
this.scene.tweens.add({
targets: vat.liquid,
alpha: { from: 0.6, to: 0.9 },
duration: 800,
yoyo: true,
repeat: -1
});
}
createLightningEffect(x, y) {
const lightning = this.scene.add.graphics();
lightning.lineStyle(2, 0xffff00, 1);
// Zigzag lightning
let currentX = x;
let currentY = y;
for (let i = 0; i < 5; i++) {
const nextX = currentX + (Math.random() - 0.5) * 20;
const nextY = currentY + 10;
lightning.lineBetween(currentX, currentY, nextX, nextY);
currentX = nextX;
currentY = nextY;
}
lightning.setDepth(200);
// Flash and fade
this.scene.tweens.add({
targets: lightning,
alpha: 0,
duration: 200,
onComplete: () => lightning.destroy()
});
}
// ========== SETTINGS ==========
saveSettings() {
localStorage.setItem('novafarma_building_visuals', JSON.stringify(this.settings));
}
loadSettings() {
const saved = localStorage.getItem('novafarma_building_visuals');
if (saved) {
this.settings = { ...this.settings, ...JSON.parse(saved) };
}
}
destroy() {
if (this.dnaHelixAnimation) this.dnaHelixAnimation.destroy();
for (const vat of this.mutationVats) {
if (vat.bubbles) vat.bubbles.destroy();
}
console.log('🏭 Building Visuals System destroyed');
}
}