import * as THREE from 'three' import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js' const global = (0,eval)("this") const scene = new THREE.Scene() const camera = new THREE.PerspectiveCamera(30, window.innerWidth / window.innerHeight, 0.1, 1000) const raycaster = new THREE.Raycaster() const renderer = new THREE.WebGLRenderer() const entities = {} renderer.setSize(window.innerWidth, window.innerHeight) renderer.setAnimationLoop(animate) const geometry = new THREE.PlaneGeometry(0, 0) const material = new THREE.MeshToonMaterial({ color: 0x115011 }) const ground = new THREE.Mesh(geometry, material) scene.add(ground) const ambientLight = new THREE.AmbientLight(0x404040) scene.add(ambientLight) const directionalLight = new THREE.DirectionalLight(0xffffff, 2.5) directionalLight.position.set(-0.3, 0.1, 1) directionalLight.power = 3000 scene.add(directionalLight) // const loader = new GLTFLoader() // loader.load('player.gltf', (gltf) => scene.add(gltf.scene), undefined, (err) => console.log(err)) global.THREE = THREE global.renderer = renderer global.camera = camera global.scene = scene camera.position.set(3, -12, 10) camera.rotation.set((60 / 180) * Math.PI, 0, 0) // camera.lookAt(0, 0, 0) function animate() { renderer.render(scene, camera) } var websocket = null global.websocket = null var timerId = null function connectWebSocket() { websocket = new WebSocket('ws://127.0.0.1:1280/ws') global.websocket = websocket websocket.onerror = () => websocket.close() websocket.onopen = () => { document.getElementById('connection').innerHTML = 'open' clearInterval(timerId) } websocket.onclose = () => { websocket = null document.getElementById('connection').innerHTML = 'closed' timerId = setInterval(() => { if (websocket == null) { connectWebSocket() } }, 2000) } websocket.onmessage = (event) => { let state = JSON.parse(event.data) if (state.width != null && state.height != null && (ground.geometry.attributes.width != state.width || ground.geometry.attributes.height != state.height)) { ground.geometry = new THREE.PlaneGeometry(state.width / 100, state.height / 100) ground.position.set(state.width / 200, state.height / 200, 0) } for (const e of state.entities) { let entity if (e.id in entities) { entity = entities[e.id] } else { entity = new THREE.Mesh(new THREE.SphereGeometry(e.radius / 100), new THREE.MeshToonMaterial({ color: 0xffffff })) entity.userData.type = 'entity' entity.userData.id = e.id scene.add(entity) entities[e.id] = entity } entity.position.set(e.pos.x / 100, e.pos.y / 100, e.radius / 100) } document.getElementById('state').innerHTML = JSON.stringify(state, null, 2) } } window.addEventListener('load', () => { connectWebSocket() const canvas = renderer.domElement canvas.addEventListener('mousedown', (event) => { raycaster.setFromCamera(new THREE.Vector2((event.clientX / canvas.clientWidth) * 2 - 1, (event.clientY / canvas.clientHeight) * -2 + 1), camera) const intersect = raycaster.intersectObject(ground).at(0)?.point if (intersect != null) { if (event.button == 0) { const x = Math.round(intersect.x * 100) const y = Math.round(intersect.y * 100) websocket.send(JSON.stringify({ action: 'move', id: '2', x, y })) } if (event.button == 2) { const x = Math.round(intersect.x * 100) const y = Math.round(intersect.y * 100) websocket.send(JSON.stringify({ action: 'move', id: '1', x, y })) } } }) document.addEventListener('wheel', (event) => { if (event.deltaY < 0) { camera.zoom += 0.2 if (camera.zoom > 3) { camera.zoom = 3 } camera.updateProjectionMatrix() } if (event.deltaY > 0) { camera.zoom -= 0.2 if (camera.zoom < 1) { camera.zoom = 1 } camera.updateProjectionMatrix() } }) window.addEventListener("resize", (event) => { camera.aspect = window.innerWidth / window.innerHeight camera.updateProjectionMatrix() renderer.setSize(window.innerWidth, window.innerHeight) }) document.addEventListener("contextmenu", (event) => event.preventDefault()) document.body.appendChild(canvas) })