如何在JavaScript中实现基于旋转视野的FOV射线绘制详解
如果用一句话概括核心,那就是:在 RayCasting 游戏开发中,绘制动态视野边界线(FOV)最可靠的方式是在逻辑层通过数学公式将坐标“算”出来,而不是依赖 Canvas 绘图上下文的旋转操作。
在实现类似 Doom 风格的 RayCasting 游戏时,动态视野(Field of View, FOV)是一个关键的视觉元素。通常表现为从玩家视角出发、沿着角色朝向左右两侧展开的两条射线,模拟人眼或摄像机的可视锥形区域。然而,有一个常见的误区:直接调用 ctx.rotate() 虽然能快速旋转绘图坐标系,却不会更新原始几何数据。这样一来,后续的碰撞检测、光线投射或 UI 定位都会出现问题——因为它们依赖的坐标并没有真正改变。因此,坐标变换必须在逻辑层完成,不能只让渲染层“看起来正确”。
核心思路非常简洁:将立方体(例如玩家角色对应的方块)的局部顶点坐标,绕其中心点按照当前朝向角(弧度制)进行二维平面旋转变换。标准的旋转公式如下(以点 P(x,y) 绕中心 C(cx,cy) 逆时针旋转 θ 弧度为例):
function rotatePoint(point, center, angleRad) {
const dx = point.x - center.x;
const dy = point.y - center.y;
return {
x: center.x + dx * Math.cos(angleRad) - dy * Math.sin(angleRad),
y: center.y + dx * Math.sin(angleRad) + dy * Math.cos(angleRad)
};
}
假设玩家实体是一个宽高均为 size 的正方形,左上角位于 (this.x, this.y),那么它的四个顶点分别是:左上、右上、右下、左下。视野通常取自前向两侧的边缘,例如将右上角和左上角作为 FOV 的起始点(相当于“眼睛”位于顶部中点,视野张角由这两个点张开)。首先确定旋转中心——比如取顶部中点 cCenter = {x: this.x + size/2, y: this.y}——然后对两个关键顶点应用旋转函数:
const cCenter = { x: this.x + this.width / 2, y: this.y };
const rightTop = { x: this.x + this.width, y: this.y };
const leftTop = { x: this.x, y: this.y };
const rotatedRight = this.rotatePoint(rightTop, cCenter, this.radians());
const rotatedLeft = this.rotatePoint(leftTop, cCenter, this.radians());
// 绘制 FOV 射线:从中心出发,延伸至足够远(比如 300px)
const length = 300;
const fovRightX = cCenter.x + (rotatedRight.x - cCenter.x) * (length / Math.hypot(rotatedRight.x - cCenter.x, rotatedRight.y - cCenter.y));
const fovRightY = cCenter.y + (rotatedRight.y - cCenter.y) * (length / Math.hypot(rotatedRight.x - cCenter.x, rotatedRight.y - cCenter.y));
const fovLeftX = cCenter.x + (rotatedLeft.x - cCenter.x) * (length / Math.hypot(rotatedLeft.x - cCenter.x, rotatedLeft.y - cCenter.y));
const fovLeftY = cCenter.y + (rotatedLeft.y - cCenter.y) * (length / Math.hypot(rotatedLeft.x - cCenter.x, rotatedLeft.y - cCenter.y));
// 渲染
this.desenho.beginPath();
this.desenho.strokeStyle = "#4a90e2";
this.desenho.moveTo(cCenter.x, cCenter.y);
this.desenho.lineTo(fovRightX, fovRightY);
this.desenho.moveTo(cCenter.x, cCenter.y);
this.desenho.lineTo(fovLeftX, fovLeftY);
this.desenho.stroke();
有几个关键细节需要特别注意:
- 角度单位:
this.radians()必须返回弧度值。如果你存储的是角度,记得乘以Math.PI / 180进行转换。 - 逻辑与渲染解耦:所有坐标计算应在
draw()方法调用之前完成,确保逻辑层和渲染层各司其职,互不干扰。 - 更真实的 FOV:如果需要固定的张角(例如 60°),可以独立定义视角半角
fovHalf = Math.PI / 6,然后以cCenter为原点、this.radians()为基准方向,分别计算 ±fovHalf 方向的射线终点。这种方法不依赖模型顶点,更加灵活通用。 - 性能优化:若对性能敏感,建议预缓存
Math.cos和Math.sin的值,避免每帧重复计算,提升渲染效率。
通过手动执行坐标旋转,你不仅获得了可预测、易调试的 FOV 几何数据,还为后续的光线投射、碰撞检测以及 HUD 对齐奠定了坚实的数据基础。归根结底,这才是 RayCasting 游戏底层可控性的关键所在。
游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。
同类文章
如何在JavaScript中实现基于旋转视野的FOV射线绘制详解
如果用一句话概括核心,那就是:在 RayCasting 游戏开发中,绘制动态视野边界线(FOV)最可靠的方式是在逻辑层通过数学公式将坐标“算”出来,而不是依赖 Canvas 绘图上下文的旋转操作。 在实现类似 Doom 风格的 RayCasting 游戏时,动态视野(Field of View, F
TypeScript后端数据正确映射为前端接口类型的方法
在后端数据与前端类型之间来回转换,几乎是每位 TypeScript 开发者都无法回避的常态。后端返回的 car_brand、reg_number,和前端接口中定义的 brand、govtNumber,命名风格常常对不上号。此时,如果为了省事直接用 as 类型断言“强行”指认类型,那就踩进了常见的陷阱
动态HTML表格按层级条件合并单元格的JavaScript实现
本文详细讲解一种递归式 JavaScript 合并单元格方法,用于按列优先级(如前3列)智能合并表格行:仅当前一列已合并的前提下,才允许后续列合并相同值,从而精准实现多级分组与层级表格合并效果。 在动态生成的 HTML 表格中,按业务逻辑合并重复行是常见需求。然而,简单地对单列分别遍历合并——例如先
Next.js 13+重定向后滚动失效解决方案
在 Next js App Router 的日常开发中,有一个令人颇为困扰的异常现象——当服务端执行 `redirect()` 跳转后,目标页面竟然无法正常滚动。没错,页面已经渲染完成,内容也完整显示,但垂直滚动条仿佛凭空消失。这个问题在 Next js 13 5 4 版本中尤为突出。 先给出结论:
WebGL图像加载延迟的纹理初始化时立即显示方法
本文详细介绍如何利用 Promise 与 async await 重构 WebGL 纹理加载流程,彻底解决首次渲染显示蓝色占位色、需要手动交互才能刷新的问题,实现文件导入后四张纹理平面即时正确渲染。 实际上,这个坑在 WebGL 开发中相当常见——纹理异步加载的小陷阱,说起来不大,但第一次遇到确实令
- 日榜
- 周榜
- 月榜
相关攻略
2026-07-01 07:01
2026-07-01 07:01
2026-07-01 07:00
2026-07-01 07:00
2026-07-01 07:00
2026-07-01 07:00
2026-07-01 06:59
2026-07-01 06:59
热门教程
- 游戏攻略
- 安卓教程
- 苹果教程
- 电脑教程
热门话题

