Commit
·
09bc1ec
1
Parent(s):
8ea1a0b
Update game_viewer.html
Browse files- frontend/game_viewer.html +106 -10
frontend/game_viewer.html
CHANGED
|
@@ -492,12 +492,60 @@
|
|
| 492 |
physicsWorld.addContactMaterial(defaultContactMaterial);
|
| 493 |
physicsWorld.defaultContactMaterial = defaultContactMaterial;
|
| 494 |
|
| 495 |
-
// Create
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 496 |
const groundGeometry = new THREE.PlaneGeometry(WORLD_SIZE, WORLD_SIZE);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 497 |
const groundMaterial = new THREE.MeshStandardMaterial({
|
| 498 |
-
|
| 499 |
-
roughness: 0.
|
| 500 |
-
metalness: 0.
|
| 501 |
});
|
| 502 |
const groundMesh = new THREE.Mesh(groundGeometry, groundMaterial);
|
| 503 |
groundMesh.rotation.x = -Math.PI / 2; // Rotate to be horizontal
|
|
@@ -513,37 +561,85 @@
|
|
| 513 |
groundBody.quaternion.setFromEuler(-Math.PI / 2, 0, 0);
|
| 514 |
physicsWorld.addBody(groundBody);
|
| 515 |
|
| 516 |
-
// Create 4
|
| 517 |
const wallHeight = 5;
|
| 518 |
const wallThickness = 0.5;
|
| 519 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 520 |
// North wall (z = +WORLD_HALF)
|
| 521 |
-
const
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 522 |
const northWallBody = new CANNON.Body({ mass: 0, material: defaultMaterial });
|
| 523 |
northWallBody.addShape(northWallShape);
|
| 524 |
-
northWallBody.position.
|
| 525 |
physicsWorld.addBody(northWallBody);
|
| 526 |
wallBodies.push(northWallBody);
|
| 527 |
|
| 528 |
// South wall (z = -WORLD_HALF)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 529 |
const southWallBody = new CANNON.Body({ mass: 0, material: defaultMaterial });
|
| 530 |
southWallBody.addShape(northWallShape);
|
| 531 |
-
southWallBody.position.
|
| 532 |
physicsWorld.addBody(southWallBody);
|
| 533 |
wallBodies.push(southWallBody);
|
| 534 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 535 |
// East wall (x = +WORLD_HALF)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 536 |
const eastWallShape = new CANNON.Box(new CANNON.Vec3(wallThickness / 2, wallHeight / 2, WORLD_SIZE / 2));
|
| 537 |
const eastWallBody = new CANNON.Body({ mass: 0, material: defaultMaterial });
|
| 538 |
eastWallBody.addShape(eastWallShape);
|
| 539 |
-
eastWallBody.position.
|
| 540 |
physicsWorld.addBody(eastWallBody);
|
| 541 |
wallBodies.push(eastWallBody);
|
| 542 |
|
| 543 |
// West wall (x = -WORLD_HALF)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 544 |
const westWallBody = new CANNON.Body({ mass: 0, material: defaultMaterial });
|
| 545 |
westWallBody.addShape(eastWallShape);
|
| 546 |
-
westWallBody.position.
|
| 547 |
physicsWorld.addBody(westWallBody);
|
| 548 |
wallBodies.push(westWallBody);
|
| 549 |
|
|
|
|
| 492 |
physicsWorld.addContactMaterial(defaultContactMaterial);
|
| 493 |
physicsWorld.defaultContactMaterial = defaultContactMaterial;
|
| 494 |
|
| 495 |
+
// Create blueprint-style grid texture for ground
|
| 496 |
+
function createBlueprintTexture(size = 512) {
|
| 497 |
+
const canvas = document.createElement('canvas');
|
| 498 |
+
canvas.width = size;
|
| 499 |
+
canvas.height = size;
|
| 500 |
+
const ctx = canvas.getContext('2d');
|
| 501 |
+
|
| 502 |
+
// Background - blueprint blue
|
| 503 |
+
ctx.fillStyle = '#1a4a6e';
|
| 504 |
+
ctx.fillRect(0, 0, size, size);
|
| 505 |
+
|
| 506 |
+
// Major grid lines (1 unit = 64px at 512 texture for 8 divisions)
|
| 507 |
+
const majorSpacing = size / 8;
|
| 508 |
+
ctx.strokeStyle = '#2a6a9e';
|
| 509 |
+
ctx.lineWidth = 2;
|
| 510 |
+
ctx.beginPath();
|
| 511 |
+
for (let i = 0; i <= 8; i++) {
|
| 512 |
+
const pos = i * majorSpacing;
|
| 513 |
+
ctx.moveTo(pos, 0);
|
| 514 |
+
ctx.lineTo(pos, size);
|
| 515 |
+
ctx.moveTo(0, pos);
|
| 516 |
+
ctx.lineTo(size, pos);
|
| 517 |
+
}
|
| 518 |
+
ctx.stroke();
|
| 519 |
+
|
| 520 |
+
// Minor grid lines (subdivisions)
|
| 521 |
+
const minorSpacing = majorSpacing / 4;
|
| 522 |
+
ctx.strokeStyle = '#1f5a8e';
|
| 523 |
+
ctx.lineWidth = 1;
|
| 524 |
+
ctx.beginPath();
|
| 525 |
+
for (let i = 0; i <= 32; i++) {
|
| 526 |
+
const pos = i * minorSpacing;
|
| 527 |
+
ctx.moveTo(pos, 0);
|
| 528 |
+
ctx.lineTo(pos, size);
|
| 529 |
+
ctx.moveTo(0, pos);
|
| 530 |
+
ctx.lineTo(size, pos);
|
| 531 |
+
}
|
| 532 |
+
ctx.stroke();
|
| 533 |
+
|
| 534 |
+
return canvas;
|
| 535 |
+
}
|
| 536 |
+
|
| 537 |
+
// Create ground plane
|
| 538 |
const groundGeometry = new THREE.PlaneGeometry(WORLD_SIZE, WORLD_SIZE);
|
| 539 |
+
const blueprintCanvas = createBlueprintTexture();
|
| 540 |
+
const blueprintTexture = new THREE.CanvasTexture(blueprintCanvas);
|
| 541 |
+
blueprintTexture.wrapS = THREE.RepeatWrapping;
|
| 542 |
+
blueprintTexture.wrapT = THREE.RepeatWrapping;
|
| 543 |
+
blueprintTexture.repeat.set(WORLD_SIZE / 5, WORLD_SIZE / 5); // 5 units per texture tile
|
| 544 |
+
|
| 545 |
const groundMaterial = new THREE.MeshStandardMaterial({
|
| 546 |
+
map: blueprintTexture,
|
| 547 |
+
roughness: 0.9,
|
| 548 |
+
metalness: 0.0
|
| 549 |
});
|
| 550 |
const groundMesh = new THREE.Mesh(groundGeometry, groundMaterial);
|
| 551 |
groundMesh.rotation.x = -Math.PI / 2; // Rotate to be horizontal
|
|
|
|
| 561 |
groundBody.quaternion.setFromEuler(-Math.PI / 2, 0, 0);
|
| 562 |
physicsWorld.addBody(groundBody);
|
| 563 |
|
| 564 |
+
// Create 4 boundary walls with blueprint texture
|
| 565 |
const wallHeight = 5;
|
| 566 |
const wallThickness = 0.5;
|
| 567 |
|
| 568 |
+
// Wall material - same blueprint texture
|
| 569 |
+
const wallTexture = new THREE.CanvasTexture(createBlueprintTexture());
|
| 570 |
+
wallTexture.wrapS = THREE.RepeatWrapping;
|
| 571 |
+
wallTexture.wrapT = THREE.RepeatWrapping;
|
| 572 |
+
|
| 573 |
+
const wallMaterial = new THREE.MeshStandardMaterial({
|
| 574 |
+
map: wallTexture,
|
| 575 |
+
roughness: 0.9,
|
| 576 |
+
metalness: 0.0
|
| 577 |
+
});
|
| 578 |
+
|
| 579 |
+
// North/South walls (along X axis)
|
| 580 |
+
const nsWallGeometry = new THREE.BoxGeometry(WORLD_SIZE, wallHeight, wallThickness);
|
| 581 |
+
// Texture repeat: width based on world size, height = 1 tile (5 units)
|
| 582 |
+
const nsWallMaterial = wallMaterial.clone();
|
| 583 |
+
nsWallMaterial.map = wallTexture.clone();
|
| 584 |
+
nsWallMaterial.map.repeat.set(WORLD_SIZE / 5, wallHeight / 5);
|
| 585 |
+
|
| 586 |
// North wall (z = +WORLD_HALF)
|
| 587 |
+
const northWallMesh = new THREE.Mesh(nsWallGeometry, nsWallMaterial);
|
| 588 |
+
northWallMesh.position.set(0, wallHeight / 2, WORLD_HALF);
|
| 589 |
+
northWallMesh.receiveShadow = true;
|
| 590 |
+
northWallMesh.castShadow = true;
|
| 591 |
+
scene.add(northWallMesh);
|
| 592 |
+
|
| 593 |
+
const northWallShape = new CANNON.Box(new CANNON.Vec3(WORLD_SIZE / 2, wallHeight / 2, wallThickness / 2));
|
| 594 |
const northWallBody = new CANNON.Body({ mass: 0, material: defaultMaterial });
|
| 595 |
northWallBody.addShape(northWallShape);
|
| 596 |
+
northWallBody.position.copy(northWallMesh.position);
|
| 597 |
physicsWorld.addBody(northWallBody);
|
| 598 |
wallBodies.push(northWallBody);
|
| 599 |
|
| 600 |
// South wall (z = -WORLD_HALF)
|
| 601 |
+
const southWallMesh = new THREE.Mesh(nsWallGeometry, nsWallMaterial);
|
| 602 |
+
southWallMesh.position.set(0, wallHeight / 2, -WORLD_HALF);
|
| 603 |
+
southWallMesh.receiveShadow = true;
|
| 604 |
+
southWallMesh.castShadow = true;
|
| 605 |
+
scene.add(southWallMesh);
|
| 606 |
+
|
| 607 |
const southWallBody = new CANNON.Body({ mass: 0, material: defaultMaterial });
|
| 608 |
southWallBody.addShape(northWallShape);
|
| 609 |
+
southWallBody.position.copy(southWallMesh.position);
|
| 610 |
physicsWorld.addBody(southWallBody);
|
| 611 |
wallBodies.push(southWallBody);
|
| 612 |
|
| 613 |
+
// East/West walls (along Z axis)
|
| 614 |
+
const ewWallGeometry = new THREE.BoxGeometry(wallThickness, wallHeight, WORLD_SIZE);
|
| 615 |
+
const ewWallMaterial = wallMaterial.clone();
|
| 616 |
+
ewWallMaterial.map = wallTexture.clone();
|
| 617 |
+
ewWallMaterial.map.repeat.set(WORLD_SIZE / 5, wallHeight / 5);
|
| 618 |
+
|
| 619 |
// East wall (x = +WORLD_HALF)
|
| 620 |
+
const eastWallMesh = new THREE.Mesh(ewWallGeometry, ewWallMaterial);
|
| 621 |
+
eastWallMesh.position.set(WORLD_HALF, wallHeight / 2, 0);
|
| 622 |
+
eastWallMesh.receiveShadow = true;
|
| 623 |
+
eastWallMesh.castShadow = true;
|
| 624 |
+
scene.add(eastWallMesh);
|
| 625 |
+
|
| 626 |
const eastWallShape = new CANNON.Box(new CANNON.Vec3(wallThickness / 2, wallHeight / 2, WORLD_SIZE / 2));
|
| 627 |
const eastWallBody = new CANNON.Body({ mass: 0, material: defaultMaterial });
|
| 628 |
eastWallBody.addShape(eastWallShape);
|
| 629 |
+
eastWallBody.position.copy(eastWallMesh.position);
|
| 630 |
physicsWorld.addBody(eastWallBody);
|
| 631 |
wallBodies.push(eastWallBody);
|
| 632 |
|
| 633 |
// West wall (x = -WORLD_HALF)
|
| 634 |
+
const westWallMesh = new THREE.Mesh(ewWallGeometry, ewWallMaterial);
|
| 635 |
+
westWallMesh.position.set(-WORLD_HALF, wallHeight / 2, 0);
|
| 636 |
+
westWallMesh.receiveShadow = true;
|
| 637 |
+
westWallMesh.castShadow = true;
|
| 638 |
+
scene.add(westWallMesh);
|
| 639 |
+
|
| 640 |
const westWallBody = new CANNON.Body({ mass: 0, material: defaultMaterial });
|
| 641 |
westWallBody.addShape(eastWallShape);
|
| 642 |
+
westWallBody.position.copy(westWallMesh.position);
|
| 643 |
physicsWorld.addBody(westWallBody);
|
| 644 |
wallBodies.push(westWallBody);
|
| 645 |
|