KBLLR commited on
Commit
cc04566
·
verified ·
1 Parent(s): bda8d6c

can you add camera options and reduce the size of my character?

Browse files
Files changed (1) hide show
  1. index.html +95 -24
index.html CHANGED
@@ -188,7 +188,7 @@
188
  </div>
189
  </div>
190
  </div>
191
- <!-- Game UI -->
192
  <div id="game-ui" class="fixed inset-0 pointer-events-none z-20 opacity-0 transition-all">
193
  <div class="absolute bottom-4 left-4 bg-gray-800 bg-opacity-70 p-4 rounded-lg">
194
  <div class="flex items-center space-x-2">
@@ -207,10 +207,16 @@
207
  <div class="w-3 h-3 rounded-full bg-yellow-500"></div>
208
  <span>Near NPC: Talk (Space)</span>
209
  </div>
 
 
 
 
 
 
 
210
  </div>
211
  </div>
212
-
213
- <!-- Dialog Box -->
214
  <div id="dialog-box" class="fixed bottom-0 left-0 right-0 bg-gray-900 bg-opacity-90 p-6 rounded-t-2xl transform translate-y-full transition-all duration-300 z-50 max-w-4xl mx-auto">
215
  <div class="flex items-start space-x-4">
216
  <div id="dialog-character" class="w-16 h-16 rounded-full bg-gray-700 flex-shrink-0"></div>
@@ -242,6 +248,7 @@
242
  nearbyNpc: null,
243
  isRunning: false,
244
  isJumping: false,
 
245
  keys: {
246
  w: false,
247
  a: false,
@@ -251,7 +258,7 @@
251
  space: false
252
  }
253
  };
254
- // Sample character data with free models from Three.js examples
255
  const characterData = [
256
  { id: 1, name: "Robot", modelUrl: "https://threejs.org/examples/models/gltf/RobotExpressive/RobotExpressive.glb", color: "#EF4444", dialog: ["Beep boop! I am a robot.", "Processing your request...", "01010100 01101000 01110010 01100101 01100101"] },
257
  { id: 2, name: "Fox", modelUrl: "https://threejs.org/examples/models/gltf/Fox/Fox.glb", color: "#3B82F6", dialog: ["What does the fox say?", "The forest is my home.", "Sly as a fox!"] },
@@ -274,12 +281,17 @@
274
  document.getElementById('confirm-character').addEventListener('click', showWorldSelection);
275
  document.getElementById('start-world').addEventListener('click', startGame);
276
  document.getElementById('close-dialog').addEventListener('click', closeDialog);
277
-
278
  // Keyboard event listeners
279
  window.addEventListener('keydown', handleKeyDown);
280
  window.addEventListener('keyup', handleKeyUp);
281
 
282
- // Populate character selection
 
 
 
 
 
 
283
  populateCharacterSelection();
284
  });
285
 
@@ -450,11 +462,15 @@
450
 
451
  // Add some environment objects
452
  addEnvironmentObjects();
453
-
 
 
 
 
 
454
  // Load player character
455
  loadPlayerCharacter();
456
-
457
- // Load NPC characters
458
  loadNPCCharacters();
459
 
460
  // Start animation loop
@@ -504,12 +520,10 @@ function addEnvironmentObjects() {
504
  function loadPlayerCharacter() {
505
  loader.load(gameState.selectedCharacter.modelUrl, (gltf) => {
506
  const model = gltf.scene;
507
-
508
- // Scale and position the model
509
- model.scale.set(1, 1, 1);
510
  model.position.set(0, 0, 0);
511
-
512
- // Enable shadows for all children
513
  model.traverse((child) => {
514
  if (child.isMesh) {
515
  child.castShadow = true;
@@ -606,7 +620,6 @@ function addEnvironmentObjects() {
606
  rightLeg.position.set(0.2, -0.4, 0);
607
  rightLeg.castShadow = true;
608
  group.add(rightLeg);
609
-
610
  group.position.y = 0;
611
  scene.add(group);
612
 
@@ -624,8 +637,7 @@ function addEnvironmentObjects() {
624
  },
625
  currentAnimation: null
626
  };
627
-
628
- // Add a simple animation mixer for the player
629
  mixer = new THREE.AnimationMixer(group);
630
  createPlayerAnimations();
631
  setPlayerAnimation('idle');
@@ -727,6 +739,8 @@ function loadNPCCharacters() {
727
  head.position.y = 1.6;
728
  head.castShadow = true;
729
  group.add(head);
 
 
730
 
731
  // Position NPCs in a circle around the center
732
  const angle = (index / gameState.selectedWorldCharacters.length) * Math.PI * 2;
@@ -738,8 +752,7 @@ function loadNPCCharacters() {
738
 
739
  // Make NPC face center
740
  group.lookAt(0, 0, 0);
741
-
742
- scene.add(group);
743
 
744
  gameState.npcs.push({
745
  model: group,
@@ -765,6 +778,14 @@ function loadNPCCharacters() {
765
  // Check for nearby NPCs
766
  checkForNearbyNPCs();
767
 
 
 
 
 
 
 
 
 
768
  renderer.render(scene, camera);
769
  }
770
  function handlePlayerMovement(delta) {
@@ -872,11 +893,58 @@ function handlePlayerMovement(delta) {
872
  player.isMoving = moving;
873
  updatePlayerAnimation();
874
  }
 
 
 
 
 
 
 
 
875
 
876
- // Update camera position to follow player with smooth interpolation
877
- const targetCameraPosition = player.model.position.clone().add(new THREE.Vector3(0, 5, 10));
878
- camera.position.lerp(targetCameraPosition, 0.1 * delta * 60);
879
- camera.lookAt(player.model.position);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
880
  }
881
  function updatePlayerAnimation() {
882
  if (gameState.isJumping) return;
@@ -989,7 +1057,10 @@ function showDialog(npc) {
989
  showDialog(gameState.nearbyNpc);
990
  }
991
  break;
992
- }
 
 
 
993
  }
994
  function handleKeyUp(event) {
995
  // Ignore key repeats
 
188
  </div>
189
  </div>
190
  </div>
191
+ <!-- Game UI -->
192
  <div id="game-ui" class="fixed inset-0 pointer-events-none z-20 opacity-0 transition-all">
193
  <div class="absolute bottom-4 left-4 bg-gray-800 bg-opacity-70 p-4 rounded-lg">
194
  <div class="flex items-center space-x-2">
 
207
  <div class="w-3 h-3 rounded-full bg-yellow-500"></div>
208
  <span>Near NPC: Talk (Space)</span>
209
  </div>
210
+ <div class="flex items-center space-x-2">
211
+ <div class="w-3 h-3 rounded-full bg-red-500"></div>
212
+ <span>C: Camera Mode</span>
213
+ </div>
214
+ </div>
215
+ <div class="absolute top-4 right-4 bg-gray-800 bg-opacity-70 p-4 rounded-lg">
216
+ <div class="text-white font-semibold">Camera: <span id="camera-mode-display">Follow</span></div>
217
  </div>
218
  </div>
219
+ <!-- Dialog Box -->
 
220
  <div id="dialog-box" class="fixed bottom-0 left-0 right-0 bg-gray-900 bg-opacity-90 p-6 rounded-t-2xl transform translate-y-full transition-all duration-300 z-50 max-w-4xl mx-auto">
221
  <div class="flex items-start space-x-4">
222
  <div id="dialog-character" class="w-16 h-16 rounded-full bg-gray-700 flex-shrink-0"></div>
 
248
  nearbyNpc: null,
249
  isRunning: false,
250
  isJumping: false,
251
+ cameraMode: 'follow', // 'follow', 'orbit', 'first-person'
252
  keys: {
253
  w: false,
254
  a: false,
 
258
  space: false
259
  }
260
  };
261
+ // Sample character data with free models from Three.js examples
262
  const characterData = [
263
  { id: 1, name: "Robot", modelUrl: "https://threejs.org/examples/models/gltf/RobotExpressive/RobotExpressive.glb", color: "#EF4444", dialog: ["Beep boop! I am a robot.", "Processing your request...", "01010100 01101000 01110010 01100101 01100101"] },
264
  { id: 2, name: "Fox", modelUrl: "https://threejs.org/examples/models/gltf/Fox/Fox.glb", color: "#3B82F6", dialog: ["What does the fox say?", "The forest is my home.", "Sly as a fox!"] },
 
281
  document.getElementById('confirm-character').addEventListener('click', showWorldSelection);
282
  document.getElementById('start-world').addEventListener('click', startGame);
283
  document.getElementById('close-dialog').addEventListener('click', closeDialog);
 
284
  // Keyboard event listeners
285
  window.addEventListener('keydown', handleKeyDown);
286
  window.addEventListener('keyup', handleKeyUp);
287
 
288
+ // Camera controls listener
289
+ window.addEventListener('keydown', (event) => {
290
+ if (event.key.toLowerCase() === 'c') {
291
+ cycleCameraMode();
292
+ }
293
+ });
294
+ // Populate character selection
295
  populateCharacterSelection();
296
  });
297
 
 
462
 
463
  // Add some environment objects
464
  addEnvironmentObjects();
465
+ // Initialize OrbitControls
466
+ controls = new THREE.OrbitControls(camera, renderer.domElement);
467
+ controls.enableDamping = true;
468
+ controls.dampingFactor = 0.05;
469
+ controls.enabled = false; // Start with controls disabled for follow camera
470
+
471
  // Load player character
472
  loadPlayerCharacter();
473
+ // Load NPC characters
 
474
  loadNPCCharacters();
475
 
476
  // Start animation loop
 
520
  function loadPlayerCharacter() {
521
  loader.load(gameState.selectedCharacter.modelUrl, (gltf) => {
522
  const model = gltf.scene;
523
+ // Scale and position the model - reduced size
524
+ model.scale.set(0.6, 0.6, 0.6);
 
525
  model.position.set(0, 0, 0);
526
+ // Enable shadows for all children
 
527
  model.traverse((child) => {
528
  if (child.isMesh) {
529
  child.castShadow = true;
 
620
  rightLeg.position.set(0.2, -0.4, 0);
621
  rightLeg.castShadow = true;
622
  group.add(rightLeg);
 
623
  group.position.y = 0;
624
  scene.add(group);
625
 
 
637
  },
638
  currentAnimation: null
639
  };
640
+ // Add a simple animation mixer for the player
 
641
  mixer = new THREE.AnimationMixer(group);
642
  createPlayerAnimations();
643
  setPlayerAnimation('idle');
 
739
  head.position.y = 1.6;
740
  head.castShadow = true;
741
  group.add(head);
742
+ // Scale down NPCs to match player size
743
+ group.scale.set(0.6, 0.6, 0.6);
744
 
745
  // Position NPCs in a circle around the center
746
  const angle = (index / gameState.selectedWorldCharacters.length) * Math.PI * 2;
 
752
 
753
  // Make NPC face center
754
  group.lookAt(0, 0, 0);
755
+ scene.add(group);
 
756
 
757
  gameState.npcs.push({
758
  model: group,
 
778
  // Check for nearby NPCs
779
  checkForNearbyNPCs();
780
 
781
+ // Update camera based on mode
782
+ updateCamera(delta);
783
+
784
+ // Update OrbitControls if enabled
785
+ if (controls.enabled) {
786
+ controls.update();
787
+ }
788
+
789
  renderer.render(scene, camera);
790
  }
791
  function handlePlayerMovement(delta) {
 
893
  player.isMoving = moving;
894
  updatePlayerAnimation();
895
  }
896
+ // Update camera position based on camera mode
897
+ updateCamera(delta);
898
+ }
899
+
900
+ function updateCamera(delta) {
901
+ if (!gameState.player) return;
902
+
903
+ const player = gameState.player;
904
 
905
+ switch (gameState.cameraMode) {
906
+ case 'follow':
907
+ // Follow camera - smooth follow behind player
908
+ const targetCameraPosition = player.model.position.clone().add(new THREE.Vector3(0, 3, 8));
909
+ camera.position.lerp(targetCameraPosition, 0.1 * delta * 60);
910
+ camera.lookAt(player.model.position);
911
+ break;
912
+
913
+ case 'orbit':
914
+ // Orbit camera - let OrbitControls handle positioning
915
+ // Set the target to player position
916
+ controls.target.copy(player.model.position);
917
+ break;
918
+
919
+ case 'first-person':
920
+ // First-person camera - attach to player's head
921
+ const headPosition = player.model.position.clone();
922
+ headPosition.y += 1.2; // Eye level
923
+ camera.position.copy(headPosition);
924
+
925
+ // Make camera face same direction as player
926
+ camera.rotation.y = player.model.rotation.y;
927
+ break;
928
+ }
929
+ }
930
+
931
+ function cycleCameraMode() {
932
+ const modes = ['follow', 'orbit', 'first-person'];
933
+ const currentIndex = modes.indexOf(gameState.cameraMode);
934
+ const nextIndex = (currentIndex + 1) % modes.length;
935
+ gameState.cameraMode = modes[nextIndex];
936
+
937
+ // Update UI display
938
+ document.getElementById('camera-mode-display').textContent =
939
+ gameState.cameraMode.charAt(0).toUpperCase() + gameState.cameraMode.slice(1);
940
+
941
+ // Enable/disable OrbitControls based on mode
942
+ controls.enabled = (gameState.cameraMode === 'orbit');
943
+
944
+ // Reset camera position for first-person mode
945
+ if (gameState.cameraMode === 'first-person') {
946
+ camera.rotation.set(0, 0, 0);
947
+ }
948
  }
949
  function updatePlayerAnimation() {
950
  if (gameState.isJumping) return;
 
1057
  showDialog(gameState.nearbyNpc);
1058
  }
1059
  break;
1060
+ case 'c':
1061
+ // Camera mode switching is handled separately
1062
+ break;
1063
+ }
1064
  }
1065
  function handleKeyUp(event) {
1066
  // Ignore key repeats