Загрузить файлы в «3d Runner»
This commit is contained in:
253
3d Runner/background.js
Normal file
253
3d Runner/background.js
Normal file
@@ -0,0 +1,253 @@
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user