awacke1 commited on
Commit
f7538ec
·
verified ·
1 Parent(s): 6e3ec2c

Create index.html

Browse files
Files changed (1) hide show
  1. index.html +282 -0
index.html ADDED
@@ -0,0 +1,282 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Shared 3D World Builder</title>
7
+ <style>
8
+ body { margin: 0; overflow: hidden; }
9
+ canvas { display: block; }
10
+ #info { position: absolute; top: 10px; left: 10px; color: white; background: rgba(0,0,0,0.7); padding: 10px; }
11
+ </style>
12
+ </head>
13
+ <body>
14
+ <div id="info">Use WASD to move, mouse to look, click to place object, right-click to delete.</div>
15
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r134/three.min.js"></script>
16
+ <script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/controls/PointerLockControls.js"></script>
17
+ <script>
18
+ let scene, camera, renderer, controls, websocket, selectedObjectType = 'None', worldObjects = {};
19
+ let moveForward = false, moveBackward = false, moveLeft = false, moveRight = false;
20
+ const username = window.USERNAME || 'Anonymous';
21
+ const websocketUrl = window.WEBSOCKET_URL || 'ws://localhost:8765';
22
+ const plotWidth = window.PLOT_WIDTH || 50.0;
23
+ const plotDepth = window.PLOT_DEPTH || 50.0;
24
+
25
+ function init() {
26
+ scene = new THREE.Scene();
27
+ camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
28
+ renderer = new THREE.WebGLRenderer();
29
+ renderer.setSize(window.innerWidth, window.innerHeight);
30
+ document.body.appendChild(renderer.domElement);
31
+
32
+ controls = new THREE.PointerLockControls(camera, document.body);
33
+ scene.add(controls.getObject());
34
+ camera.position.y = 1.6;
35
+
36
+ const groundGeometry = new THREE.PlaneGeometry(plotWidth, plotDepth);
37
+ const groundMaterial = new THREE.MeshBasicMaterial({ color: 0x888888 });
38
+ const ground = new THREE.Mesh(groundGeometry, groundMaterial);
39
+ ground.rotation.x = -Math.PI / 2;
40
+ scene.add(ground);
41
+
42
+ const gridHelper = new THREE.GridHelper(plotWidth, plotWidth / 2);
43
+ scene.add(gridHelper);
44
+
45
+ document.addEventListener('click', () => controls.lock());
46
+ document.addEventListener('keydown', onKeyDown);
47
+ document.addEventListener('keyup', onKeyUp);
48
+ document.addEventListener('mousedown', onMouseDown);
49
+ window.addEventListener('resize', () => {
50
+ camera.aspect = window.innerWidth / window.innerHeight;
51
+ camera.updateProjectionMatrix();
52
+ renderer.setSize(window.innerWidth, window.innerHeight);
53
+ });
54
+
55
+ initWebSocket();
56
+ animate();
57
+ }
58
+
59
+ function initWebSocket() {
60
+ websocket = new WebSocket(websocketUrl);
61
+ websocket.onopen = () => console.log('WebSocket connected');
62
+ websocket.onmessage = (event) => {
63
+ const data = JSON.parse(event.data);
64
+ if (data.type === 'initial_state' || data.type === 'object_placed') {
65
+ const objects = data.type === 'initial_state' ? data.payload : { [data.payload.object_data.obj_id]: data.payload.object_data };
66
+ for (let obj_id in objects) {
67
+ if (!worldObjects[obj_id]) {
68
+ worldObjects[obj_id] = objects[obj_id];
69
+ addObjectToScene(objects[obj_id]);
70
+ }
71
+ }
72
+ } else if (data.type === 'object_deleted') {
73
+ if (worldObjects[data.payload.obj_id]) {
74
+ removeObjectFromScene(data.payload.obj_id);
75
+ delete worldObjects[data.payload.obj_id];
76
+ }
77
+ } else if (data.type === 'player_moved') {
78
+ // Handle player movement visualization if needed
79
+ } else if (data.type === 'user_join' || data.type === 'user_leave' || data.type === 'user_rename') {
80
+ console.log(`${data.payload.username} ${data.type === 'user_join' ? 'joined' : data.type === 'user_leave' ? 'left' : 'renamed to ' + data.payload.new_username}`);
81
+ }
82
+ };
83
+ websocket.onclose = () => console.log('WebSocket closed');
84
+ websocket.onerror = (error) => console.error('WebSocket error:', error);
85
+ }
86
+
87
+ function updateSelectedObjectType(newType) {
88
+ selectedObjectType = newType;
89
+ console.log(`Tool changed to: ${newType}`);
90
+ }
91
+
92
+ function addObjectToScene(objData) {
93
+ let geometry, material, mesh;
94
+ switch (objData.type) {
95
+ case 'Cube':
96
+ geometry = new THREE.BoxGeometry(1, 1, 1);
97
+ material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
98
+ break;
99
+ case 'Sphere':
100
+ geometry = new THREE.SphereGeometry(0.5, 32, 32);
101
+ material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
102
+ break;
103
+ case 'Cylinder':
104
+ geometry = new THREE.CylinderGeometry(0.5, 0.5, 1, 32);
105
+ material = new THREE.MeshBasicMaterial({ color: 0x0000ff });
106
+ break;
107
+ case 'Cone':
108
+ geometry = new THREE.ConeGeometry(0.5, 1, 32);
109
+ material = new THREE.MeshBasicMaterial({ color: 0xffff00 });
110
+ break;
111
+ case 'Torus':
112
+ geometry = new THREE.TorusGeometry(0.4, 0.1, 16, 100);
113
+ material = new THREE.MeshBasicMaterial({ color: 0xff00ff });
114
+ break;
115
+ case 'Tree':
116
+ geometry = new THREE.ConeGeometry(0.5, 2, 8);
117
+ material = new THREE.MeshBasicMaterial({ color: 0x228B22 });
118
+ break;
119
+ case 'Rock':
120
+ geometry = new THREE.DodecahedronGeometry(0.5);
121
+ material = new THREE.MeshBasicMaterial({ color: 0x808080 });
122
+ break;
123
+ case 'Simple House':
124
+ geometry = new THREE.BoxGeometry(2, 1.5, 2);
125
+ material = new THREE.MeshBasicMaterial({ color: 0xA52A2A });
126
+ break;
127
+ case 'Pine Tree':
128
+ geometry = new THREE.ConeGeometry(0.3, 1.5, 8);
129
+ material = new THREE.MeshBasicMaterial({ color: 0x006400 });
130
+ break;
131
+ case 'Brick Wall':
132
+ geometry = new THREE.BoxGeometry(3, 1, 0.2);
133
+ material = new THREE.MeshBasicMaterial({ color: 0x8B4513 });
134
+ break;
135
+ case 'Mushroom':
136
+ geometry = new THREE.SphereGeometry(0.5, 32, 16, 0, Math.PI);
137
+ material = new THREE.MeshBasicMaterial({ color: 0xF5F5DC });
138
+ break;
139
+ case 'Cactus':
140
+ geometry = new THREE.CylinderGeometry(0.2, 0.2, 1.5, 8);
141
+ material = new THREE.MeshBasicMaterial({ color: 0x2E8B57 });
142
+ break;
143
+ case 'Campfire':
144
+ geometry = new THREE.DodecahedronGeometry(0.3);
145
+ material = new THREE.MeshBasicMaterial({ color: 0xFF4500 });
146
+ break;
147
+ case 'Star':
148
+ geometry = new THREE.SphereGeometry(0.3, 4, 2);
149
+ material = new THREE.MeshBasicMaterial({ color: 0xFFFF00 });
150
+ break;
151
+ case 'Gem':
152
+ geometry = new THREE.OctahedronGeometry(0.4);
153
+ material = new THREE.MeshBasicMaterial({ color: 0x00CED1 });
154
+ break;
155
+ case 'Tower':
156
+ geometry = new THREE.CylinderGeometry(0.3, 0.5, 2, 8);
157
+ material = new THREE.MeshBasicMaterial({ color: 0x708090 });
158
+ break;
159
+ case 'Barrier':
160
+ geometry = new THREE.BoxGeometry(2, 0.5, 0.2);
161
+ material = new THREE.MeshBasicMaterial({ color: 0x696969 });
162
+ break;
163
+ case 'Fountain':
164
+ geometry = new THREE.CylinderGeometry(0.5, 0.3, 1, 32);
165
+ material = new THREE.MeshBasicMaterial({ color: 0x4682B4 });
166
+ break;
167
+ case 'Lantern':
168
+ geometry = new THREE.BoxGeometry(0.3, 0.5, 0.3);
169
+ material = new THREE.MeshBasicMaterial({ color: 0xFFD700 });
170
+ break;
171
+ case 'Sign Post':
172
+ geometry = new THREE.BoxGeometry(0.2, 1, 0.2);
173
+ material = new THREE.MeshBasicMaterial({ color: 0x8B4513 });
174
+ break;
175
+ default:
176
+ return;
177
+ }
178
+ mesh = new THREE.Mesh(geometry, material);
179
+ mesh.position.set(objData.position.x, objData.position.y, objData.position.z);
180
+ mesh.rotation.set(objData.rotation.x, objData.rotation.y, objData.rotation.z);
181
+ mesh.name = objData.obj_id;
182
+ scene.add(mesh);
183
+ }
184
+
185
+ function removeObjectFromScene(obj_id) {
186
+ const object = scene.getObjectByName(obj_id);
187
+ if (object) {
188
+ scene.remove(object);
189
+ }
190
+ }
191
+
192
+ function onKeyDown(event) {
193
+ switch (event.code) {
194
+ case 'KeyW': moveForward = true; break;
195
+ case 'KeyS': moveBackward = true; break;
196
+ case 'KeyA': moveLeft = true; break;
197
+ case 'KeyD': moveRight = true; break;
198
+ }
199
+ }
200
+
201
+ function onKeyUp(event) {
202
+ switch (event.code) {
203
+ case 'KeyW': moveForward = false; break;
204
+ case 'KeyS': moveBackward = false; break;
205
+ case 'KeyA': moveLeft = false; break;
206
+ case 'KeyD': moveRight = false; break;
207
+ }
208
+ }
209
+
210
+ function onMouseDown(event) {
211
+ if (!controls.isLocked) return;
212
+ if (event.button === 0 && selectedObjectType !== 'None') {
213
+ const raycaster = new THREE.Raycaster();
214
+ const mouse = new THREE.Vector2(0, 0);
215
+ raycaster.setFromCamera(mouse, camera);
216
+ const intersects = raycaster.intersectObjects(scene.children);
217
+ for (let intersect of intersects) {
218
+ if (intersect.object !== controls.getObject()) {
219
+ const position = intersect.point;
220
+ position.y += 0.5;
221
+ placeObject(position);
222
+ break;
223
+ }
224
+ }
225
+ } else if (event.button === 2) {
226
+ const raycaster = new THREE.Raycaster();
227
+ const mouse = new THREE.Vector2(0, 0);
228
+ raycaster.setFromCamera(mouse, camera);
229
+ const intersects = raycaster.intersectObjects(scene.children);
230
+ for (let intersect of intersects) {
231
+ if (intersect.object !== controls.getObject() && intersect.object.name) {
232
+ websocket.send(JSON.stringify({
233
+ type: 'delete_object',
234
+ payload: { obj_id: intersect.object.name, username }
235
+ }));
236
+ break;
237
+ }
238
+ }
239
+ }
240
+ }
241
+
242
+ function placeObject(position) {
243
+ if (selectedObjectType === 'None') return;
244
+ const obj_id = `obj_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
245
+ const objectData = {
246
+ obj_id: obj_id,
247
+ type: selectedObjectType,
248
+ position: { x: position.x, y: position.y, z: position.z },
249
+ rotation: { x: 0, y: 0, z: 0 }
250
+ };
251
+ websocket.send(JSON.stringify({
252
+ type: 'place_object',
253
+ payload: { username, object_data: objectData }
254
+ }));
255
+ }
256
+
257
+ function animate() {
258
+ requestAnimationFrame(animate);
259
+ const delta = 0.1;
260
+ const velocity = new THREE.Vector3();
261
+ if (moveForward) velocity.z -= 0.1;
262
+ if (moveBackward) velocity.z += 0.1;
263
+ if (moveLeft) velocity.x -= 0.1;
264
+ if (moveRight) velocity.x += 0.1;
265
+ controls.getObject().position.add(velocity);
266
+ const pos = controls.getObject().position;
267
+ const rot = controls.getObject().rotation;
268
+ websocket.send(JSON.stringify({
269
+ type: 'player_position',
270
+ payload: {
271
+ username,
272
+ position: { x: pos.x, y: pos.y, z: pos.z },
273
+ rotation: { x: rot.x, y: rot.y, z: rot.z }
274
+ }
275
+ }));
276
+ renderer.render(scene, camera);
277
+ }
278
+
279
+ init();
280
+ </script>
281
+ </body>
282
+ </html>