3DWorldBuilder / index.html
awacke1's picture
Update index.html
c50b518 verified
raw
history blame
6.14 kB
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Three.js Infinite World</title>
<style>body{margin:0;overflow:hidden;}canvas{display:block;}</style>
<!-- State injected here -->
</head>
<body>
<script type="importmap">
{"imports":{"three":"https://unpkg.com/[email protected]/build/three.module.js","three/addons/":"https://unpkg.com/[email protected]/examples/jsm/"}}
</script>
<script type="module">
import * as THREE from 'three';
let scene, camera, renderer, playerMesh, raycaster, mouse;
let newlyPlacedObjects = [];
const groundMeshes = {}, placeholderPlots=new Set();
const SESSION_KEY='unsavedInfiniteWorldState';
function init(){
scene=new THREE.Scene(); scene.background=new THREE.Color(0xabcdef);
camera=new THREE.PerspectiveCamera(60,window.innerWidth/window.innerHeight,0.1,4000);
camera.position.set(0,15,20);camera.lookAt(0,0,0);
setupLighting(); setupGround(); setupPlayer();
raycaster=new THREE.Raycaster(); mouse=new THREE.Vector2();
renderer=new THREE.WebGLRenderer({antialias:true});
renderer.setSize(window.innerWidth,window.innerHeight);
renderer.shadowMap.enabled=true; document.body.appendChild(renderer.domElement);
loadObjects(); restoreUnsavedState();
window.addEventListener('mousemove',onMouseMove,false);
window.addEventListener('click',onDocClick,false);
window.addEventListener('keydown',onKeyDown);
window.addEventListener('keyup',onKeyUp);
window.teleportPlayer=teleportPlayer;
window.getSaveDataAndPosition=getSaveDataAndPosition;
window.resetNewlyPlacedObjects=resetNewlyPlacedObjects;
setInterval(pollGameState,5000);
animate();
}
function setupLighting(){
scene.add(new THREE.AmbientLight(0xffffff,0.5));
const dir=new THREE.DirectionalLight(0xffffff,1);dir.position.set(50,150,100);
dir.castShadow=true;scene.add(dir);
}
function setupGround(){
const plots=window.PLOTS_METADATA||[];
(plots.length?plots:[{grid_x:0,grid_z:0}]).forEach(p=>createGround(p.grid_x,p.grid_z,false));
}
function createGround(x,z,ph=false){
const key=`${x}_${z}`; if(groundMeshes[key])return;
const geo=new THREE.PlaneGeometry(window.PLOT_WIDTH,window.PLOT_DEPTH);
const mat=new THREE.MeshStandardMaterial({color:ph?0x448844:0x55aa55,side:THREE.DoubleSide});
const m=new THREE.Mesh(geo,mat); m.rotation.x=-Math.PI/2;
m.position.set(x*window.PLOT_WIDTH+window.PLOT_WIDTH/2,-0.05,z*window.PLOT_DEPTH+window.PLOT_DEPTH/2);
scene.add(m); groundMeshes[key]=m; if(ph)placeholderPlots.add(key);
}
function setupPlayer(){
const geo=new THREE.CapsuleGeometry(0.4,0.8,4,8);
playerMesh=new THREE.Mesh(geo,new THREE.MeshStandardMaterial({color:0x0000ff,roughness:0.6}));
playerMesh.position.set(window.PLOT_WIDTH/2,1.2,window.PLOT_DEPTH/2);
scene.add(playerMesh);
}
function loadObjects(){
(window.ALL_INITIAL_OBJECTS||[]).forEach(d=>createAndPlace(d,false));
}
function createAndPlace(d,newObj){
const obj=window.KITS[d.type]?createPrefabKit(d.type):null;
if(!obj) return;
obj.position.set(d.pos_x||d.position.x,d.pos_y||d.position.y,d.pos_z||d.position.z);
scene.add(obj); if(newObj)newlyPlacedObjects.push(obj);
}
function createPrefabKit(name){
const kit=window.KITS[name]||{}; const grp=new THREE.Group();
kit.modules?.forEach(m=>{const md=createModule(m); if(md)grp.add(md)});
return grp;
}
function createModule(n){
switch(n){
case 'Cube': return new THREE.Mesh(new THREE.BoxGeometry(1,1,1),new THREE.MeshStandardMaterial());
case 'Sphere': return new THREE.Mesh(new THREE.SphereGeometry(0.5,16,16),new THREE.MeshStandardMaterial());
case 'Cylinder': return new THREE.Mesh(new THREE.CylinderGeometry(0.5,0.5,1,12),new THREE.MeshStandardMaterial());
case 'Cone': return new THREE.Mesh(new THREE.ConeGeometry(0.5,1,12),new THREE.MeshStandardMaterial());
default: console.warn('Unknown module',n); return null;
}
}
function onDocClick(ev){
if(window.SELECTED_OBJECT_TYPE==='None')return; const candidates=Object.values(groundMeshes);
raycaster.setFromCamera(mouse,camera); const hit=raycaster.intersectObjects(candidates);
if(!hit.length)return; const pt=hit[0].point;
const mesh=createPrefabKit(window.SELECTED_OBJECT_TYPE);
if(mesh){mesh.position.copy(pt);scene.add(mesh);newlyPlacedObjects.push(mesh);saveUnsaved();}
}
function saveUnsaved(){sessionStorage.setItem(SESSION_KEY,JSON.stringify(newlyPlacedObjects.map(o=>({obj_id:o.userData?.obj_id,type:o.userData?.type,position:{x:o.position.x,y:o.position.y,z:o.position.z},rotation:{_x:o.rotation.x,_y:o.rotation.y,_z:o.rotation.z,_order:o.rotation.order}}))));}
function restoreUnsavedState(){const s=sessionStorage.getItem(SESSION_KEY); if(s){JSON.parse(s).forEach(d=>createAndPlace(d,true));}}
function resetNewlyPlacedObjects(){sessionStorage.removeItem(SESSION_KEY);newlyPlacedObjects=[];}
function getSaveDataAndPosition(){const objs=newlyPlacedObjects.map(o=>({obj_id:o.userData?.obj_id,type:o.userData?.type,position:{x:o.position.x,y:o.position.y,z:o.position.z},rotation:{_x:o.rotation.x,_y:o.rotation.y,_z:o.rotation.z,_order:o.rotation.order}}));
const pos={x:playerMesh.position.x,y:playerMesh.position.y,z:playerMesh.position.z};return JSON.stringify({playerPosition:pos,objectsToSave:objs});
}
function teleportPlayer(x,z){playerMesh.position.set(x,playerMesh.position.y,z);camera.position.set(x,playerMesh.position.y+15,z+20);camera.lookAt(playerMesh.position);}
function pollGameState(){console.log('Polling',window.GAME_STATE);}
function onMouseMove(e){mouse.x=(e.clientX/window.innerWidth)*2-1;mouse.y=-(e.clientY/window.innerHeight)*2+1;}
function onKeyDown(e){/* movement logic */}
function onKeyUp(e){}
function animate(){requestAnimationFrame(animate);renderer.render(scene,camera);}
init();
</script>
</body>
</html>