修复2.5D光线投射游戏鱼眼畸变及参数优化求助
解决2.5D光线投射游戏的鱼眼畸变与参数优化问题
核心问题分析
你的投射视图出现鱼眼畸变,本质是未对光线距离做视角余弦校正:边缘光线与玩家视线存在夹角,直接使用直线距离会让边缘的墙看起来被拉伸变形。同时画面观感不符合3D效果,是因为墙高的计算逻辑没有结合FOV和投影平面的物理关系。
推荐参数设置
- FOV(视场角):推荐设置为
75,这个数值兼顾写实感和广角视野,是第一人称游戏的常用值;偏好紧凑视角可用65,追求开阔视野则用90。 - 投影画布尺寸:保持
width2=720, height2=360(16:9比例)即可,也可调整为height2=480提升画面高度。 - 玩家视线高度:对应地图格子大小(你的格子为20单位),设为
10(格子高度的一半),符合真实视角逻辑。
代码修改要点
1. 添加鱼眼畸变校正
在计算光线距离后,乘以光线与玩家视线夹角的余弦值,修正距离:
// 原距离计算 let dist = Math.sqrt(deltaX * deltaX + deltaY * deltaY); // 添加余弦校正 const angleDiff = angle - player.heading; dist *= Math.cos(angleDiff * Math.PI / 180);
2. 重构墙高计算逻辑
基于投影平面公式计算墙高,替代原有的简单比例计算:
// 提前定义全局参数 const tileSize = 20; // 地图格子大小 const projectionPlaneDist = (width2 / 2) / Math.tan((FOV / 2) * Math.PI / 180); // 计算墙高 let h = (tileSize / dist) * projectionPlaneDist; h = Math.min(h, height2); // 限制墙高不超过画布高度
3. 调整FOV参数
把全局FOV修改为:
const FOV = 75;
完整修改后的generateColumns函数
const tileSize = 20; const projectionPlaneDist = (width2 / 2) / Math.tan((FOV / 2) * Math.PI / 180); const generateColumns = () => { let distances = Array(columns).fill(0); for (let i = 0; i < columns; i++) { let collided = false; let rayX = player.x; let rayY = player.y; let angle = (player.heading - FOV / 2) + (i / columns) * FOV; let dx = rayCastStep * Math.cos(angle * Math.PI / 180 + Math.PI); let dy = rayCastStep * Math.sin(angle * Math.PI / 180 + Math.PI); while (!collided) { rayX -= dx; rayY -= dy; for (let y = 0; y < map.length; y++) { for (let x = 0; x < map[y][0].length; x++) { if (map[y][0][x] == "#" && willCollide({ xC: rayX, yC: rayY }, { x: x * tileSize + tileSize/2, y: y * tileSize + tileSize/2, w: tileSize, h: tileSize })) { collided = true; let deltaX = player.x - rayX; let deltaY = player.y - rayY; let dist = Math.sqrt(deltaX * deltaX + deltaY * deltaY); // 鱼眼校正 const angleDiff = angle - player.heading; dist *= Math.cos(angleDiff * Math.PI / 180); // 计算正确的墙高 let h = (tileSize / dist) * projectionPlaneDist; h = Math.min(h, height2); distances[i] = { fill: h / height2, h: h } } } } } ctx1.strokeStyle = "#fff"; ctx1.beginPath(); ctx1.moveTo(player.x * (256 / map[0][0].length) / tileSize, player.y * (256 / map.length) / tileSize); ctx1.lineTo(rayX * (256 / map[0][0].length) / tileSize, rayY * (256 / map.length) / tileSize) ctx1.stroke(); } return distances; }
效果说明
修改后,鱼眼畸变会完全消除,墙的比例符合真实3D视角逻辑:近处的墙更高,远处的墙按比例缩小,左右边缘的墙不会出现拉伸变形。你可根据视觉偏好调整FOV数值,比如改成85会获得更宽广的视野,适合快节奏游戏体验。
内容的提问来源于stack exchange,提问作者bread
相关产品推荐
相关产品推荐

