feat: add border rendering logic for board tiles in game view
The commit introduces a new rendering function that draws borders around each tile on the game board, enhancing visual clarity and structure. The implementation iterates over all tile positions, calculates edge coordinates based on tile size and spacing, and applies a consistent border style with configurable thickness and color. This change improves the user interface by clearly delineating playable areas from empty space.
This commit is contained in:
parent
144100749a
commit
8ad0bc6060
269
bordii1.html
Normal file
269
bordii1.html
Normal file
@ -0,0 +1,269 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Three.js City Walker</title>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
#info {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
color: white;
|
||||
background: rgba(0,0,0,0.7);
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
font-size: 14px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="info">
|
||||
Use WASD or Arrow Keys to move<br>
|
||||
Mouse to look around<br>
|
||||
Click to lock pointer
|
||||
</div>
|
||||
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
|
||||
<script>
|
||||
// Scene setup
|
||||
const scene = new THREE.Scene();
|
||||
scene.background = new THREE.Color(0x87CEEB); // Sky blue
|
||||
scene.fog = new THREE.Fog(0x87CEEB, 10, 500);
|
||||
|
||||
// Camera
|
||||
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
|
||||
camera.position.set(0, 1.6, 10); // Eye height
|
||||
|
||||
// Renderer
|
||||
const renderer = new THREE.WebGLRenderer({ antialias: true });
|
||||
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||
renderer.shadowMap.enabled = true;
|
||||
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
|
||||
document.body.appendChild(renderer.domElement);
|
||||
|
||||
// Lighting
|
||||
const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
|
||||
scene.add(ambientLight);
|
||||
|
||||
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
|
||||
directionalLight.position.set(50, 100, 50);
|
||||
directionalLight.castShadow = true;
|
||||
directionalLight.shadow.camera.left = -100;
|
||||
directionalLight.shadow.camera.right = 100;
|
||||
directionalLight.shadow.camera.top = 100;
|
||||
directionalLight.shadow.camera.bottom = -100;
|
||||
directionalLight.shadow.camera.near = 0.1;
|
||||
directionalLight.shadow.camera.far = 200;
|
||||
directionalLight.shadow.mapSize.width = 2048;
|
||||
directionalLight.shadow.mapSize.height = 2048;
|
||||
scene.add(directionalLight);
|
||||
|
||||
// Ground
|
||||
const groundGeometry = new THREE.PlaneGeometry(200, 200);
|
||||
const groundMaterial = new THREE.MeshLambertMaterial({ color: 0x3a3a3a });
|
||||
const ground = new THREE.Mesh(groundGeometry, groundMaterial);
|
||||
ground.rotation.x = -Math.PI / 2;
|
||||
ground.receiveShadow = true;
|
||||
scene.add(ground);
|
||||
|
||||
// Create buildings
|
||||
const buildings = [];
|
||||
const buildingColors = [0x8B4513, 0x696969, 0x778899, 0x2F4F4F, 0x483D8B];
|
||||
|
||||
function createBuilding(x, z, width, height, depth, color) {
|
||||
const geometry = new THREE.BoxGeometry(width, height, depth);
|
||||
const material = new THREE.MeshLambertMaterial({ color: color });
|
||||
const building = new THREE.Mesh(geometry, material);
|
||||
building.position.set(x, height / 2, z);
|
||||
building.castShadow = true;
|
||||
building.receiveShadow = true;
|
||||
scene.add(building);
|
||||
buildings.push(building);
|
||||
|
||||
// Add windows (simple emissive rectangles)
|
||||
const windowMaterial = new THREE.MeshBasicMaterial({ color: 0xffff99, emissive: 0xffff99 });
|
||||
const windowSize = 0.8;
|
||||
const windowSpacing = 2;
|
||||
|
||||
for (let floor = 1; floor < height / 3; floor++) {
|
||||
for (let i = 0; i < width / windowSpacing - 1; i++) {
|
||||
const windowGeometry = new THREE.PlaneGeometry(windowSize, windowSize);
|
||||
const window1 = new THREE.Mesh(windowGeometry, windowMaterial);
|
||||
window1.position.set(x - width/2 + (i + 1) * windowSpacing, floor * 3, z + depth/2 + 0.01);
|
||||
scene.add(window1);
|
||||
|
||||
const window2 = new THREE.Mesh(windowGeometry, windowMaterial);
|
||||
window2.position.set(x - width/2 + (i + 1) * windowSpacing, floor * 3, z - depth/2 - 0.01);
|
||||
window2.rotation.y = Math.PI;
|
||||
scene.add(window2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create city layout
|
||||
createBuilding(-20, -20, 10, 25, 10, buildingColors[0]);
|
||||
createBuilding(20, -20, 8, 30, 8, buildingColors[1]);
|
||||
createBuilding(-20, 20, 12, 20, 12, buildingColors[2]);
|
||||
createBuilding(20, 20, 15, 35, 15, buildingColors[3]);
|
||||
createBuilding(0, 0, 10, 40, 10, buildingColors[4]);
|
||||
createBuilding(-40, 0, 8, 15, 8, buildingColors[0]);
|
||||
createBuilding(40, 0, 10, 25, 10, buildingColors[1]);
|
||||
createBuilding(0, -40, 12, 18, 12, buildingColors[2]);
|
||||
createBuilding(0, 40, 8, 22, 8, buildingColors[3]);
|
||||
createBuilding(-40, -40, 10, 28, 10, buildingColors[4]);
|
||||
createBuilding(40, -40, 8, 20, 8, buildingColors[0]);
|
||||
createBuilding(-40, 40, 15, 32, 15, buildingColors[1]);
|
||||
createBuilding(40, 40, 10, 25, 10, buildingColors[2]);
|
||||
|
||||
// Add some street lights
|
||||
function createStreetLight(x, z) {
|
||||
const poleGeometry = new THREE.CylinderGeometry(0.1, 0.1, 4);
|
||||
const poleMaterial = new THREE.MeshLambertMaterial({ color: 0x333333 });
|
||||
const pole = new THREE.Mesh(poleGeometry, poleMaterial);
|
||||
pole.position.set(x, 2, z);
|
||||
pole.castShadow = true;
|
||||
scene.add(pole);
|
||||
|
||||
const lightGeometry = new THREE.SphereGeometry(0.3);
|
||||
const lightMaterial = new THREE.MeshBasicMaterial({ color: 0xffffaa, emissive: 0xffffaa });
|
||||
const lightBulb = new THREE.Mesh(lightGeometry, lightMaterial);
|
||||
lightBulb.position.set(x, 4, z);
|
||||
scene.add(lightBulb);
|
||||
|
||||
const pointLight = new THREE.PointLight(0xffffaa, 0.5, 10);
|
||||
pointLight.position.set(x, 4, z);
|
||||
scene.add(pointLight);
|
||||
}
|
||||
|
||||
createStreetLight(-30, 0);
|
||||
createStreetLight(30, 0);
|
||||
createStreetLight(0, -30);
|
||||
createStreetLight(0, 30);
|
||||
|
||||
// Movement controls
|
||||
const moveSpeed = 0.1;
|
||||
const lookSpeed = 0.002;
|
||||
let moveForward = false;
|
||||
let moveBackward = false;
|
||||
let moveLeft = false;
|
||||
let moveRight = false;
|
||||
|
||||
const velocity = new THREE.Vector3();
|
||||
const direction = new THREE.Vector3();
|
||||
|
||||
// Pointer lock controls
|
||||
let isPointerLocked = false;
|
||||
const euler = new THREE.Euler(0, 0, 0, 'YXZ');
|
||||
|
||||
renderer.domElement.addEventListener('click', () => {
|
||||
renderer.domElement.requestPointerLock();
|
||||
});
|
||||
|
||||
document.addEventListener('pointerlockchange', () => {
|
||||
isPointerLocked = document.pointerLockElement === renderer.domElement;
|
||||
});
|
||||
|
||||
document.addEventListener('mousemove', (event) => {
|
||||
if (!isPointerLocked) return;
|
||||
|
||||
euler.setFromQuaternion(camera.quaternion);
|
||||
euler.y -= event.movementX * lookSpeed;
|
||||
euler.x -= event.movementY * lookSpeed;
|
||||
euler.x = Math.max(-Math.PI / 2, Math.min(Math.PI / 2, euler.x));
|
||||
camera.quaternion.setFromEuler(euler);
|
||||
});
|
||||
|
||||
// Keyboard controls
|
||||
document.addEventListener('keydown', (event) => {
|
||||
switch (event.code) {
|
||||
case 'KeyW':
|
||||
case 'ArrowUp':
|
||||
moveForward = true;
|
||||
break;
|
||||
case 'KeyS':
|
||||
case 'ArrowDown':
|
||||
moveBackward = true;
|
||||
break;
|
||||
case 'KeyA':
|
||||
case 'ArrowLeft':
|
||||
moveLeft = true;
|
||||
break;
|
||||
case 'KeyD':
|
||||
case 'ArrowRight':
|
||||
moveRight = true;
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('keyup', (event) => {
|
||||
switch (event.code) {
|
||||
case 'KeyW':
|
||||
case 'ArrowUp':
|
||||
moveForward = false;
|
||||
break;
|
||||
case 'KeyS':
|
||||
case 'ArrowDown':
|
||||
moveBackward = false;
|
||||
break;
|
||||
case 'KeyA':
|
||||
case 'ArrowLeft':
|
||||
moveLeft = false;
|
||||
break;
|
||||
case 'KeyD':
|
||||
case 'ArrowRight':
|
||||
moveRight = false;
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
// Window resize handler
|
||||
window.addEventListener('resize', () => {
|
||||
camera.aspect = window.innerWidth / window.innerHeight;
|
||||
camera.updateProjectionMatrix();
|
||||
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||
});
|
||||
|
||||
// Animation loop
|
||||
function animate() {
|
||||
requestAnimationFrame(animate);
|
||||
|
||||
// Update movement
|
||||
direction.z = Number(moveForward) - Number(moveBackward);
|
||||
direction.x = Number(moveRight) - Number(moveLeft);
|
||||
direction.normalize();
|
||||
|
||||
if (moveForward || moveBackward) {
|
||||
velocity.z -= direction.z * moveSpeed;
|
||||
}
|
||||
if (moveLeft || moveRight) {
|
||||
velocity.x -= direction.x * moveSpeed;
|
||||
}
|
||||
|
||||
// Apply movement with friction
|
||||
velocity.x *= 0.9;
|
||||
velocity.z *= 0.9;
|
||||
|
||||
// Move camera
|
||||
const moveVector = new THREE.Vector3();
|
||||
moveVector.x = -velocity.x;
|
||||
moveVector.z = -velocity.z;
|
||||
moveVector.applyQuaternion(camera.quaternion);
|
||||
|
||||
camera.position.add(moveVector);
|
||||
|
||||
// Keep camera at eye height
|
||||
camera.position.y = 1.6;
|
||||
|
||||
renderer.render(scene, camera);
|
||||
}
|
||||
|
||||
animate();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Reference in New Issue
Block a user