【Cocos2d-x】视线和光线:如何创建 2D 视觉范围效果

云里来.雾里去2014-10-20 12:10:383557 次阅读

Android客户端下载:sight_and_light-debug.rar

以下翻译转载自:indienova

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

注意:手机浏览可能会不能加载内嵌网页

今天,我要介绍大家制作如下这个效果:(鼠标移动可看不同效果,可在原文中尝试交互效果)

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

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

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

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

1
Point + Direction * T

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

1
2
3
4
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 应该相等,也就是:

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

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

1
2
3
4
5
6
7
8
9
10
11
// Isolate T1 for both equations, getting rid of T1
T1 = (s_px+s_dx*T2-r_px)/r_dx = (s_py+s_dy*T2-r_py)/r_dy
// Multiply both sides by 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
// Solve for T2!
T2 = (r_dx*(s_py-r_py) + r_dy*(r_px-s_px))/(s_dx*r_dy - s_dy*r_dx)
// Plug the value of T2 to get T1
T1 = (s_px+s_dx*T2-r_px)/r_dx

要确保 T1>0 和 0<T2<1。如果不是这样,那么预计中的交点并不在视线或者线段上,其实也就是无交点。如果由交点,那很好!你找到一个交点。现在用同样一条视线和所有线段计算,以便找到最近的交点(应该是 T1 值最小的那个)。

下面是看起来的样子:(移动鼠标的效果)

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

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

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

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

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

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

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

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

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

Cocos2d-x实现过程

这个效果最初是在indienova看到的相关介绍,于是就开始琢磨如何在Cocos2d-x中实现这个效果。

第一次尝试:

这个效果是由 背景图(骷髅)和前景(美女)图 叠加形成的,在光线变动的情况下背景保持不变,而前景根据光线的明暗相应的显示对应部分的明暗度,而没有被光线照射到的地方隐藏掉。

首先想到的自然是 DrawNode 绘画出光照射到的多边形区域,然后用ClippingNode 设置DrawNode 为模板来绘制前景图。

但是从效果中可以看出影子中还会区分透明度,越偏离视线的方向的光线越暗,并与前景叠加,前景被分成了几个层次的透明度。

ClippingNode在绘制模板的时候会把模板扣抠掉,如果可以保留模板的绘制的话,就可以将前景与模板的颜色做blend处理,形成多层次透明度。

查阅 ClippingNode 代码,发现ClippingNode在做模板设置的时候设置了 模板测试 从不通过,所以模板怎么都不会被绘制出来。

1
2
glStencilFunc(GL_NEVER, mask_layer, mask_layer);
glStencilOp(!_inverted ? GL_REPLACE : GL_ZERO, GL_KEEP, GL_KEEP);

可以修改为:

1
2
glStencilFunc(GL_GEQUAL, mask_layer, mask_layer);
glStencilOp(GL_KEEP, GL_KEEP, !_inverted ? GL_REPLACE : GL_ZERO);

然后设置前景的blend func 为:

1
2
3
auto fore = Sprite::create("foreground.png");
BlendFunc func = {GL_DST_COLOR, GL_NONE};
fore->setBlendFunc(func);

此时测试模板和前景是能很好的叠加效果的。

但是接下来使用DrawNode绘制多边形的时候却出现了问题,DrawNode对于处理复杂多边形并不能胜任,画出来的形状都是乱飞的。

第二次尝试:

这次尝试了使用了 前一篇文章 介绍的nanovg 来绘制多边形,首先建了个NvgNode,重载draw 里面写绘制函数,将这个node作为模板,最后发现新问题:

1.nanovg 绘制的效率比较低,简单测试同为使用多边形填充整个屏幕,nanovg 30帧,DrawNode 60帧,差的还是比较多。

2.nanovg 处理多边形是 也是 使用 模板来处理 填充颜色,修改了一番还是不能够很好的和cocos结合,没有再往深处继续研究。

第三次尝试:

这次还是回到了DrawNode上,对于opengl 绘制 复杂多边形上进行资料搜索。

看到几种解决方案(参考):

第一种解决方案:多边形网格化法

对于非简单多边形、非凸多边形或有洞的多边形,OpenGL在GLU库中提供了一个多边形网格化对象GLUtesselator,对多边形进行网格化————将它们分解成一组简单的、能够进行渲染的OpenGL多边形。

经测试这种方法对凹凸多边形和自交、带孔多边形都能正确的渲染。

第二种解决方案:模板缓冲法stencil Buffer

可以参考nanovg中的实现方法

第三种解决方案: 凹多边形凸分解法

思路: 使用算法将凹多边形分解为多个凸多边形或一系列的三角形,然后进行渲染。

这里 列出了许多三角形划分多边形算法的实现,这里选了一个比较靠谱的  Triangulate 来使用。

将最后输出的多边形分解为三角形后调用DrawNode::drawTriangle 来绘制,成功!

项目地址: https://github.com/2youyouo2/sight_and_night

来源网址:http://cocokele.com/sight-and-light/

【Cocos2d-x】视线和光线:如何创建 2D 视觉范围效果相关推荐

  1. Unity 创建2D平台游戏开发学习教程

    了解如何使用C#在Unity中创建您的第一款2D平台游戏 你会学到什么 使用Unity创建2D奥运会 使用可脚本化的对象和单一模式 使用良好的编程实践 创造武器和射弹 使用可脚本化的对象和委托模式创建 ...

  2. Unity 2021创建2D休闲点击器游戏视频教程

    Unity 2021创建2D休闲点击器游戏视频教程 Learn how to create a 2D Idle Clicker Game in Unity 2021 了解如何在Unity 2021中创 ...

  3. arcade 物理系统_如何使用Python和Arcade库创建2D游戏

    arcade 物理系统 对于那些学习编程的人来说, Python是一种出色的语言,它对于想要"完成工作"并且不花很多时间在样板代码上的人来说是完美的语言. Arcade是一个用于创 ...

  4. NGUI使用教程(2) 使用NGUI创建2D场景而且加入标签和button

    1.创建2D场景 要使用NGUI创建2D场景,首先咱们必须新建一个项目,而且导入NGUI作为这个项目的插件,相信假设看过上一篇教程都知道怎么导入NGUI了,这里就不赘述,假设有疑问的能够去看上一篇教程 ...

  5. 利用Unity插件Anima2D创建2D骨骼动画

    利用Unity插件Anima2D创建2D骨骼动画 创建步骤 导入Anima2D插件 准备2D素材 配置2D骨骼 对2D角色应用IK(反向动力学) 利用Animation创建2D人物动画 创建步骤 导入 ...

  6. 三维地图前端arcgis_通过ArcGIS创建2D及3D地图

    前端开发中,GIS的用途很明确,就是用来做地图.你对地图的操作,不管是图形的绘制还是实体的添加都是在基础地图之上.本文将向你讲诉如何使用GIS创建基础地图以一些API的使用. 前提 在编写代码之前先简 ...

  7. Unity ShaderLab特效教程 适用于贴图、sprite和ugui的2d着色器实例 代码+详解注释 【2d流光边框效果】

    如果代码中有什么不清楚请查看以下基础知识 Shader基础知识 unity3d 中 七种坐标知识详解 2d流光边框效果 可以自定义边框的高和宽,流光尺寸和速度以及中心点 笑狗图: 代码 Shader ...

  8. 在Blender中创建真实的汽车CGI视觉动画效果

    Blender VFX Tutorial Rig & Animate a Realistic Car in Real 大小:1.18G 时长1h 包含项目文件 1280X720 MP4 语言: ...

  9. 自定义动画属性java_创建酷炫动画效果的10个JavaScript库

    原标题:创建酷炫动画效果的10个JavaScript库 1) Dynamics.jsDynamics.js是设计基于物理规律的动画的重要Java库.它可以赋予生命给所有包含CSS 和SVG属性的DOM ...

最新文章

  1. MySQL创建用户(CREATE USER)
  2. 感悟:微博深度学习平台架构和实践
  3. json mysql乱码问题_JSON数据乱码问题
  4. vsftpd.conf配置范例
  5. 网卡重启影响nfs吗_NFS网络储存系统
  6. 数据结构区间问题总结
  7. excel npoi 连接_Asp.Net使用Npoi导入导出Excel的方法
  8. 让刺猬和狐狸结婚:资本巨鳄BlackRock的金融科技野心
  9. java项目实战之404错误原因总结
  10. Dynamics CRM 365 - 零基础入门学习后端插件的调试方法
  11. 在AIX环境下实施Oracle 集群RAC的结构 文平
  12. IOl:从文件夹中找到后缀名为TXT的文件,然后复制到指定的文件夹
  13. 2022年最值得阅读的强化学习书籍
  14. php公众号解决投票刷票,微信公众号投票活动如何防止刷票现象
  15. 【魔方攻略】SQ1魔方教程(原创)
  16. Web3世界的入口Wallet使用指南
  17. PPT制作(文字排版)
  18. SVPWM的一些理解
  19. 关于端口1433连接失败问题
  20. 一起谈.NET技术,.NET十年(下)

热门文章

  1. 2015桐庐年会--奔跑吧,骚年
  2. 文件压缩支付加密方式
  3. 驱动以SN码获取流程定制Barcode属性
  4. 【python练习题3】英雄联盟英雄购买界面+数字炸弹游戏
  5. 用户画像(profile v.s. persona)
  6. 基于Go语言GoFrame+Vue+ElementUI实现的权限控制系统
  7. 慧算账解读新《代理记账管理办法》
  8. 有容云:微服务容器化的挑战和解决之道
  9. 【TS】1010- 细数 10 个 TypeScript 奇怪的符号
  10. 随意发表见解易成无效表达