Tim13ekd commited on
Commit
af78ba8
·
verified ·
1 Parent(s): feb7fd2

mache es mit three js ein richtiges 3d game

Browse files
Files changed (2) hide show
  1. index.html +15 -9
  2. script.js +269 -81
index.html CHANGED
@@ -54,33 +54,39 @@
54
  </head>
55
  <body class="bg-gray-900">
56
  <canvas id="gameCanvas"></canvas>
57
-
58
  <div id="ui">
59
  <div id="title">
60
- <h1 class="text-xl font-bold">First Person Explorer 3D</h1>
61
- <p class="text-sm">Move with WASD | Look around with mouse</p>
62
  </div>
63
  <div id="controls">
64
  <div class="control-item">
65
  <span class="bg-gray-700 px-2 py-1 rounded mb-1">W</span>
66
- <span>Move Forward</span>
67
  </div>
68
  <div class="control-item">
69
  <span class="bg-gray-700 px-2 py-1 rounded mb-1">A</span>
70
- <span>Move Left</span>
71
  </div>
72
  <div class="control-item">
73
  <span class="bg-gray-700 px-2 py-1 rounded mb-1">S</span>
74
- <span>Move Back</span>
75
  </div>
76
  <div class="control-item">
77
  <span class="bg-gray-700 px-2 py-1 rounded mb-1">D</span>
78
- <span>Move Right</span>
 
 
 
 
 
 
 
 
79
  </div>
80
  </div>
81
  </div>
82
-
83
- <script src="script.js"></script>
84
  <script src="https://huggingface.co/deepsite/deepsite-badge.js"></script>
85
  </body>
86
  </html>
 
54
  </head>
55
  <body class="bg-gray-900">
56
  <canvas id="gameCanvas"></canvas>
 
57
  <div id="ui">
58
  <div id="title">
59
+ <h1 class="text-xl font-bold">3D Maze Adventure</h1>
60
+ <p class="text-sm">WASD: Move | SPACE: Jump | E: Interact | Click to play</p>
61
  </div>
62
  <div id="controls">
63
  <div class="control-item">
64
  <span class="bg-gray-700 px-2 py-1 rounded mb-1">W</span>
65
+ <span>Forward</span>
66
  </div>
67
  <div class="control-item">
68
  <span class="bg-gray-700 px-2 py-1 rounded mb-1">A</span>
69
+ <span>Left</span>
70
  </div>
71
  <div class="control-item">
72
  <span class="bg-gray-700 px-2 py-1 rounded mb-1">S</span>
73
+ <span>Back</span>
74
  </div>
75
  <div class="control-item">
76
  <span class="bg-gray-700 px-2 py-1 rounded mb-1">D</span>
77
+ <span>Right</span>
78
+ </div>
79
+ <div class="control-item">
80
+ <span class="bg-gray-700 px-2 py-1 rounded mb-1">SPACE</span>
81
+ <span>Jump</span>
82
+ </div>
83
+ <div class="control-item">
84
+ <span class="bg-gray-700 px-2 py-1 rounded mb-1">E</span>
85
+ <span>Interact</span>
86
  </div>
87
  </div>
88
  </div>
89
+ <script src="script.js"></script>
 
90
  <script src="https://huggingface.co/deepsite/deepsite-badge.js"></script>
91
  </body>
92
  </html>
script.js CHANGED
@@ -1,4 +1,5 @@
1
- // 3D First Person Movement with WASD and Mouse Look
 
2
  document.addEventListener('DOMContentLoaded', () => {
3
  const canvas = document.getElementById('gameCanvas');
4
  const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
@@ -14,27 +15,47 @@ document.addEventListener('DOMContentLoaded', () => {
14
 
15
  // Camera settings
16
  const camera = {
17
- position: [0, 1.6, 5], // x, y, z (y is height)
18
- rotation: [0, 0, 0], // pitch, yaw, roll
19
  fov: 75,
20
  near: 0.1,
21
  far: 1000,
22
- speed: 0.2
 
23
  };
24
 
25
- // Player movement state
 
 
 
 
 
 
 
 
26
  const movement = {
27
  forward: false,
28
  backward: false,
29
  left: false,
30
- right: false
 
 
 
 
31
  };
32
 
33
- // Mouse movement
 
 
 
 
 
 
34
  let isMouseLocked = false;
35
  let mouseSensitivity = 0.002;
36
-
37
- // Initialize scene
 
38
  const scene = new THREE.Scene();
39
  const renderer = new THREE.WebGLRenderer({ canvas, antialias: true });
40
  renderer.setSize(canvas.width, canvas.height);
@@ -48,37 +69,54 @@ document.addEventListener('DOMContentLoaded', () => {
48
  camera.far
49
  );
50
  threeCamera.position.set(...camera.position);
51
-
52
- // Basic lighting
53
- const ambientLight = new THREE.AmbientLight(0x404040);
54
  scene.add(ambientLight);
 
55
  const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
56
- directionalLight.position.set(1, 1, 1);
 
 
 
57
  scene.add(directionalLight);
58
 
59
- // Create a simple maze environment
 
 
 
 
 
 
60
  createEnvironment(scene);
61
 
62
  // Event listeners for keyboard
 
63
  window.addEventListener('keydown', (e) => {
64
  switch (e.key.toLowerCase()) {
65
  case 'w': movement.forward = true; break;
66
  case 's': movement.backward = true; break;
67
  case 'a': movement.left = true; break;
68
  case 'd': movement.right = true; break;
 
 
 
 
 
 
 
 
69
  }
70
  });
71
-
72
  window.addEventListener('keyup', (e) => {
73
  switch (e.key.toLowerCase()) {
74
  case 'w': movement.forward = false; break;
75
  case 's': movement.backward = false; break;
76
  case 'a': movement.left = false; break;
77
  case 'd': movement.right = false; break;
 
78
  }
79
  });
80
-
81
- // Mouse movement controls
82
  canvas.addEventListener('click', () => {
83
  canvas.requestPointerLock = canvas.requestPointerLock ||
84
  canvas.mozRequestPointerLock ||
@@ -111,12 +149,15 @@ document.addEventListener('DOMContentLoaded', () => {
111
  threeCamera.updateProjectionMatrix();
112
  renderer.setSize(canvas.width, canvas.height);
113
  });
114
-
115
- // Game loop
116
  function animate() {
 
 
117
  requestAnimationFrame(animate);
 
118
 
119
- // Movement logic
120
  const forwardVector = new THREE.Vector3(
121
  Math.sin(camera.rotation[1]),
122
  0,
@@ -128,20 +169,40 @@ document.addEventListener('DOMContentLoaded', () => {
128
  0,
129
  Math.cos(camera.rotation[1] + Math.PI/2)
130
  ).normalize();
 
 
 
131
 
132
- if (movement.forward) {
133
- threeCamera.position.addScaledVector(forwardVector, camera.speed);
134
- }
135
- if (movement.backward) {
136
- threeCamera.position.addScaledVector(forwardVector, -camera.speed);
137
- }
138
- if (movement.left) {
139
- threeCamera.position.addScaledVector(sideVector, -camera.speed);
 
 
 
 
140
  }
141
- if (movement.right) {
142
- threeCamera.position.addScaledVector(sideVector, camera.speed);
 
 
 
 
 
 
 
 
 
 
143
  }
144
 
 
 
 
145
  // Update camera rotation
146
  threeCamera.rotation.set(
147
  camera.rotation[0],
@@ -149,70 +210,197 @@ document.addEventListener('DOMContentLoaded', () => {
149
  0,
150
  'YXZ'
151
  );
152
-
153
- renderer.render(scene, threeCamera);
154
  }
155
 
156
  animate();
157
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158
 
159
- // Create a simple maze environment
160
- function createEnvironment(scene) {
161
- // Floor
162
- const floorGeometry = new THREE.PlaneGeometry(50, 50);
163
- const floorMaterial = new THREE.MeshStandardMaterial({
164
- color: 0x555555,
165
- roughness: 0.8,
166
- metalness: 0.2
167
- });
168
- const floor = new THREE.Mesh(floorGeometry, floorMaterial);
169
- floor.rotation.x = -Math.PI / 2;
170
- scene.add(floor);
171
-
172
- // Walls
173
- const wallMaterial = new THREE.MeshStandardMaterial({
174
- color: 0x888888,
175
- roughness: 0.7
176
- });
177
-
178
- // Add some simple walls to create a maze-like environment
179
- const walls = [
180
- { position: [0, 2.5, -8], size: [10, 5, 1] },
181
- { position: [0, 2.5, 8], size: [10, 5, 1] },
182
- { position: [-8, 2.5, 0], size: [1, 5, 10] },
183
- { position: [8, 2.5, 0], size: [1, 5, 10] },
184
- { position: [-5, 2.5, -5], size: [1, 5, 3] },
185
- { position: [5, 2.5, 5], size: [3, 5, 1] },
186
- // Add more walls as needed
187
- ];
188
-
189
- walls.forEach(wall => {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
190
  const wallGeometry = new THREE.BoxGeometry(...wall.size);
191
  const wallMesh = new THREE.Mesh(wallGeometry, wallMaterial);
192
  wallMesh.position.set(...wall.position);
193
  scene.add(wallMesh);
194
  });
195
-
196
- // Add some random decorative boxes
197
- for (let i = 0; i < 10; i++) {
198
- const boxSize = Math.random() * 1.5 + 0.5;
199
- const boxGeometry = new THREE.BoxGeometry(boxSize, boxSize, boxSize);
200
- const boxMaterial = new THREE.MeshStandardMaterial({
201
- color: Math.random() * 0xffffff,
202
- roughness: 0.5,
203
- metalness: 0.1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
204
  });
205
- const box = new THREE.Mesh(boxGeometry, boxMaterial);
206
- box.position.set(
207
- (Math.random() - 0.5) * 15,
208
- boxSize / 2,
209
- (Math.random() - 0.5) * 15
 
 
 
 
 
 
 
210
  );
211
- scene.add(box);
 
 
212
  }
213
- }
214
 
215
- // Include Three.js from CDN
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
216
  const threeScript = document.createElement('script');
217
  threeScript.src = 'https://cdn.jsdelivr.net/npm/three@0.132.2/build/three.min.js';
218
- document.head.appendChild(threeScript);
 
 
 
 
 
1
+
2
+ // 3D First Person Game with Physics and Interactions
3
  document.addEventListener('DOMContentLoaded', () => {
4
  const canvas = document.getElementById('gameCanvas');
5
  const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
 
15
 
16
  // Camera settings
17
  const camera = {
18
+ position: [0, 1.6, 5],
19
+ rotation: [0, 0, 0],
20
  fov: 75,
21
  near: 0.1,
22
  far: 1000,
23
+ speed: 0.2,
24
+ height: 1.6
25
  };
26
 
27
+ // Game state
28
+ const game = {
29
+ score: 0,
30
+ collectedItems: 0,
31
+ maxItems: 10,
32
+ isRunning: true,
33
+ startTime: Date.now()
34
+ };
35
+ // Player movement state
36
  const movement = {
37
  forward: false,
38
  backward: false,
39
  left: false,
40
+ right: false,
41
+ jump: false,
42
+ isGrounded: false,
43
+ velocityY: 0,
44
+ gravity: -0.005
45
  };
46
 
47
+ // Physics settings
48
+ const physics = {
49
+ friction: 0.98,
50
+ maxSpeed: 0.3,
51
+ jumpForce: 0.15
52
+ };
53
+ // Game controls
54
  let isMouseLocked = false;
55
  let mouseSensitivity = 0.002;
56
+ const raycaster = new THREE.Raycaster();
57
+ const pointer = new THREE.Vector2();
58
+ // Initialize scene
59
  const scene = new THREE.Scene();
60
  const renderer = new THREE.WebGLRenderer({ canvas, antialias: true });
61
  renderer.setSize(canvas.width, canvas.height);
 
69
  camera.far
70
  );
71
  threeCamera.position.set(...camera.position);
72
+ // Enhanced lighting
73
+ const ambientLight = new THREE.AmbientLight(0x404040, 0.5);
 
74
  scene.add(ambientLight);
75
+
76
  const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
77
+ directionalLight.position.set(1, 5, 1);
78
+ directionalLight.castShadow = true;
79
+ directionalLight.shadow.mapSize.width = 2048;
80
+ directionalLight.shadow.mapSize.height = 2048;
81
  scene.add(directionalLight);
82
 
83
+ // Hemisphere light for natural outdoor lighting
84
+ const hemiLight = new THREE.HemisphereLight(0xffffbb, 0x080820, 0.5);
85
+ scene.add(hemiLight);
86
+
87
+ // Fog for depth
88
+ scene.fog = new THREE.FogExp2(0x222222, 0.02);
89
+ // Create a simple maze environment
90
  createEnvironment(scene);
91
 
92
  // Event listeners for keyboard
93
+ // Enhanced controls with jump
94
  window.addEventListener('keydown', (e) => {
95
  switch (e.key.toLowerCase()) {
96
  case 'w': movement.forward = true; break;
97
  case 's': movement.backward = true; break;
98
  case 'a': movement.left = true; break;
99
  case 'd': movement.right = true; break;
100
+ case ' ':
101
+ if (movement.isGrounded) {
102
+ movement.jump = true;
103
+ movement.isGrounded = false;
104
+ movement.velocityY = physics.jumpForce;
105
+ }
106
+ break;
107
+ case 'e': checkInteraction(); break;
108
  }
109
  });
 
110
  window.addEventListener('keyup', (e) => {
111
  switch (e.key.toLowerCase()) {
112
  case 'w': movement.forward = false; break;
113
  case 's': movement.backward = false; break;
114
  case 'a': movement.left = false; break;
115
  case 'd': movement.right = false; break;
116
+ case ' ': movement.jump = false; break;
117
  }
118
  });
119
+ // Mouse movement controls
 
120
  canvas.addEventListener('click', () => {
121
  canvas.requestPointerLock = canvas.requestPointerLock ||
122
  canvas.mozRequestPointerLock ||
 
149
  threeCamera.updateProjectionMatrix();
150
  renderer.setSize(canvas.width, canvas.height);
151
  });
152
+ // Enhanced game loop with physics
153
+ const clock = new THREE.Clock();
154
  function animate() {
155
+ if (!game.isRunning) return;
156
+
157
  requestAnimationFrame(animate);
158
+ const delta = clock.getDelta();
159
 
160
+ // Movement vectors
161
  const forwardVector = new THREE.Vector3(
162
  Math.sin(camera.rotation[1]),
163
  0,
 
169
  0,
170
  Math.cos(camera.rotation[1] + Math.PI/2)
171
  ).normalize();
172
+
173
+ // Apply forces
174
+ const velocity = new THREE.Vector3();
175
 
176
+ if (movement.forward) velocity.add(forwardVector);
177
+ if (movement.backward) velocity.sub(forwardVector);
178
+ if (movement.left) velocity.sub(sideVector);
179
+ if (movement.right) velocity.add(sideVector);
180
+
181
+ // Apply physics
182
+ velocity.multiplyScalar(camera.speed);
183
+ velocity.y = movement.velocityY;
184
+
185
+ // Limit speed
186
+ if (velocity.length() > physics.maxSpeed) {
187
+ velocity.normalize().multiplyScalar(physics.maxSpeed);
188
  }
189
+
190
+ // Apply friction
191
+ velocity.multiplyScalar(physics.friction);
192
+
193
+ // Update position
194
+ threeCamera.position.add(velocity);
195
+
196
+ // Gravity
197
+ if (!movement.isGrounded) {
198
+ movement.velocityY += movement.gravity;
199
+ } else {
200
+ movement.velocityY = 0;
201
  }
202
 
203
+ // Ground check
204
+ checkGroundCollision();
205
+
206
  // Update camera rotation
207
  threeCamera.rotation.set(
208
  camera.rotation[0],
 
210
  0,
211
  'YXZ'
212
  );
213
+ renderer.render(scene, threeCamera);
 
214
  }
215
 
216
  animate();
217
  });
218
+ // Create game environment with collectibles and obstacles
219
+ function createEnvironment(scene) {
220
+ const tileSize = 5;
221
+ const gridSize = 11;
222
+ const wallHeight = 3;
223
+
224
+ // Floor with texture
225
+ const floorGeometry = new THREE.PlaneGeometry(tileSize * gridSize, tileSize * gridSize);
226
+ const floorTexture = new THREE.TextureLoader().load('https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/textures/terrain/grasslight-big.jpg');
227
+ floorTexture.wrapS = floorTexture.wrapT = THREE.RepeatWrapping;
228
+ floorTexture.repeat.set(gridSize, gridSize);
229
+ const floorMaterial = new THREE.MeshStandardMaterial({
230
+ map: floorTexture,
231
+ roughness: 0.9,
232
+ metalness: 0
233
+ });
234
+ const floor = new THREE.Mesh(floorGeometry, floorMaterial);
235
+ floor.rotation.x = -Math.PI / 2;
236
+ floor.receiveShadow = true;
237
+ scene.add(floor);
238
 
239
+ // Walls with better materials
240
+ const wallMaterial = new THREE.MeshStandardMaterial({
241
+ color: 0xcccccc,
242
+ roughness: 0.7,
243
+ metalness: 0.1
244
+ });
245
+
246
+ // Create maze grid
247
+ const mazeGrid = Array(gridSize).fill().map(() => Array(gridSize).fill(0));
248
+
249
+ // Basic maze structure
250
+ for (let x = 0; x < gridSize; x++) {
251
+ for (let z = 0; z < gridSize; z++) {
252
+ // Border walls
253
+ if (x === 0 || x === gridSize-1 || z === 0 || z === gridSize-1) {
254
+ mazeGrid[x][z] = 1;
255
+ }
256
+ // Inner pattern
257
+ else if (Math.random() > 0.7 && !(x === 1 && z === 1)) {
258
+ mazeGrid[x][z] = 1;
259
+ }
260
+ }
261
+ }
262
+
263
+ // Ensure there's always a path
264
+ mazeGrid[1][1] = 0; // Start position
265
+ mazeGrid[gridSize-2][gridSize-2] = 0; // Exit position
266
+ // Build maze from grid
267
+ for (let x = 0; x < gridSize; x++) {
268
+ for (let z = 0; z < gridSize; z++) {
269
+ if (mazeGrid[x][z]) {
270
+ const wallX = (x - (gridSize-1)/2) * tileSize;
271
+ const wallZ = (z - (gridSize-1)/2) * tileSize;
272
+
273
+ const wallGeometry = new THREE.BoxGeometry(
274
+ tileSize, wallHeight, tileSize
275
+ );
276
+ const wallMesh = new THREE.Mesh(wallGeometry, wallMaterial);
277
+ wallMesh.position.set(wallX, wallHeight/2, wallZ);
278
+ wallMesh.castShadow = true;
279
+ wallMesh.receiveShadow = true;
280
+ scene.add(wallMesh);
281
+ }
282
+ }
283
+ }
284
+ walls.forEach(wall => {
285
  const wallGeometry = new THREE.BoxGeometry(...wall.size);
286
  const wallMesh = new THREE.Mesh(wallGeometry, wallMaterial);
287
  wallMesh.position.set(...wall.position);
288
  scene.add(wallMesh);
289
  });
290
+ // Create collectible items
291
+ for (let i = 0; i < game.maxItems; i++) {
292
+ let x, z;
293
+ do {
294
+ x = Math.floor(Math.random() * gridSize);
295
+ z = Math.floor(Math.random() * gridSize);
296
+ } while (mazeGrid[x][z] || (x === 1 && z === 1));
297
+
298
+ const itemX = (x - (gridSize-1)/2) * tileSize;
299
+ const itemZ = (z - (gridSize-1)/2) * tileSize;
300
+
301
+ const itemGeometry = new THREE.SphereGeometry(0.5, 16, 16);
302
+ const itemMaterial = new THREE.MeshStandardMaterial({
303
+ color: 0x00ff00,
304
+ emissive: 0x00ff00,
305
+ emissiveIntensity: 0.5,
306
+ metalness: 0.3,
307
+ roughness: 0.4
308
+ });
309
+ const item = new THREE.Mesh(itemGeometry, itemMaterial);
310
+ item.position.set(itemX, 1, itemZ);
311
+ item.userData.isCollectible = true;
312
+ item.castShadow = true;
313
+ scene.add(item);
314
+ }
315
+
316
+ // Create exit door
317
+ const exitX = ((gridSize-2) - (gridSize-1)/2) * tileSize;
318
+ const exitZ = ((gridSize-2) - (gridSize-1)/2) * tileSize;
319
+
320
+ const exitGeometry = new THREE.BoxGeometry(tileSize/2, wallHeight/2, tileSize/2);
321
+ const exitMaterial = new THREE.MeshStandardMaterial({
322
+ color: 0xff0000,
323
+ emissive: 0xff0000,
324
+ emissiveIntensity: 0.3
325
  });
326
+ const exit = new THREE.Mesh(exitGeometry, exitMaterial);
327
+ exit.position.set(exitX, wallHeight/4, exitZ);
328
+ exit.userData.isExit = true;
329
+ scene.add(exit);
330
+ }
331
+ // Collision detection
332
+ function checkGroundCollision() {
333
+ const groundRay = new THREE.Raycaster(
334
+ threeCamera.position,
335
+ new THREE.Vector3(0, -1, 0),
336
+ 0,
337
+ camera.height * 1.1
338
  );
339
+
340
+ const intersects = groundRay.intersectObjects(scene.children.filter(obj => obj !== floor));
341
+ movement.isGrounded = intersects.length > 0;
342
  }
 
343
 
344
+ // Interaction system
345
+ function checkInteraction() {
346
+ raycaster.setFromCamera(pointer, threeCamera);
347
+ const intersects = raycaster.intersectObjects(scene.children);
348
+
349
+ if (intersects.length > 0) {
350
+ const obj = intersects[0].object;
351
+
352
+ if (obj.userData.isCollectible) {
353
+ // Collect item
354
+ scene.remove(obj);
355
+ game.collectedItems++;
356
+ game.score += 100;
357
+ updateUI();
358
+
359
+ if (game.collectedItems === game.maxItems) {
360
+ document.getElementById('hint').textContent = "Find the red exit!";
361
+ }
362
+ } else if (obj.userData.isExit && game.collectedItems === game.maxItems) {
363
+ // Game completed
364
+ game.isRunning = false;
365
+ const timeElapsed = Math.floor((Date.now() - game.startTime) / 1000);
366
+ document.getElementById('title').innerHTML = `
367
+ <h1 class="text-xl font-bold">Game Completed!</h1>
368
+ <p>Score: ${game.score + timeElapsed * 10}</p>
369
+ <p>Time: ${timeElapsed}s</p>
370
+ `;
371
+ }
372
+ }
373
+ }
374
+
375
+ // UI update
376
+ function updateUI() {
377
+ document.getElementById('score').textContent = `Score: ${game.score}`;
378
+ document.getElementById('items').textContent = `Items: ${game.collectedItems}/${game.maxItems}`;
379
+ }
380
+
381
+ // Initialize UI elements
382
+ const ui = document.getElementById('ui');
383
+ const gameInfo = document.createElement('div');
384
+ gameInfo.id = 'game-info';
385
+ gameInfo.style.position = 'absolute';
386
+ gameInfo.style.top = '20px';
387
+ gameInfo.style.right = '20px';
388
+ gameInfo.style.backgroundColor = 'rgba(0,0,0,0.5)';
389
+ gameInfo.style.padding = '10px';
390
+ gameInfo.style.borderRadius = '5px';
391
+ gameInfo.style.color = 'white';
392
+ gameInfo.innerHTML = `
393
+ <div id="score">Score: 0</div>
394
+ <div id="items">Items: 0/${game.maxItems}</div>
395
+ <div id="hint">Collect all green spheres!</div>
396
+ `;
397
+ ui.appendChild(gameInfo);
398
+
399
+ // Include Three.js and PointerLockControls from CDN
400
  const threeScript = document.createElement('script');
401
  threeScript.src = 'https://cdn.jsdelivr.net/npm/three@0.132.2/build/three.min.js';
402
+ document.head.appendChild(threeScript);
403
+
404
+ const pointerLockScript = document.createElement('script');
405
+ pointerLockScript.src = 'https://cdn.jsdelivr.net/npm/three@0.132.2/examples/js/controls/PointerLockControls.js';
406
+ document.head.appendChild(pointerLockScript);