60 lines
4.6 KiB
JavaScript
60 lines
4.6 KiB
JavaScript
import * as THREE from 'three';
|
|
|
|
export function createJourneyScenery(scene, pathZ) {
|
|
const mat = c => new THREE.MeshStandardMaterial({color:c, roughness:.7});
|
|
const wood=mat('#705340'), stone=mat('#a9a393'), black=mat('#172126'), skin=mat('#dca57e');
|
|
function part(parent, geo, material, x,y,z) {
|
|
const m=new THREE.Mesh(geo,material);m.position.set(x,y,z);m.castShadow=true;m.receiveShadow=true;parent.add(m);return m;
|
|
}
|
|
const box=(p,w,h,d,m,x,y,z)=>part(p,new THREE.BoxGeometry(w,h,d),m,x,y,z);
|
|
const home=new THREE.Group();home.position.set(-35,0,7);scene.add(home);
|
|
box(home,8,4,6,mat('#d2c1a3'),0,2,0);
|
|
const roof=part(home,new THREE.ConeGeometry(6.5,2,4),mat('#6d493d'),0,5,0);roof.rotation.y=Math.PI/4;
|
|
box(home,1.3,2.6,.15,wood,0,1.3,-3.08);
|
|
for(const x of [-2.5,2.5]){box(home,1.6,1.4,.12,mat('#8eafb3'),x,2.4,-3.08);box(home,.08,1.4,.15,wood,x,2.4,-3.16);}
|
|
box(scene,31,.035,5,mat('#555957'),-22,.02,0);
|
|
for(let x=-36;x<-8;x+=3)box(scene,1.5,.045,.12,mat('#ddd0a3'),x,.04,0);
|
|
const car=new THREE.Group();scene.add(car);
|
|
const paint=mat('#bd703c'),glass=mat('#72989e');
|
|
box(car,4.4,.65,1.9,paint,0,.8,0);box(car,2.3,.8,1.75,glass,-.15,1.5,0);box(car,2.5,.12,1.9,paint,-.15,1.96,0);
|
|
for(const x of [-1.35,1.35])for(const z of [-1,1]){
|
|
const wheel=part(car,new THREE.CylinderGeometry(.42,.42,.22,16),black,x,.48,z);wheel.rotation.x=Math.PI/2;
|
|
box(car,.09,.2,.45,mat(x>0?'#fff1c0':'#b34232'),x>0?2.23:-2.23,.9,z*.65);
|
|
}
|
|
box(car,.1,.5,1.7,black,-1.32,1.45,0);
|
|
box(scene,5,.04,3,stone,-11,.025,-4);
|
|
const gate=new THREE.Group();gate.position.set(-8.5,0,pathZ(-8.5));scene.add(gate);
|
|
for(const z of [-2.5,2.5])box(gate,.3,3.7,.3,wood,0,1.85,z);
|
|
box(gate,.4,.65,5.8,wood,0,3.4,0);
|
|
const signCanvas=document.createElement('canvas');signCanvas.width=512;signCanvas.height=128;
|
|
const ctx=signCanvas.getContext('2d');ctx.fillStyle='#24392d';ctx.fillRect(0,0,512,128);ctx.fillStyle='#f2dfae';ctx.textAlign='center';ctx.font='bold 42px Tahoma';ctx.fillText('ورودی جنگل · تپهٔ آرزوها',256,80);
|
|
const sign=part(gate,new THREE.PlaneGeometry(4,.9),new THREE.MeshBasicMaterial({map:new THREE.CanvasTexture(signCanvas),side:THREE.DoubleSide}),.25,3.4,0);sign.rotation.y=Math.PI/2;
|
|
const camp=new THREE.Group();camp.position.set(4,0,4.4);scene.add(camp);
|
|
for(let i=0;i<12;i++){const a=i*Math.PI/6;part(camp,new THREE.DodecahedronGeometry(.24),stone,Math.cos(a)*.9,.16,Math.sin(a)*.9);}
|
|
for(let i=0;i<4;i++){const log=box(camp,1.4,.16,.17,wood,0,.23,0);log.rotation.y=i*Math.PI/4;}
|
|
const flames=[];
|
|
for(let i=0;i<7;i++){
|
|
const flame=part(camp,new THREE.ConeGeometry(.18+(i%2)*.1,.8,7),new THREE.MeshBasicMaterial({color:i%2?'#ffb32f':'#f56528',transparent:true,opacity:.85}),Math.sin(i*2)*.3,.65,Math.cos(i*2)*.3);flames.push(flame);
|
|
}
|
|
const light=new THREE.PointLight('#ff993d',8,10);light.position.y=1.2;camp.add(light);
|
|
const dancers=[];
|
|
for(let i=0;i<6;i++){
|
|
const root=new THREE.Group(), a=i*Math.PI/3;root.position.set(Math.cos(a)*2.2,0,Math.sin(a)*2.2);root.rotation.y=-a-Math.PI/2;camp.add(root);
|
|
const female=i%2===0, cloth=mat(['#ae684a','#698b84','#c29d59','#75829a','#985b69','#6f8158'][i]);
|
|
part(root,new THREE.CylinderGeometry(.23,.20,.6,10),cloth,0,1.15,0);
|
|
part(root,new THREE.SphereGeometry(.22,12,10),skin,0,1.7,0);
|
|
part(root,new THREE.SphereGeometry(.235,12,10),mat('#322923'),0,1.8,-.045).scale.set(1,female?1.4:.65,1);
|
|
if(female)part(root,new THREE.CylinderGeometry(.23,.4,.5,12),cloth,0,.8,0);
|
|
for(const side of [-1,1])box(root,.14,.65,.17,black,side*.15,.4,0);
|
|
const arms=[];
|
|
for(const side of [-1,1]){const arm=new THREE.Group();arm.position.set(side*.27,1.4,0);root.add(arm);box(arm,.13,.6,.14,cloth,0,-.25,0);arms.push(arm);}
|
|
const cup=part(arms[0],new THREE.CylinderGeometry(.07,.06,.2,10),mat('#e6b853'),0,-.58,0);
|
|
dancers.push({root,arms,a});
|
|
}
|
|
return {car, update(time, phase, progress=0, lane=0) {
|
|
car.position.set(phase==='home'||phase==='boarding'?-32:phase==='driving'?-32+progress*21:-11,.05, ['entrance','walking'].includes(phase) ? -4 : -.3+lane-3.7*Math.pow(progress,6));
|
|
flames.forEach((f,i)=>{f.scale.y=.7+Math.sin(time*11+i)*.25;f.rotation.y=time+i;});light.intensity=7+Math.sin(time*17);
|
|
dancers.forEach(({root,arms,a},i)=>{root.position.y=Math.abs(Math.sin(time*3+i))*.12;root.rotation.z=Math.sin(time*3+i)*.09;arms.forEach((arm,j)=>{arm.rotation.z=(j?1:-1)*(.7+Math.sin(time*3+a+j)*.5);arm.rotation.x=Math.cos(time*2+i)*.3;});});
|
|
}};
|
|
}
|