<!DOCTYPE html>
<html>
<head>
<title>3D迷宫</title>
<style>
body { margin: 0; overflow: hidden; }
</style>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script>
// 全局变量声明
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 100);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 在全局变量区域新增:
let isMouseLocked = false;
const mazeLayout = [
// 边界墙(强化外层结构)
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
// 新的随机分布与数字平衡
[1,0,3,4,0,5,2,3,5,4,2,0,5,3,4,0,2,5,0,3,0,1],
[1,0,5,0,3,0,0,0,0,5,0,4,0,0,0,0,4,0,0,3,0,1],
[1,0,0,0,5,0,4,2,0,0,0,3,5,2,0,0,5,0,0,0,0,1],
[1,0,4,0,1,0,0,1,0,5,0,1,0,0,0,0,1,0,2,0,0,1],
[1,0,3,0,1,0,0,1,0,4,0,1,0,5,0,0,1,0,5,4,0,1],
[1,0,0,0,4,1,1,5,0,0,0,4,5,3,0,0,1,0,3,0,0,1],
[1,0,5,0,0,0,0,0,0,3,0,5,0,2,0,0,1,0,0,0,0,1],
[1,0,2,5,0,4,5,0,2,2,0,0,0,0,0,0,1,0,5,4,0,1],
[1,0,0,0,0,0,0,0,0,0,0,3,5,2,0,0,1,0,4,0,0,1],
[1,0,4,0,5,3,2,0,5,0,4,1,0,1,0,0,1,0,0,0,0,1],
[1,0,5,0,0,0,0,0,4,0,3,1,0,1,0,0,1,0,2,5,0,1],
[1,0,0,0,3,5,2,0,0,0,0,1,0,1,0,0,1,0,5,2,0,1],
[1,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,0,3,0,0,1],
[1,0,3,0,5,4,2,0,3,0,5,1,0,1,0,0,1,0,0,0,0,1],
[1,0,4,0,0,0,0,0,3,0,2,1,0,1,0,0,1,0,5,2,0,1],
[1,0,0,0,2,1,1,4,0,0,0,4,5,3,0,0,1,0,2,0,0,1],
[1,0,5,0,1,0,0,1,0,4,0,1,0,0,0,0,1,0,0,0,0,1],
[1,0,2,0,1,0,0,1,0,3,0,1,0,5,0,0,1,0,2,0,0,1],
[1,0,5,4,0,3,5,0,2,2,0,0,0,0,0,0,1,0,4,0,0,1],
[1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
];
const walls = [];
const moveSpeed = 0.15;
let verticalSpeed = 0;
let canJump = true;
let keys = { forward: false, back: false, left: false, right: false, jump: false };
let cameraDirection = new THREE.Vector3();
let cameraRight = new THREE.Vector3();
let yaw = 0, pitch = 0;
let prevMouseX = 0, prevMouseY = 0;
let sensitivity = 0.3;
let frameCount = 0;
const playerRadius = 0.5;
// 初始化场景
const floorGeometry = new THREE.PlaneGeometry(50, 50);
const floorMaterial = new THREE.MeshPhongMaterial({ color: 0x444444 });
const floor = new THREE.Mesh(floorGeometry, floorMaterial);
floor.rotation.x = -Math.PI/2;
scene.add(floor);
camera.position.set(0, 2, 8);
camera.rotation.set(0, 0, 0);
// 在初始化时添加事件监听:
renderer.domElement.addEventListener('click', () => {
if (!isMouseLocked) {
renderer.domElement.requestPointerLock();
}
});
document.addEventListener('pointerlockchange', () => {
isMouseLocked = document.pointerLockElement === renderer.domElement;
});
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
document.exitPointerLock();
isMouseLocked = false;
}
});
// 灯光设置
const ambientLight = new THREE.AmbientLight(0x404040);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
directionalLight.position.set(0, 10, 0);
scene.add(directionalLight);
function createTextTexture(text, options = {}) {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = 512;
canvas.height = 512;
// 设置渐变背景
const gradient = ctx.createLinearGradient(0, 0, canvas.width, canvas.height);
gradient.addColorStop(0, '#FF3366');
gradient.addColorStop(0.5, '#4FACFE');
gradient.addColorStop(1, '#00F2FE');
// 设置文字样式
ctx.font = 'bold 72px Arial';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
// 调整文字垂直位置,将文字向上移动一些
const textY = canvas.height * 0.4; // 从0.5改为0.4,使文字更靠上
// 添加发光效果
ctx.shadowColor = '#FF9ECD';
ctx.shadowBlur = 15;
ctx.shadowOffsetX = 2;
ctx.shadowOffsetY = 2;
// 绘制描边
ctx.strokeStyle = '#FFFFFF';
ctx.lineWidth = 8;
ctx.strokeText(text, canvas.width/2, textY);
// 使用渐变填充文字
ctx.fillStyle = gradient;
ctx.fillText(text, canvas.width/2, textY);
// 调整装饰线的位置
ctx.beginPath();
ctx.strokeStyle = '#FFD700';
ctx.lineWidth = 2;
ctx.moveTo(100, textY + 80); // 装饰线也相应上移
ctx.lineTo(canvas.width - 100, textY + 80);
ctx.stroke();
return new THREE.CanvasTexture(canvas);
}
// 为每个文字创建不同的样式
const caiTexture = createTextTexture('蔡徐坤', {
gradient: ['#FF3366', '#4FACFE', '#00F2FE']
});
const jiTexture = createTextTexture('鸡你太美', {
gradient: ['#FF416C', '#FF4B2B', '#F7971E']
});
const manTexture = createTextTexture('一个真正的man', {
gradient: ['#8E2DE2', '#4A00E0', '#6A11CB']
});
const youTexture = createTextTexture('你干嘛哎呦', {
gradient: ['#20E2D7', '#F9D423', '#FF4E50']
});
// 生成迷宫部分完整修改后的代码:
const wallMaterial = new THREE.MeshPhongMaterial({ color: 0x999999 });
for (let row = 0; row < mazeLayout.length; row++) {
for (let col = 0; col < mazeLayout[row].length; col++) {
const value = mazeLayout[row][col];
if (value >= 1) { // 只要>=1就生成墙
let material;
if (value === 1) {
material = wallMaterial;
} else if (value === 2) {
material = new THREE.MeshBasicMaterial({ map: caiTexture, side: THREE.DoubleSide });
} else if (value === 3) {
material = new THREE.MeshBasicMaterial({ map: jiTexture, side: THREE.DoubleSide });
} else if (value === 4) {
material = new THREE.MeshBasicMaterial({ map: manTexture, side: THREE.DoubleSide });
} else if (value === 5) {
material = new THREE.MeshBasicMaterial({ map: youTexture, side: THREE.DoubleSide });
}
const wall = new THREE.Mesh(new THREE.BoxGeometry(2,5,2), material);
wall.position.x = (col*2) - 11 +1;
wall.position.z = (row*2) - 11 +1;
walls.push(wall);
scene.add(wall);
}
}
}
// 输入处理
document.addEventListener('keydown', (e) => {
switch(e.code) {
case 'KeyW': keys.forward = true; break;
case 'KeyS': keys.back = true; break;
case 'KeyA': keys.left = true; break;
case 'KeyD': keys.right = true; break;
case 'Space': keys.jump = true; break;
}
});
document.addEventListener('keyup', (e) => {
switch(e.code) {
case 'KeyW': keys.forward = false; break;
case 'KeyS': keys.back = false; break;
case 'KeyA': keys.left = false; break;
case 'KeyD': keys.right = false; break;
case 'Space': keys.jump = false; break;
}
});
document.addEventListener('mousemove', (e) => {
let dx = e.movementX || 0;
let dy = e.movementY || 0;
// 过滤微小移动
if (Math.abs(dx) < 0.3) dx = 0;
if (Math.abs(dy) < 0.3) dy = 0;
prevMouseX = dx;
prevMouseY = dy;
});
document.body.style.cursor = 'none';
// 跳跃逻辑相关变量
const JUMP_FORCE = 2.5;
const GRAVITY = 0.8;
let lastJumpTime = 0;
// 玩家相关变量
const GROUND_LEVEL = 1.5; // 地面高度
const PLAYER_RADIUS = 0.5; // 玩家半径
const PLAYER_HEIGHT = PLAYER_RADIUS * 2; // 玩家总高度
// 碰撞检测函数
function isColliding(position) {
const playerBox = new THREE.Box3();
playerBox.setFromCenterAndSize(
position,
new THREE.Vector3(PLAYER_RADIUS * 2, PLAYER_HEIGHT, PLAYER_RADIUS * 2)
);
for (const wall of walls) {
const wallBox = new THREE.Box3().setFromObject(wall);
if (playerBox.intersectsBox(wallBox)) return true;
}
return false;
}
// 更新跳跃逻辑
function updateJump() {
// 精确的地面检测
const isOnGround = camera.position.y <= GROUND_LEVEL + PLAYER_HEIGHT;
// 处理跳跃,添加时间间隔控制
if (keys.jump && isOnGround && canJump) {
const currentTime = performance.now();
if (currentTime - lastJumpTime > 250) {
verticalSpeed = JUMP_FORCE;
canJump = false;
lastJumpTime = currentTime;
}
}
// 更新位置
camera.position.y += verticalSpeed * 0.014;
verticalSpeed -= GRAVITY * 0.014;
// 地面碰撞处理
if (camera.position.y <= GROUND_LEVEL + PLAYER_HEIGHT) {
camera.position.y = GROUND_LEVEL + PLAYER_HEIGHT;
verticalSpeed = 0;
canJump = true;
}
}
// 主循环
function animate() {
requestAnimationFrame(animate);
// 更新跳跃逻辑
updateJump();
// 渲染场景
renderer.render(scene, camera);
}
// 启动动画
animate();
// 监听键盘事件
window.addEventListener('keydown', (event) => {
if (event.code === 'Space') {
keys.jump = true;
}
});
window.addEventListener('keyup', (event) => {
if (event.code === 'Space') {
keys.jump = false;
}
});
// 移动逻辑
function updateMovement() {
camera.getWorldDirection(cameraDirection);
cameraDirection.y = 0;
cameraDirection.normalize();
cameraRight.crossVectors(cameraDirection, new THREE.Vector3(0,1,0)).normalize();
let moveVector = new THREE.Vector3(0,0,0);
if(keys.forward) moveVector.add(cameraDirection);
if(keys.back) moveVector.add(cameraDirection.negate());
if(keys.left) moveVector.add(cameraRight.negate());
if(keys.right) moveVector.add(cameraRight);
moveVector.normalize();
const stepSize = moveSpeed * 0.1 * 0.2;
const steps = 5;
for (let i = 0; i < steps; i++) {
const stepVector = moveVector.clone().multiplyScalar(stepSize);
const newPosition = camera.position.clone().add(stepVector);
if (!isColliding(newPosition)) {
camera.position.copy(newPosition);
} else {
camera.position.add( stepVector.multiplyScalar(-0.5) );
break;
}
}
}
// 视角控制
function updateCameraRotation() {
if (!isMouseLocked) return;
// 更严格的防抖阈值(0.5改为0.1)
if (Math.abs(prevMouseX) < 0.05) prevMouseX = 0;
if (Math.abs(prevMouseY) < 0.05) prevMouseY = 0;
// 完全静止时立即返回
if (prevMouseX === 0 && prevMouseY === 0) return;
// 统一灵敏度计算(修复原代码重复计算问题)
const deltaX = prevMouseX * sensitivity * 0.002;
const deltaY = prevMouseY * sensitivity * 0.002;
// 应用旋转
yaw -= deltaX;
pitch -= deltaY;
// 加强视角限制
pitch = Math.max(Math.min(pitch, Math.PI/2 - 0.2), -Math.PI/2 + 0.2); // 保留10度安全区
yaw = yaw % (Math.PI * 2); // 保持yaw在合理范围内
// 设置旋转顺序防止侧转
camera.rotation.order = 'YXZ'; // 关键设置:先Y轴后X轴
camera.rotation.set(pitch, yaw, 0);
}
// 自动修复位置
function fixPosition() {
const originalPos = camera.position.clone();
if (isColliding(originalPos)) {
camera.position.y += 0.5;
}
if (isColliding(camera.position)) {
camera.position.copy(originalPos).add(cameraDirection.multiplyScalar(-1));
}
}
// 动画循环
function animate() {
updateCameraRotation();
updateMovement();
updateJump();
if (frameCount % 30 === 0) {
fixPosition();
}
renderer.render(scene, camera);
requestAnimationFrame(animate);
frameCount++;
}
animate();
// 获取渲染器的canvas元素
const canvas = renderer.domElement;
// 提示用户如何操作(更新提示内容)
console.log("按 F 键进入全屏模式,双击 Esc 退出全屏并显示光标");
let escPressCount = 0;
const ESC_DOUBLE_CLICK_INTERVAL = 300; // 双击判定时间间隔(毫秒)
// 专用全屏进入函数
function enterFullScreen() {
if (!document.fullscreenElement) {
canvas.requestFullscreen().catch(console.error);
document.body.style.cursor = 'none';
}
}
// 专用全屏退出函数
function exitFullScreen() {
if (document.fullscreenElement) {
document.exitFullscreen();
}
document.body.style.cursor = 'auto';
}
// 监听键盘事件:F 键强制进入全屏
document.addEventListener('keydown', (e) => {
if (e.key.toLowerCase() === 'f') { // 支持大小写
enterFullScreen();
e.preventDefault(); // 阻止默认行为
}
});
// 双击 ESC 检测逻辑
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
const now = Date.now();
if (!escPressCount || now - escPressCount > ESC_DOUBLE_CLICK_INTERVAL) {
escPressCount = now;
return;
}
// 检测到双击
exitFullScreen();
escPressCount = 0;
e.preventDefault();
}
});
// 全屏状态变化监听
document.addEventListener('fullscreenchange', () => {
if (!document.fullscreenElement) {
document.body.style.cursor = 'auto';
}
});
// 额外添加:鼠标移动时显示光标(游戏常用设计)
let cursorTimeout;
document.addEventListener('mousemove', () => {
document.body.style.cursor = 'auto';
clearTimeout(cursorTimeout);
cursorTimeout = setTimeout(() => {
if (document.fullscreenElement) {
document.body.style.cursor = 'none';
}
}, 2000); // 2秒无操作后隐藏光标
});
</script>
</body>
</html>