/** * Effects3D Class - Visual Effects for 3D Game */ class Effects3D { constructor(scene) { this.scene = scene; this.particles = []; } // Создание системы частиц createParticleSystem(x, y, z, color, count = 20) { const geometry = new THREE.BufferGeometry(); const positions = []; const velocities = []; for (let i = 0; i < count; i++) { positions.push(x, y, z); velocities.push( (Math.random() - 0.5) * 0.3, Math.random() * 0.2, (Math.random() - 0.5) * 0.3 ); } geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3)); const material = new THREE.PointsMaterial({ color: color, size: 0.15, transparent: true, opacity: 1 }); const particles = new THREE.Points(geometry, material); this.scene.add(particles); return { mesh: particles, velocities: velocities, life: 1.0, update: () => { const positions = particles.geometry.attributes.position.array; for (let i = 0; i < count; i++) { positions[i * 3] += velocities[i * 3]; positions[i * 3 + 1] += velocities[i * 3 + 1]; positions[i * 3 + 2] += velocities[i * 3 + 2]; velocities[i * 3 + 1] -= 0.01; // гравитация } particles.geometry.attributes.position.needsUpdate = true; particles.material.opacity = this.life; this.life -= 0.02; } }; } // Эффект при получении урона showDamageEffect(x, z) { const effect = this.createParticleSystem(x, 1, z, 0xff0000, 15); this.particles.push(effect); } // Эффект при получении денег showMoneyEffect(x, z) { const effect = this.createParticleSystem(x, 1, z, 0xffd700, 10); this.particles.push(effect); } // Эффект при лечении showHealEffect(x, z) { const effect = this.createParticleSystem(x, 1, z, 0x00ff00, 15); this.particles.push(effect); } // Эффект при убийстве врага showKillEffect(x, z) { const effect = this.createParticleSystem(x, 1, z, 0xff4444, 25); this.particles.push(effect); } // Обновить все частицы update() { for (let i = this.particles.length - 1; i >= 0; i--) { const p = this.particles[i]; p.update(); if (p.life <= 0) { this.scene.remove(p.mesh); p.mesh.geometry.dispose(); p.mesh.material.dispose(); this.particles.splice(i, 1); } } } // Тряска экрана shakeScreen(intensity = 0.5) { const originalPos = Game.camera.position.clone(); const shake = () => { Game.camera.position.x = originalPos.x + (Math.random() - 0.5) * intensity; Game.camera.position.y = originalPos.y + (Math.random() - 0.5) * intensity; }; const interval = setInterval(shake, 30); setTimeout(() => { clearInterval(interval); Game.camera.position.copy(originalPos); }, 300); } // Плавающий текст createFloatingText(x, y, z, text, color = '#ffffff') { const canvas = document.createElement('canvas'); const context = canvas.getContext('2d'); canvas.width = 256; canvas.height = 64; context.fillStyle = 'transparent'; context.fillRect(0, 0, canvas.width, canvas.height); context.font = 'bold 32px Arial'; context.fillStyle = color; context.textAlign = 'center'; context.fillText(text, 128, 40); const texture = new THREE.CanvasTexture(canvas); const material = new THREE.SpriteMaterial({ map: texture, transparent: true, opacity: 1 }); const sprite = new THREE.Sprite(material); sprite.position.set(x, y + 2, z); sprite.scale.set(2, 0.5, 1); this.scene.add(sprite); // Анимация всплывания const animate = () => { sprite.position.y += 0.05; sprite.material.opacity -= 0.02; if (sprite.material.opacity <= 0) { this.scene.remove(sprite); texture.dispose(); material.dispose(); return; } requestAnimationFrame(animate); }; animate(); } // Очистка всех эффектов dispose() { this.particles.forEach(p => { this.scene.remove(p.mesh); p.mesh.geometry.dispose(); p.mesh.material.dispose(); }); this.particles = []; } } // Глобальный экземпляр window.Effects = null;