本文编译自 NCASE(Nicky Case)的教程,针对本站页面做了部分修改。基本上保证了原文的内容,在文章最后附有原文链接。这款游戏全面开源,采用 JavaScript 编写,所以文中的代码均也以 JavaScript 为基础。
注意:由于引入多个页面,本文在移动设备上的阅读可能有问题
今天,我要介绍大家制作如下这个效果:
(请在下面的区域内移动鼠标,如果没有反应请点击一下该区域再尝试)
这个效果被用在了我最新的开源游戏 Nothing To Hide 里面。您可能知道,有不少游戏都有类似的效果,比如《摩纳哥:你的就是我的(Monaco: What’s Yours Is Mine)》、《爆破杰克(Dynamite Jack)》以及《史莱姆吉什(Gish)》等……说不定也会出现在你的游戏中!
我会将自己的实现步骤以及在开发过程中犯过的错误展示出来。首先,是一些预热的内容,下面的演示展示了绘制一些线段并且跟踪鼠标的位置。(提示:一个方形由四条线段组成,以此类推)
接下来是比较数学的一部分。别担心,只是回忆一下之前学过的代数。
我们需要找到视线(也可以是光线,我们用视线来统一代替)和这些线段之间最近的交点。任何一条线都可以这样来表示: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 的效果有很强的可扩展性,如果应用得当,加上好的创意,可以大大增强你的游戏的吸引力!
这个主意真的很酷,实现起来没有太难,最重要的是,作者的demonstration(效果展示)做得也非常棒,很容易懂!
喔,这个感觉真是好棒啊!
看着挺容易的,其实不容易想到,倒是没有什么特别复杂的算法,思路才是最重要的。
感谢作者分享。
超级棒的文章!
it's cool!!
万分感谢~从端点发射这个思路好~www
感谢作者的思路分享
非常棒的文章,演示效果非常棒。
unity的3d项目要怎么实现这种效果