Files
Some_Projects/3d Runner/background.js

254 lines
9.2 KiB
JavaScript

/**
* Enhanced background - Space with floating geometric city silhouette shapes and
*/
class BackgroundShapes {
constructor(scene) {
this.scene = scene;
this.shapes = [];
this.stars = [];
this.cityLights = [];
this.frameCount = 0;
this.createStars();
this.createCityscape();
this.createShapes();
}
createStars() {
// Starfield
const starGeometry = new THREE.BufferGeometry();
const starCount = 500;
const positions = new Float32Array(starCount * 3);
const colors = new Float32Array(starCount * 3);
const sizes = new Float32Array(starCount);
for (let i = 0; i < starCount; i++) {
positions[i * 3] = (Math.random() - 0.5) * 100;
positions[i * 3 + 1] = Math.random() * 40 + 5;
positions[i * 3 + 2] = -40 - Math.random() * 60;
// Random star colors (white, cyan, magenta, yellow)
const colorChoice = Math.random();
if (colorChoice < 0.7) {
colors[i * 3] = 1; colors[i * 3 + 1] = 1; colors[i * 3 + 2] = 1;
} else if (colorChoice < 0.85) {
colors[i * 3] = 0; colors[i * 3 + 1] = 1; colors[i * 3 + 2] = 1;
} else {
colors[i * 3] = 1; colors[i * 3 + 1] = 0; colors[i * 3 + 2] = 1;
}
sizes[i] = Math.random() * 2 + 0.5;
}
starGeometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
starGeometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));
starGeometry.setAttribute('size', new THREE.BufferAttribute(sizes, 1));
const starMaterial = new THREE.PointsMaterial({
size: 0.3,
vertexColors: true,
transparent: true,
opacity: 0.8,
sizeAttenuation: true
});
this.starField = new THREE.Points(starGeometry, starMaterial);
scene.add(this.starField);
// Shooting stars
this.shootingStars = [];
}
createCityscape() {
// Create neon city silhouette in background
const buildingCount = 30;
const buildingMaterial = new THREE.MeshBasicMaterial({
color: 0x0a0515,
transparent: true,
opacity: 0.9
});
for (let i = 0; i < buildingCount; i++) {
const width = 1 + Math.random() * 2;
const height = 3 + Math.random() * 12;
const depth = 0.5;
const geometry = new THREE.BoxGeometry(width, height, depth);
const building = new THREE.Mesh(geometry, buildingMaterial);
building.position.set(
-25 + i * 1.8 + Math.random() * 0.5,
height / 2 - 1,
-45 - Math.random() * 10
);
// Add window lights
const windowRows = Math.floor(height / 1.5);
const windowCols = Math.floor(width / 0.8);
for (let row = 0; row < windowRows; row++) {
for (let col = 0; col < windowCols; col++) {
if (Math.random() > 0.4) {
const windowGeom = new THREE.PlaneGeometry(0.3, 0.4);
const windowColor = Math.random() > 0.5 ? 0x00ffff : 0xff00ff;
const windowMat = new THREE.MeshBasicMaterial({
color: windowColor,
transparent: true,
opacity: 0.3 + Math.random() * 0.4
});
const windowMesh = new THREE.Mesh(windowGeom, windowMat);
windowMesh.position.set(
-width/2 + 0.4 + col * 0.7,
-height/2 + 1 + row * 1.2,
depth/2 + 0.01
);
building.add(windowMesh);
}
}
}
this.cityLights.push(building);
scene.add(building);
}
// Ground reflection plane
const reflectionGeom = new THREE.PlaneGeometry(60, 100);
const reflectionMat = new THREE.MeshBasicMaterial({
color: 0x00ffff,
transparent: true,
opacity: 0.05,
side: THREE.DoubleSide
});
const reflection = new THREE.Mesh(reflectionGeom, reflectionMat);
reflection.rotation.x = -Math.PI / 2;
reflection.position.y = -0.48;
reflection.position.z = -20;
scene.add(reflection);
}
createShapes() {
// Floating neon shapes
const colors = [0x00ffff, 0xff00ff, 0x6644aa, 0xffd700];
const types = ['cube', 'octahedron', 'tetrahedron', 'torus'];
for (let i = 0; i < 20; i++) {
let geometry;
const type = types[Math.floor(Math.random() * types.length)];
switch(type) {
case 'cube':
geometry = new THREE.BoxGeometry(0.8, 0.8, 0.8);
break;
case 'octahedron':
geometry = new THREE.OctahedronGeometry(0.6);
break;
case 'tetrahedron':
geometry = new THREE.TetrahedronGeometry(0.6);
break;
case 'torus':
geometry = new THREE.TorusGeometry(0.4, 0.15, 8, 16);
break;
}
const material = new THREE.MeshBasicMaterial({
color: colors[Math.floor(Math.random() * colors.length)],
transparent: true,
opacity: 0.2,
wireframe: true
});
const mesh = new THREE.Mesh(geometry, material);
mesh.position.set(
(Math.random() - 0.5) * 30,
Math.random() * 12 + 3,
-25 - Math.random() * 35
);
mesh.userData.rotationSpeed = {
x: (Math.random() - 0.5) * 0.02,
y: (Math.random() - 0.5) * 0.02,
z: (Math.random() - 0.5) * 0.02
};
mesh.userData.floatSpeed = 0.003 + Math.random() * 0.008;
mesh.userData.baseY = mesh.position.y;
mesh.userData.floatAmount = 1 + Math.random() * 2;
this.shapes.push(mesh);
scene.add(mesh);
}
}
update(frameCount) {
this.frameCount = frameCount;
// Animate starfield
if (this.starField) {
this.starField.rotation.y = frameCount * 0.0001;
this.starField.position.z = Math.sin(frameCount * 0.001) * 2;
}
// Animate shapes
this.shapes.forEach(mesh => {
mesh.rotation.x += mesh.userData.rotationSpeed.x;
mesh.rotation.y += mesh.userData.rotationSpeed.y;
mesh.rotation.z += mesh.userData.rotationSpeed.z;
mesh.position.y = mesh.userData.baseY +
Math.sin(frameCount * mesh.userData.floatSpeed) * mesh.userData.floatAmount;
});
// Twinkle city lights
this.cityLights.forEach((building, idx) => {
building.children.forEach((window, wIdx) => {
if (window.material) {
const twinkle = Math.sin(frameCount * 0.05 + idx * 0.5 + wIdx * 0.1);
window.material.opacity = 0.3 + twinkle * 0.2;
}
});
});
// Random shooting star
if (frameCount % 200 === 0 && Math.random() > 0.5) {
this.createShootingStar();
}
// Update shooting stars
for (let i = this.shootingStars.length - 1; i >= 0; i--) {
const ss = this.shootingStars[i];
ss.position.add(ss.userData.velocity);
ss.material.opacity -= 0.02;
if (ss.material.opacity <= 0) {
this.scene.remove(ss);
this.shootingStars.splice(i, 1);
}
}
}
createShootingStar() {
const geometry = new THREE.BufferGeometry().setFromPoints([
new THREE.Vector3(0, 0, 0),
new THREE.Vector3(0, -2, 1)
]);
const material = new THREE.LineBasicMaterial({
color: 0xffffff,
transparent: true,
opacity: 1
});
const shootingStar = new THREE.Line(geometry, material);
shootingStar.position.set(
Math.random() * 40 - 20,
25 + Math.random() * 10,
-30 - Math.random() * 20
);
shootingStar.userData.velocity = new THREE.Vector3(-0.3, -0.5, 0.5);
this.shootingStars.push(shootingStar);
this.scene.add(shootingStar);
}
}