视线和光线:如何创建 2D 视觉范围效果

作者:indienova
2014-03-13
62 113 9

本文编译自 Nicky Case)的教程,针对本站页面做了部分修改。基本上保证了原文的内容,在文章最后附有原文链接。这款游戏全面开源,采用 JavaScript 编写,所以文中的代码均也以 JavaScript 为基础。

注意:由于引入多个页面,本文在移动设备上的阅读可能有问题

今天,我要介绍大家制作如下这个效果:
(请在下面的区域内移动鼠标,如果没有反应请点击一下该区域再尝试)

这个效果被用在了我最新的开源游戏 Nothing To Hide 里面。您可能知道,有不少游戏都有类似的效果,比如《摩纳哥:你的就是我的(Monaco: What’s Yours Is Mine)》、《爆破杰克(Dynamite Jack)》以及《史莱姆吉什(Gish)》等……说不定也会出现在你的游戏中!

games

我会将自己的实现步骤以及在开发过程中犯过的错误展示出来。首先,是一些预热的内容,下面的演示展示了绘制一些线段并且跟踪鼠标的位置。(提示:一个方形由四条线段组成,以此类推)

接下来是比较数学的一部分。别担心,只是回忆一下之前学过的代数。

我们需要找到视线(也可以是光线,我们用视线来统一代替)和这些线段之间最近的交点。任何一条线都可以这样来表示:Point + Direction * T

这样,我们就可以得到关于视线和线段的四个等式。

Ray X = r_px + r_dx * T1
Ray Y = r_py + r_dy * T1
Segment X = s_px + s_dx * T2
Segment Y = s_py + s_dy * T2

注意:在我们开始之前,要注意检查视线和相对应的线段是否平行,也就是方向是否相同。如果平行,就没有交点,不用处理。

如果它们(视线和相对应的线段)相交,那么交点的 X 和 Y 应该相等,也就是:

r_px + r_dx * T1 = s_px + s_dx * T2
r_py + r_dy * T1 = s_py + s_dy * T2

我们将用下面的方法取得 T1 和 T2

// 从等式中取得 T1,然后忽略掉 T1
T1 = (s_px+s_dx*T2-r_px)/r_dx = (s_py+s_dy*T2-r_py)/r_dy

// 两边都乘以 r_dx * r_dy
s_px*r_dy + s_dx*T2*r_dy - r_px*r_dy = s_py*r_dx + s_dy*T2*r_dx - r_py*r_dx

// 解出 T2
T2 = (r_dx*(s_py-r_py) + r_dy*(r_px-s_px))/(s_dx*r_dy - s_dy*r_dx)

// 带入 T2 得到 T1
T1 = (s_px+s_dx*T2-r_px)/r_dx

要确保 T1>0 和 0

下面是看起来的样子:(请在下面的区域内移动鼠标)

很好,现在让我们发射出 50 条视线来:

然后,我想,我只要连接起这些交点来,就可以得到一个看起来不错的多边形,结果看起来是这样:

见鬼。就算我发出 360 条视线,也还是看起来不对劲儿。这个问题困扰了我半天,直到我意识到:我不用向所有方向发出视线,我只需要向每个线段的端点发出视线就可以。

针对每一条(不同的)线段的端点,我直接发出视线,另外增加两条偏移量为 +/- 0.00001 弧度的视线。这两条额外的视线用来去和线段后面的墙来相交。

接下来,我按照这些视线的角度将这些交点排序,这样我就可以简单的按照顺时针顺序将它们连接起来,可以绘制出一个看起来满意的多边形。

最后!看起来确实不错了。我又添加了一些效果,看起来就像下面这样,带有一些模糊的阴影效果。红点代表的是 11 个初始点——是的,11 个多边形。

最后,做了些改进,我放了两幅图。然后,将这两幅图混合,就成了我们在开始的时候看到的那个效果那样。

然后我又添加了额外的光源,就成了下面这样:

多光源、投射阴影、激光感应炸弹、显示你或者敌人的可视范围……这种 2D 的效果有很强的可扩展性,如果应用得当,加上好的创意,可以大大增强你的游戏的吸引力!

原文地址:http://ncase.github.io/sight-and-light/

近期点赞的会员

 分享这篇文章

indienova 

indienova - 独立精神 

您可能还会对这些文章感兴趣

参与此文章的讨论

  1. daichou03 2016-09-05

    这个主意真的很酷,实现起来没有太难,最重要的是,作者的demonstration(效果展示)做得也非常棒,很容易懂!

  2. Kayiet白糖 2016-09-21

    喔,这个感觉真是好棒啊!

  3. dearjy 2016-10-16

    看着挺容易的,其实不容易想到,倒是没有什么特别复杂的算法,思路才是最重要的。
    感谢作者分享。

  4. yukiandi 2017-02-11

    超级棒的文章!

  5. bigboss 2018-02-12 微信会员

    it's cool!!

  6. CyclohexaneC6H12 2018-10-31

    万分感谢~从端点发射这个思路好~www

  7. masterHx 2019-07-01

    感谢作者的思路分享

  8. anyue 2019-11-02

    非常棒的文章,演示效果非常棒。

  9. ForMxc 2020-08-30

    unity的3d项目要怎么实现这种效果

您需要登录或者注册后才能发表评论

登录/注册