added obstacle factory, worldscene, game controller, game manager and structured images&glbs into folders
This commit is contained in:
104
src/WorldScene.js
Normal file
104
src/WorldScene.js
Normal file
@@ -0,0 +1,104 @@
|
||||
// @ts-nocheck
|
||||
import * as THREE from "three";
|
||||
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
|
||||
import { clone as cloneSkeleton } from "three/examples/jsm/utils/SkeletonUtils.js";
|
||||
|
||||
const CHUNK_SIZE = 140;
|
||||
|
||||
const grassVertex = `
|
||||
varying vec2 vUv;
|
||||
uniform float uTime;
|
||||
void main() {
|
||||
vUv = uv;
|
||||
vec3 pos = position;
|
||||
float sway = sin(uTime * 2.0 + (instanceMatrix[3][0] * 0.5) + (instanceMatrix[3][2] * 0.5)) * 0.15 * uv.y;
|
||||
pos.x += sway;
|
||||
gl_Position = projectionMatrix * modelViewMatrix * instanceMatrix * vec4(pos, 1.0);
|
||||
}
|
||||
`;
|
||||
|
||||
const grassFragment = `
|
||||
varying vec2 vUv;
|
||||
void main() {
|
||||
gl_FragColor = vec4(mix(vec3(0.12, 0.28, 0.18), vec3(0.5, 0.72, 0.4), vUv.y), 1.0);
|
||||
}
|
||||
`;
|
||||
|
||||
export function createWorldChunk(zOffset, uTime) {
|
||||
const group = new THREE.Group();
|
||||
group.position.z = zOffset;
|
||||
const floor = new THREE.Mesh(new THREE.PlaneGeometry(160, CHUNK_SIZE + 0.1), new THREE.MeshStandardMaterial({ color: 0x1e2b21 }));
|
||||
floor.rotation.x = -Math.PI / 2;
|
||||
group.add(floor);
|
||||
|
||||
const count = 7000;
|
||||
const geo = new THREE.PlaneGeometry(0.4, 0.9, 1, 2);
|
||||
geo.translate(0, 0.45, 0);
|
||||
const mat = new THREE.ShaderMaterial({
|
||||
uniforms: { uTime }, vertexShader: grassVertex, fragmentShader: grassFragment,
|
||||
side: THREE.DoubleSide, alphaToCoverage: true
|
||||
});
|
||||
const mesh = new THREE.InstancedMesh(geo, mat, count);
|
||||
const dummy = new THREE.Object3D();
|
||||
for(let i=0; i<count; i++) {
|
||||
let x = (Math.random() - 0.5) * 120;
|
||||
if (x > -10 && x < 10) x += (x > 0) ? 10 : -10;
|
||||
dummy.position.set(x, 0, (Math.random() - 0.5) * CHUNK_SIZE);
|
||||
dummy.rotation.y = Math.random() * Math.PI;
|
||||
dummy.scale.setScalar(0.7 + Math.random() * 1.6);
|
||||
dummy.updateMatrix();
|
||||
mesh.setMatrixAt(i, dummy.matrix);
|
||||
}
|
||||
group.add(mesh);
|
||||
return group;
|
||||
}
|
||||
|
||||
export function createClouds(group) {
|
||||
const cloudMaterial = new THREE.MeshLambertMaterial({
|
||||
color: 0xffffff,
|
||||
transparent: true,
|
||||
opacity: 0.8
|
||||
});
|
||||
|
||||
const thickness = 2;
|
||||
// Increase count to 40 for a denser sky
|
||||
for (let i = 0; i < 40; i++) {
|
||||
const w = 10 + Math.random() * 20;
|
||||
const d = 10 + Math.random() * 20;
|
||||
const cloud = new THREE.Mesh(new THREE.BoxGeometry(w, thickness, d), cloudMaterial);
|
||||
|
||||
const y = 30 + Math.random() * 25;
|
||||
|
||||
// FIX: Spread clouds from +50 (behind camera) to -400 (deep horizon)
|
||||
// This ensures that as soon as the game starts, there are clouds
|
||||
// already "waiting" far in the distance.
|
||||
const z = (Math.random() * -450) + 50;
|
||||
|
||||
cloud.position.set((Math.random() - 0.5) * 280, y, z);
|
||||
group.add(cloud);
|
||||
}
|
||||
}
|
||||
|
||||
export function moveWorld(chunks, moveStep, chunkSize, count) {
|
||||
chunks.forEach(chunk => {
|
||||
chunk.position.z += moveStep;
|
||||
// Logic for looping the world
|
||||
if (chunk.position.z > chunkSize) {
|
||||
chunk.position.z -= chunkSize * count;
|
||||
}
|
||||
});
|
||||
}
|
||||
export function animateClouds(cloudGroup, moveStep) {
|
||||
if (!cloudGroup) return;
|
||||
|
||||
cloudGroup.children.forEach(cloud => {
|
||||
cloud.position.z += moveStep * 0.4;
|
||||
|
||||
// Reset cloud position further back to -400
|
||||
// This way they stay hidden behind the fog until they naturally drift forward
|
||||
if (cloud.position.z > 100) {
|
||||
cloud.position.z = -400;
|
||||
cloud.position.x = (Math.random() - 0.5) * 280;
|
||||
}
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user