Spaces:
Running
Running
(index):64 cdn.tailwindcss.com should not be used in production. To use Tailwind CSS in production, install it as a PostCSS plugin or use the Tailwind CLI: https://tailwindcss.com/docs/installation
Browse files(anonymous) @ (index):64Understand this warning
OrbitControls.js:1 Uncaught SyntaxError: Cannot use import statement outside a moduleUnderstand this error
GLTFLoader.js:1 Uncaught SyntaxError: Cannot use import statement outside a moduleUnderstand this error
about:srcdoc:566 Uncaught ReferenceError: THREE is not defined
at initThreeJS (about:srcdoc:566:13)
at HTMLButtonElement.startGame (about:srcdoc:478:13)Understand this error
about:srcdoc:1108 Uncaught TypeError: Cannot set properties of undefined (setting 'enabled')
at cycleCameraMode (about:srcdoc:1108:30)
at about:srcdoc:359:21
- index.html +123 -96
index.html
CHANGED
|
@@ -5,9 +5,9 @@
|
|
| 5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
<title>3D Character World</title>
|
| 7 |
<script src="https://cdn.tailwindcss.com"></script>
|
| 8 |
-
<script src="https://cdn.jsdelivr.net/npm/three@0.
|
| 9 |
-
<script src="https://cdn.jsdelivr.net/npm/three@0.
|
| 10 |
-
<script src="https://cdn.jsdelivr.net/npm/three@0.
|
| 11 |
<style>
|
| 12 |
body {
|
| 13 |
margin: 0;
|
|
@@ -342,9 +342,8 @@
|
|
| 342 |
let scene, camera, renderer, controls;
|
| 343 |
let mixer, clock, loader;
|
| 344 |
let world;
|
| 345 |
-
|
| 346 |
// Initialize the app
|
| 347 |
-
document.addEventListener('DOMContentLoaded', () => {
|
| 348 |
// Set up UI event listeners
|
| 349 |
document.getElementById('start-btn').addEventListener('click', showCharacterSelection);
|
| 350 |
document.getElementById('confirm-character').addEventListener('click', showWorldSelection);
|
|
@@ -370,9 +369,14 @@
|
|
| 370 |
|
| 371 |
// Initialize audio context on user interaction
|
| 372 |
document.addEventListener('click', initializeAudio, { once: true });
|
| 373 |
-
});
|
| 374 |
|
| 375 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 376 |
if (audioContext) return;
|
| 377 |
|
| 378 |
try {
|
|
@@ -562,93 +566,117 @@ card.addEventListener('click', () => {
|
|
| 562 |
});
|
| 563 |
}
|
| 564 |
function initThreeJS() {
|
| 565 |
-
|
| 566 |
-
|
| 567 |
-
|
| 568 |
-
|
| 569 |
-
// Camera
|
| 570 |
-
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
|
| 571 |
-
camera.position.set(0, 5, 10);
|
| 572 |
-
|
| 573 |
-
// Renderer
|
| 574 |
-
const canvas = document.getElementById('canvas');
|
| 575 |
-
renderer = new THREE.WebGLRenderer({
|
| 576 |
-
canvas: canvas,
|
| 577 |
-
antialias: true,
|
| 578 |
-
alpha: true
|
| 579 |
-
});
|
| 580 |
-
renderer.setSize(window.innerWidth, window.innerHeight);
|
| 581 |
-
renderer.shadowMap.enabled = true;
|
| 582 |
-
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
|
| 583 |
-
|
| 584 |
-
// Clock for animations
|
| 585 |
-
clock = new THREE.Clock();
|
| 586 |
|
| 587 |
-
|
| 588 |
-
|
| 589 |
-
|
| 590 |
-
|
| 591 |
-
|
| 592 |
-
|
| 593 |
-
|
| 594 |
-
|
| 595 |
-
|
| 596 |
-
|
| 597 |
-
|
| 598 |
-
|
| 599 |
-
|
| 600 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 601 |
|
| 602 |
-
|
| 603 |
-
|
| 604 |
-
|
| 605 |
|
| 606 |
-
|
| 607 |
-
|
| 608 |
-
|
| 609 |
-
|
| 610 |
-
|
| 611 |
-
|
| 612 |
-
|
| 613 |
-
|
| 614 |
-
|
| 615 |
-
|
| 616 |
-
|
| 617 |
-
|
| 618 |
-
// Create ground
|
| 619 |
-
|
| 620 |
-
|
| 621 |
-
|
| 622 |
-
|
| 623 |
-
|
| 624 |
-
|
| 625 |
-
|
| 626 |
-
|
| 627 |
-
|
| 628 |
-
|
| 629 |
-
|
| 630 |
-
|
| 631 |
-
|
| 632 |
-
|
| 633 |
-
|
| 634 |
-
|
| 635 |
-
|
| 636 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 637 |
|
| 638 |
-
|
| 639 |
-
|
| 640 |
-
|
| 641 |
-
|
| 642 |
-
|
| 643 |
-
|
| 644 |
-
|
| 645 |
-
|
| 646 |
-
|
| 647 |
-
|
| 648 |
-
|
| 649 |
-
|
| 650 |
-
|
| 651 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 652 |
}
|
| 653 |
function addEnvironmentObjects() {
|
| 654 |
// Add some trees
|
|
@@ -946,13 +974,11 @@ scene.add(group);
|
|
| 946 |
|
| 947 |
// Update camera based on mode
|
| 948 |
updateCamera(delta);
|
| 949 |
-
|
| 950 |
// Update OrbitControls if enabled
|
| 951 |
-
if (controls.enabled) {
|
| 952 |
controls.update();
|
| 953 |
}
|
| 954 |
-
|
| 955 |
-
renderer.render(scene, camera);
|
| 956 |
}
|
| 957 |
function handlePlayerMovement(delta) {
|
| 958 |
if (!gameState.player) return;
|
|
@@ -1093,7 +1119,6 @@ function handlePlayerMovement(delta) {
|
|
| 1093 |
break;
|
| 1094 |
}
|
| 1095 |
}
|
| 1096 |
-
|
| 1097 |
function cycleCameraMode() {
|
| 1098 |
const modes = ['follow', 'orbit', 'first-person'];
|
| 1099 |
const currentIndex = modes.indexOf(gameState.cameraMode);
|
|
@@ -1105,7 +1130,9 @@ function handlePlayerMovement(delta) {
|
|
| 1105 |
gameState.cameraMode.charAt(0).toUpperCase() + gameState.cameraMode.slice(1);
|
| 1106 |
|
| 1107 |
// Enable/disable OrbitControls based on mode
|
| 1108 |
-
controls
|
|
|
|
|
|
|
| 1109 |
|
| 1110 |
// Reset camera position for first-person mode
|
| 1111 |
if (gameState.cameraMode === 'first-person') {
|
|
|
|
| 5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
<title>3D Character World</title>
|
| 7 |
<script src="https://cdn.tailwindcss.com"></script>
|
| 8 |
+
<script src="https://cdn.jsdelivr.net/npm/three@0.167.0/build/three.min.js"></script>
|
| 9 |
+
<script src="https://cdn.jsdelivr.net/npm/three@0.167.0/examples/jsm/controls/OrbitControls.js"></script>
|
| 10 |
+
<script src="https://cdn.jsdelivr.net/npm/three@0.167.0/examples/jsm/loaders/GLTFLoader.js"></script>
|
| 11 |
<style>
|
| 12 |
body {
|
| 13 |
margin: 0;
|
|
|
|
| 342 |
let scene, camera, renderer, controls;
|
| 343 |
let mixer, clock, loader;
|
| 344 |
let world;
|
|
|
|
| 345 |
// Initialize the app
|
| 346 |
+
document.addEventListener('DOMContentLoaded', async () => {
|
| 347 |
// Set up UI event listeners
|
| 348 |
document.getElementById('start-btn').addEventListener('click', showCharacterSelection);
|
| 349 |
document.getElementById('confirm-character').addEventListener('click', showWorldSelection);
|
|
|
|
| 369 |
|
| 370 |
// Initialize audio context on user interaction
|
| 371 |
document.addEventListener('click', initializeAudio, { once: true });
|
|
|
|
| 372 |
|
| 373 |
+
// Ensure Three.js is loaded before initialization
|
| 374 |
+
if (typeof THREE === 'undefined') {
|
| 375 |
+
console.error('Three.js not loaded');
|
| 376 |
+
return;
|
| 377 |
+
}
|
| 378 |
+
});
|
| 379 |
+
function initializeAudio() {
|
| 380 |
if (audioContext) return;
|
| 381 |
|
| 382 |
try {
|
|
|
|
| 566 |
});
|
| 567 |
}
|
| 568 |
function initThreeJS() {
|
| 569 |
+
if (typeof THREE === 'undefined') {
|
| 570 |
+
console.error('Three.js is not loaded properly');
|
| 571 |
+
return;
|
| 572 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 573 |
|
| 574 |
+
try {
|
| 575 |
+
// Set up Three.js scene
|
| 576 |
+
scene = new THREE.Scene();
|
| 577 |
+
scene.background = new THREE.Color(0x87CEEB); // Sky blue
|
| 578 |
+
|
| 579 |
+
// Camera
|
| 580 |
+
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
|
| 581 |
+
camera.position.set(0, 5, 10);
|
| 582 |
+
|
| 583 |
+
// Renderer
|
| 584 |
+
const canvas = document.getElementById('canvas');
|
| 585 |
+
renderer = new THREE.WebGLRenderer({
|
| 586 |
+
canvas: canvas,
|
| 587 |
+
antialias: true,
|
| 588 |
+
alpha: true
|
| 589 |
+
});
|
| 590 |
+
renderer.setSize(window.innerWidth, window.innerHeight);
|
| 591 |
+
renderer.shadowMap.enabled = true;
|
| 592 |
+
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
|
| 593 |
+
|
| 594 |
+
// Clock for animations
|
| 595 |
+
clock = new THREE.Clock();
|
| 596 |
+
|
| 597 |
+
// Loader
|
| 598 |
+
loader = new THREE.GLTFLoader();
|
| 599 |
+
// Add environment map with error handling
|
| 600 |
+
const envMapLoader = new THREE.CubeTextureLoader();
|
| 601 |
+
envMapLoader.load([
|
| 602 |
+
'https://threejs.org/examples/textures/cube/SwedishRoyalCastle/px.jpg',
|
| 603 |
+
'https://threejs.org/examples/textures/cube/SwedishRoyalCastle/nx.jpg',
|
| 604 |
+
'https://threejs.org/examples/textures/cube/SwedishRoyalCastle/py.jpg',
|
| 605 |
+
'https://threejs.org/examples/textures/cube/SwedishRoyalCastle/ny.jpg',
|
| 606 |
+
'https://threejs.org/examples/textures/cube/SwedishRoyalCastle/pz.jpg',
|
| 607 |
+
'https://threejs.org/examples/textures/cube/SwedishRoyalCastle/nz.jpg'
|
| 608 |
+
],
|
| 609 |
+
(envMap) => {
|
| 610 |
+
scene.background = envMap;
|
| 611 |
+
scene.environment = envMap;
|
| 612 |
+
},
|
| 613 |
+
undefined,
|
| 614 |
+
(error) => {
|
| 615 |
+
console.warn('Failed to load environment map:', error);
|
| 616 |
+
// Fallback to plain color background
|
| 617 |
+
scene.background = new THREE.Color(0x87CEEB);
|
| 618 |
+
});
|
| 619 |
|
| 620 |
+
// Add better lighting for RPM avatars
|
| 621 |
+
const hemisphereLight = new THREE.HemisphereLight(0xffffff, 0x444444, 1);
|
| 622 |
+
scene.add(hemisphereLight);
|
| 623 |
|
| 624 |
+
const mainLight = new THREE.DirectionalLight(0xffffff, 0.8);
|
| 625 |
+
mainLight.position.set(10, 20, 15);
|
| 626 |
+
mainLight.castShadow = true;
|
| 627 |
+
mainLight.shadow.mapSize.width = 2048;
|
| 628 |
+
mainLight.shadow.mapSize.height = 2048;
|
| 629 |
+
mainLight.shadow.camera.near = 0.5;
|
| 630 |
+
mainLight.shadow.camera.far = 50;
|
| 631 |
+
mainLight.shadow.camera.left = -20;
|
| 632 |
+
mainLight.shadow.camera.right = 20;
|
| 633 |
+
mainLight.shadow.camera.top = 20;
|
| 634 |
+
mainLight.shadow.camera.bottom = -20;
|
| 635 |
+
scene.add(mainLight);
|
| 636 |
+
// Create ground
|
| 637 |
+
const groundGeometry = new THREE.PlaneGeometry(100, 100);
|
| 638 |
+
const groundMaterial = new THREE.MeshStandardMaterial({
|
| 639 |
+
color: 0x4ade80,
|
| 640 |
+
roughness: 0.8,
|
| 641 |
+
metalness: 0.2
|
| 642 |
+
});
|
| 643 |
+
const ground = new THREE.Mesh(groundGeometry, groundMaterial);
|
| 644 |
+
ground.rotation.x = -Math.PI / 2;
|
| 645 |
+
ground.receiveShadow = true;
|
| 646 |
+
scene.add(ground);
|
| 647 |
+
|
| 648 |
+
// Add some environment objects
|
| 649 |
+
addEnvironmentObjects();
|
| 650 |
+
|
| 651 |
+
// Initialize OrbitControls
|
| 652 |
+
if (typeof THREE.OrbitControls !== 'undefined') {
|
| 653 |
+
controls = new THREE.OrbitControls(camera, renderer.domElement);
|
| 654 |
+
controls.enableDamping = true;
|
| 655 |
+
controls.dampingFactor = 0.05;
|
| 656 |
+
controls.enabled = false; // Start with controls disabled for follow camera
|
| 657 |
+
} else {
|
| 658 |
+
console.warn('OrbitControls not available');
|
| 659 |
+
controls = { enabled: false, update: () => {} };
|
| 660 |
+
}
|
| 661 |
|
| 662 |
+
// Load player character
|
| 663 |
+
loadPlayerCharacter();
|
| 664 |
+
|
| 665 |
+
// Load NPC characters
|
| 666 |
+
loadNPCCharacters();
|
| 667 |
+
|
| 668 |
+
// Start animation loop
|
| 669 |
+
animate();
|
| 670 |
+
|
| 671 |
+
// Handle window resize
|
| 672 |
+
window.addEventListener('resize', () => {
|
| 673 |
+
camera.aspect = window.innerWidth / window.innerHeight;
|
| 674 |
+
camera.updateProjectionMatrix();
|
| 675 |
+
renderer.setSize(window.innerWidth, window.innerHeight);
|
| 676 |
+
});
|
| 677 |
+
} catch (error) {
|
| 678 |
+
console.error('Error initializing Three.js:', error);
|
| 679 |
+
}
|
| 680 |
}
|
| 681 |
function addEnvironmentObjects() {
|
| 682 |
// Add some trees
|
|
|
|
| 974 |
|
| 975 |
// Update camera based on mode
|
| 976 |
updateCamera(delta);
|
|
|
|
| 977 |
// Update OrbitControls if enabled
|
| 978 |
+
if (controls && controls.enabled) {
|
| 979 |
controls.update();
|
| 980 |
}
|
| 981 |
+
renderer.render(scene, camera);
|
|
|
|
| 982 |
}
|
| 983 |
function handlePlayerMovement(delta) {
|
| 984 |
if (!gameState.player) return;
|
|
|
|
| 1119 |
break;
|
| 1120 |
}
|
| 1121 |
}
|
|
|
|
| 1122 |
function cycleCameraMode() {
|
| 1123 |
const modes = ['follow', 'orbit', 'first-person'];
|
| 1124 |
const currentIndex = modes.indexOf(gameState.cameraMode);
|
|
|
|
| 1130 |
gameState.cameraMode.charAt(0).toUpperCase() + gameState.cameraMode.slice(1);
|
| 1131 |
|
| 1132 |
// Enable/disable OrbitControls based on mode
|
| 1133 |
+
if (controls && typeof controls.enabled !== 'undefined') {
|
| 1134 |
+
controls.enabled = (gameState.cameraMode === 'orbit');
|
| 1135 |
+
}
|
| 1136 |
|
| 1137 |
// Reset camera position for first-person mode
|
| 1138 |
if (gameState.cameraMode === 'first-person') {
|