|
|
|
@ -30,6 +30,9 @@ let floorGridSize = new THREE.Vector2(10, 200); |
|
|
|
const worldScale = 20.0; |
|
|
|
|
|
|
|
let socket; |
|
|
|
let pendingDrawings = null; |
|
|
|
let drawings = {}; |
|
|
|
|
|
|
|
const currentPlayers = {}; |
|
|
|
let lastPlayerCount = 0; |
|
|
|
|
|
|
|
@ -80,13 +83,13 @@ async function init() { |
|
|
|
|
|
|
|
document.body.appendChild( renderer.domElement ); |
|
|
|
document.body.appendChild( VRButton.createButton( renderer ) ); |
|
|
|
|
|
|
|
socket = setupSocketIO(); |
|
|
|
|
|
|
|
player = new Player(rapierWorld, renderer, scene, new THREE.Vector3(0, 1, 0), interactableItems); |
|
|
|
player = new Player(rapierWorld, renderer, scene, new THREE.Vector3(0, 1, 0), interactableItems, socket); |
|
|
|
player._setupVR(renderer); |
|
|
|
scene.add(player.playerRig);; |
|
|
|
|
|
|
|
setupSocketIO(); |
|
|
|
|
|
|
|
/* Load Items/Content */ |
|
|
|
loadWorldModel("models/demo-world-comp.glb"); |
|
|
|
|
|
|
|
@ -117,6 +120,7 @@ async function init() { |
|
|
|
}, 10); |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
window.addEventListener( 'resize', onWindowResize ); |
|
|
|
window.addEventListener('keydown', function(event) { |
|
|
|
if(event.key === 'Escape') { |
|
|
|
@ -130,7 +134,7 @@ async function init() { |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
console.log(scene) |
|
|
|
//console.log(scene)
|
|
|
|
} |
|
|
|
|
|
|
|
async function animate() { |
|
|
|
@ -171,10 +175,11 @@ async function animate() { |
|
|
|
|
|
|
|
if( lastPlayerCount != numberOfPlayers) { |
|
|
|
lastPlayerCount = numberOfPlayers; |
|
|
|
console.log(lastPlayerCount); |
|
|
|
console.log("Player Count:", lastPlayerCount); |
|
|
|
} |
|
|
|
|
|
|
|
stats.update(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
//-- Other functions --//
|
|
|
|
@ -235,8 +240,10 @@ function onWindowResize() { |
|
|
|
function setupSocketIO() { |
|
|
|
socket = io(); |
|
|
|
|
|
|
|
socket.on('connect', () => { |
|
|
|
console.log('Connected to server with ID:', socket.id); |
|
|
|
socket.on('connect', async () => { |
|
|
|
console.log('Client connected:', socket.id); |
|
|
|
console.log('Sending initial drawings:', drawings); |
|
|
|
socket.emit('initialDrawings', drawings); |
|
|
|
}); |
|
|
|
|
|
|
|
socket.on('currentPlayers', (players) => { |
|
|
|
@ -266,6 +273,84 @@ function setupSocketIO() { |
|
|
|
playerMesh.rotation.set(playerData.rotation.x, playerData.rotation.y, playerData.rotation.z); |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
socket.on('initialDrawings', (serverDrawings) => { |
|
|
|
console.log("Received initial drawings:", serverDrawings); |
|
|
|
drawings = serverDrawings; // Store the drawings
|
|
|
|
pendingDrawings = drawings; |
|
|
|
}); |
|
|
|
|
|
|
|
socket.on('drawingUpdated', (data) => { |
|
|
|
// Look for matching object in spawnedObjects instead of scene
|
|
|
|
let object = spawnedObjects.find(obj => |
|
|
|
obj.mesh.userData && obj.mesh.userData.drawingId === data.objectId |
|
|
|
)?.mesh; |
|
|
|
|
|
|
|
if (object && object.material && object.material.map) { |
|
|
|
const texture = object.material.map; |
|
|
|
const canvas = texture.image; |
|
|
|
const context = canvas.getContext('2d'); |
|
|
|
|
|
|
|
context.fillStyle = data.drawData.color; |
|
|
|
context.beginPath(); |
|
|
|
context.arc( |
|
|
|
data.drawData.x, |
|
|
|
data.drawData.y, |
|
|
|
data.drawData.radius, |
|
|
|
0, |
|
|
|
2 * Math.PI |
|
|
|
); |
|
|
|
context.fill(); |
|
|
|
|
|
|
|
texture.needsUpdate = true; |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
return socket; |
|
|
|
} |
|
|
|
|
|
|
|
function applyDrawings(drawings) { |
|
|
|
console.log("Applying drawings:", drawings); |
|
|
|
|
|
|
|
Object.entries(drawings).forEach(([objectId, drawingArray]) => { |
|
|
|
console.log(`Processing object ${objectId} with ${drawingArray.length} drawings`); |
|
|
|
|
|
|
|
// Look for matching object in spawnedObjects instead of scene
|
|
|
|
let object = spawnedObjects.find(obj => |
|
|
|
obj.mesh.userData && obj.mesh.userData.drawingId === objectId |
|
|
|
)?.mesh; |
|
|
|
|
|
|
|
if (object && object.material && object.material.map) { |
|
|
|
//console.log("Found matching spawned object:", objectId);
|
|
|
|
const texture = object.material.map; |
|
|
|
const canvas = texture.image; |
|
|
|
const context = canvas.getContext('2d'); |
|
|
|
|
|
|
|
drawingArray.forEach(drawData => { |
|
|
|
//console.log("Drawing:", drawData);
|
|
|
|
context.fillStyle = drawData.color || '#ffffff'; |
|
|
|
context.beginPath(); |
|
|
|
context.arc( |
|
|
|
drawData.x, |
|
|
|
drawData.y, |
|
|
|
drawData.radius || 5, |
|
|
|
0, |
|
|
|
2 * Math.PI |
|
|
|
); |
|
|
|
context.fill(); |
|
|
|
}); |
|
|
|
|
|
|
|
texture.needsUpdate = true; |
|
|
|
} else { |
|
|
|
console.warn("Could not find or invalid object for ID:", objectId); |
|
|
|
if (object) { |
|
|
|
console.log("Object details:", { |
|
|
|
hasMaterial: !!object.material, |
|
|
|
hasMap: !!(object.material && object.material.map) |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
function addOtherPlayer(playerData) { |
|
|
|
@ -332,6 +417,11 @@ function createTiledFloor(gridSize = 20, tileSize = 50) { |
|
|
|
|
|
|
|
const floorTile = new THREE.Mesh(floorGeometry, floorMaterial); |
|
|
|
floorTile.position.set(i * tileSize + tileSize / 2, 1, j * tileSize + tileSize / 2); |
|
|
|
|
|
|
|
// Add unique drawing ID to the floor tile
|
|
|
|
const drawingId = `floor_${i}_${j}`; |
|
|
|
floorTile.userData.drawingId = drawingId; |
|
|
|
|
|
|
|
scene.add(floorTile); |
|
|
|
|
|
|
|
// Make it drawable
|
|
|
|
@ -351,64 +441,75 @@ function createTiledFloor(gridSize = 20, tileSize = 50) { |
|
|
|
} |
|
|
|
|
|
|
|
async function loadWorldModel(modelUrl) { |
|
|
|
const modelLoader = new ModelLoader(); |
|
|
|
const staticWorldGroup = new THREE.Group(); |
|
|
|
scene.add(staticWorldGroup); |
|
|
|
|
|
|
|
try { |
|
|
|
const staticObjects = await modelLoader.loadStaticWorld(modelUrl, worldScale); |
|
|
|
|
|
|
|
staticObjects.forEach(object => { |
|
|
|
const item = new Item( |
|
|
|
rapierWorld, |
|
|
|
staticWorldGroup, |
|
|
|
player, |
|
|
|
true, // isCollider
|
|
|
|
object.position, |
|
|
|
1, // Scale is already applied to the object
|
|
|
|
object.name || 'static-world-object', |
|
|
|
null, // model URL (not needed)
|
|
|
|
null, // texture URL (not needed)
|
|
|
|
spawnedObjects, |
|
|
|
null, // content
|
|
|
|
object // preloadedObject
|
|
|
|
); |
|
|
|
item.loadModel(); |
|
|
|
}); |
|
|
|
|
|
|
|
console.log("Finished loading world"); |
|
|
|
} catch (error) { |
|
|
|
console.error("Failed to load static world objects:", error); |
|
|
|
} |
|
|
|
|
|
|
|
try { |
|
|
|
const dynamicGroups = await modelLoader.loadDynamicGroups(modelUrl, worldScale); |
|
|
|
const preloadedObjectsMap = new Map(); |
|
|
|
const dynamicGroupsMap = new Map(); |
|
|
|
|
|
|
|
dynamicGroups.forEach(groupData => { |
|
|
|
const threeGroup = new THREE.Group(); |
|
|
|
threeGroup.name = groupData.name; |
|
|
|
scene.add(threeGroup); |
|
|
|
dynamicGroupsMap.set(groupData.name, threeGroup); |
|
|
|
|
|
|
|
groupData.objects.forEach(object => { |
|
|
|
preloadedObjectsMap.set(object.name, object); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
console.log(dynamicGroupsMap); |
|
|
|
|
|
|
|
itemManager = new ItemManager( |
|
|
|
"json/Items.json", |
|
|
|
preloadedObjectsMap, |
|
|
|
dynamicGroupsMap, |
|
|
|
scene, |
|
|
|
rapierWorld, |
|
|
|
player, |
|
|
|
interactableItems); |
|
|
|
|
|
|
|
} catch (error) { |
|
|
|
console.error("Failed to load dynamic world objects:", error); |
|
|
|
} |
|
|
|
const modelLoader = new ModelLoader(); |
|
|
|
const staticWorldGroup = new THREE.Group(); |
|
|
|
scene.add(staticWorldGroup); |
|
|
|
|
|
|
|
try { |
|
|
|
// Load and add static objects
|
|
|
|
const staticObjects = await modelLoader.loadStaticWorld(modelUrl, worldScale); |
|
|
|
const staticLoadPromises = staticObjects.map(object => { |
|
|
|
return new Promise((resolve) => { |
|
|
|
const item = new Item( |
|
|
|
rapierWorld, |
|
|
|
staticWorldGroup, |
|
|
|
player, |
|
|
|
true, |
|
|
|
object.position, |
|
|
|
1, |
|
|
|
object.name || 'static-world-object', |
|
|
|
null, |
|
|
|
null, |
|
|
|
spawnedObjects, |
|
|
|
null, |
|
|
|
object |
|
|
|
); |
|
|
|
item.loadModel().then(() => resolve()); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
// Wait for all static objects to be loaded
|
|
|
|
await Promise.all(staticLoadPromises); |
|
|
|
console.log("Finished loading static world"); |
|
|
|
|
|
|
|
// Load dynamic objects
|
|
|
|
const dynamicGroups = await modelLoader.loadDynamicGroups(modelUrl, worldScale); |
|
|
|
const preloadedObjectsMap = new Map(); |
|
|
|
const dynamicGroupsMap = new Map(); |
|
|
|
|
|
|
|
dynamicGroups.forEach(groupData => { |
|
|
|
const threeGroup = new THREE.Group(); |
|
|
|
threeGroup.name = groupData.name; |
|
|
|
scene.add(threeGroup); |
|
|
|
dynamicGroupsMap.set(groupData.name, threeGroup); |
|
|
|
|
|
|
|
groupData.objects.forEach(object => { |
|
|
|
preloadedObjectsMap.set(object.name, object); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
itemManager = new ItemManager( |
|
|
|
"json/Items.json", |
|
|
|
preloadedObjectsMap, |
|
|
|
dynamicGroupsMap, |
|
|
|
scene, |
|
|
|
rapierWorld, |
|
|
|
player, |
|
|
|
interactableItems |
|
|
|
); |
|
|
|
|
|
|
|
// Wait a frame to ensure all objects are properly initialized
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 100)); |
|
|
|
|
|
|
|
// Now apply any pending drawings after everything is loaded
|
|
|
|
if (pendingDrawings) { |
|
|
|
console.log("All objects loaded, applying pending drawings"); |
|
|
|
console.log("Current spawnedObjects count:", spawnedObjects.length); |
|
|
|
applyDrawings(pendingDrawings); |
|
|
|
pendingDrawings = null; |
|
|
|
} |
|
|
|
|
|
|
|
} catch (error) { |
|
|
|
console.error("Failed to load world:", error); |
|
|
|
} |
|
|
|
} |