File size: 6,317 Bytes
e30257d |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
// Import Three.js library (already included in index.html)
// const THREE = window.THREE;
class Background {
constructor() {
// Initialize core Three.js components
this.scene = new THREE.Scene();
this.camera = new THREE.PerspectiveCamera(
75, // Field of view
window.innerWidth / window.innerHeight, // Aspect ratio
0.1, // Near plane
1000 // Far plane
);
// Setup renderer with transparency and anti-aliasing
this.renderer = new THREE.WebGLRenderer({
canvas: document.querySelector('#webgl-background'),
alpha: true,
antialias: true
});
this.renderer.setSize(window.innerWidth, window.innerHeight);
this.renderer.setClearColor(0x0a0a0a, 1); // Dark background color
// Initialize particle system properties
this.particles = [];
this.particleCount = 100;
this.particleGeometry = new THREE.BufferGeometry();
this.particleMaterial = new THREE.PointsMaterial({
size: 2,
color: 0xffffff,
transparent: true,
opacity: 0.5,
blending: THREE.AdditiveBlending
});
// Set up camera position
this.camera.position.z = 100;
// Initialize the background
this.init();
// Bind event listeners
this.bindEvents();
}
init() {
// Create particle positions array
const positions = new Float32Array(this.particleCount * 3);
// Generate random positions for particles
for (let i = 0; i < this.particleCount; i++) {
const i3 = i * 3; // Index for x, y, z coordinates
positions[i3] = (Math.random() - 0.5) * window.innerWidth; // X coordinate
positions[i3 + 1] = (Math.random() - 0.5) * window.innerHeight; // Y coordinate
positions[i3 + 2] = (Math.random() - 0.5) * 500; // Z coordinate
// Store particle data for animation
this.particles.push({
velocity: (Math.random() - 0.5) * 0.2,
baseX: positions[i3],
baseY: positions[i3 + 1]
});
}
// Set particle positions in geometry
this.particleGeometry.setAttribute(
'position',
new THREE.BufferAttribute(positions, 3)
);
// Create particle system and add to scene
this.particleSystem = new THREE.Points(
this.particleGeometry,
this.particleMaterial
);
this.scene.add(this.particleSystem);
// Start animation loop
this.animate();
}
// Handle window resize events
bindEvents() {
window.addEventListener('resize', () => {
// Update camera aspect ratio and projection matrix
this.camera.aspect = window.innerWidth / window.innerHeight;
this.camera.updateProjectionMatrix();
// Update renderer size
this.renderer.setSize(window.innerWidth, window.innerHeight);
});
}
// Animation loop for particle movement
animate() {
requestAnimationFrame(() => this.animate());
const positions = this.particleGeometry.attributes.position.array;
const time = Date.now() * 0.0005;
// Update particle positions with wave-like motion
for (let i = 0; i < this.particleCount; i++) {
const i3 = i * 3;
const particle = this.particles[i];
// Create wave-like motion using sine waves
positions[i3] = particle.baseX + Math.sin(time + i) * 2;
positions[i3 + 1] = particle.baseY + Math.cos(time + i) * 2;
// Add slight drift to z-position
positions[i3 + 2] += particle.velocity;
// Reset particles that drift too far
if (Math.abs(positions[i3 + 2]) > 250) {
positions[i3 + 2] = -250;
}
}
// Mark particle positions for update
this.particleGeometry.attributes.position.needsUpdate = true;
// Add subtle camera movement
this.camera.position.x = Math.sin(time) * 10;
this.camera.position.y = Math.cos(time) * 10;
this.camera.lookAt(this.scene.position);
// Render the scene
this.renderer.render(this.scene, this.camera);
}
// Method to add dramatic effects during game events
addDramaticEffect(type) {
switch(type) {
case 'impostor_reveal':
// Create a dramatic red flash effect
this.particleMaterial.color.setHex(0xff0000);
setTimeout(() => {
this.particleMaterial.color.setHex(0xffffff);
}, 1000);
break;
case 'round_start':
// Increase particle movement temporarily
const originalVelocities = this.particles.map(p => p.velocity);
this.particles.forEach(p => p.velocity *= 2);
setTimeout(() => {
this.particles.forEach((p, i) => p.velocity = originalVelocities[i]);
}, 2000);
break;
case 'voting':
// Create a pulsing effect
const pulseAnimation = () => {
this.particleMaterial.size = 2 + Math.sin(Date.now() * 0.005) * 1;
};
const pulseInterval = setInterval(pulseAnimation, 16);
setTimeout(() => {
clearInterval(pulseInterval);
this.particleMaterial.size = 2;
}, 3000);
break;
}
}
}
// Initialize the background when the DOM is loaded
document.addEventListener('DOMContentLoaded', () => {
const background = new Background();
// Expose background instance for game events
window.gameBackground = background;
});
// Export the Background class for potential module usage
export default Background; |