167 lines
5.4 KiB
JavaScript
167 lines
5.4 KiB
JavaScript
/**
|
|
* 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;
|