割草demo 第二期 合批shader(受击、内发光、消融) 受击击退 四叉树

割草demo第二期,第二期朋友们!!!
先上效果:
Cocos Creator - snake02 - Google Chrome 2023-04-04 17-50-37
这期主要实现了这几项:
0 > 增加一个类似贪吃蛇的移动方式
1 > RVO控制的基础上,增加怪物受击回退的功能
2 > 利用四叉树,减少碰撞检测的检测对象。
3 > 实现受击闪白、内发光、消融shader。
<有没有人问为什么标签要从0开始呀?>

<贪吃蛇平滑移动>
首先类似贪吃蛇的移动方式,是参考了网上一的文章,本质上是记录蛇头的位置,以及走过的路径。同时每个蛇身从记录的坐标中根据相应的偏移来获取对应的坐标。
大佬原文链接在此:《Cocos Creator游戏实战》贪吃蛇平滑移动 - 知乎
由于篇幅问题就不贴具体代码了,demo和上面的链接里有详细介绍,有兴趣的朋友可以了解下。

<在RVO基础上实现受击击退>
首先在上一节提到,我们并不实际的计算怪物的方位,而是给予怪物线速度经由RVO的计算后在获取对应的position。也就是simulator.instance.run()。可是我们依旧能较直观的控制怪物不停的追踪主角所在的方位。利用setAgentPrefVelocity()。那么理论上来说,通过短时间将这个期望的线速度进行反向,然后乘以力的系数就能达到我们的预期。
接下来着手去尝试…



临时增加了受击状态、持续时间、冷却时间以及受击力量。
然后在设置追踪玩家的线速度之前,判断是否在受击状态中,如果是则采取相反的方向并且和衰减的力量进行计算。
这里时间十分短暂的表现并没有完全利用物理规则去模拟力量的衰减,而是简单采取了和时间线性相关的衰减方式。
表现如下:
Cocos Creator - snake02 - Google Chrome 2023-04-04 18-23-33
暂时看上去还是OK的。更多的表现和细节还要后续加上各种奇奇怪怪的武器技能才能确定。

<四叉树优化碰撞>
这个话题老生常谈了,特别是弹幕游戏中会经常使用。
原理是每帧将怪物不停的分化到四叉树的数据结构中(如果不是经常移动的对象,或者是纯粹的静态对象,四叉树并不需要重建的那么频繁
然后当要进行碰撞检测的时候,会优先用四叉树的节点去和碰撞范围做检测,筛选出有可能发生碰撞的区域,并且返回这个区域里记录的节点。
具体应用的位置代码如下:
进行四叉树的建立,以及所有当前怪物的插入。
这里还有不少优化空间,比如只筛选在屏幕内,或者比屏幕稍大一点的范围的怪物放入四叉树中,当然这也和游戏设计有关,如果屏幕外的怪物也很可能收到攻击的话那就不用考虑这么多了。


然后再攻击的时候,从四叉树中获取到需要检测的树节点从而获取树节点下记录的怪物节点。

这里毕竟是临时效果,我直接使用的蛇头位置(稍稍放大一点)的矩形区域。getTmpAttBox()

四叉树的建立过程大致如下:
image
树节点只进行了分化层级和当前树节点Rect的记录。
在插入待检测rect的时候,进行判断,如果当前树节点已经分化成四个区域,则判断对象应该在哪几个方位(象限)并且记录在对应的子节点中。
否则存入当前的节点树,并且进行下一步检测->如果当前未分化,并且还足以进行下一次分化,同时当前的节点树已经存满了节点。则进行下一次分化,并且计算方位保存。

如果还有细节不太理解的,可以参考下面两个链接:
一个是白老板的详解,一个是B站的视频解说,一定要比我这光秃秃的代码好接受。

  1. 四叉树与碰撞检测 !Cocos Creator ! - 白玉无冰 - 博客园 (cnblogs.com)
  2. 【数学之美】四叉树模型的构造和应用_哔哩哔哩_bilibili

<受击、消融等shader>
可能有用心的盆友发现了,在文章最开始那个动图中,dc已经接近200+并且还在不规则的增加。
没错…是我这个shader小白导致的合批被疯狂打断。
经过一些资料的查阅。getMaterialInstance()本身会打断合批。与此同时使用setProperty修改uniform中的值也会打断合批。这就头疼了,shader中的好几个效果都依托自定义的uniform参数变化来实现。虽然效果简单,但也是一番心血不是?于是陷入了抓耳挠腮上蹿下跳的状态中。
这时感谢两篇帖子的帮助…

  1. 【分享】自定义渲染合批之自定义顶点格式(附 Demo 和引擎源码解读) - Creator 2.x - Cocos中文社区
  2. CocosCreator受击闪白效果 可合批 - 知乎 (zhihu.com)
    不出意外的话,第一种方式创建自定义 assembler 通过修改顶点着色器进入渲染管线前的数据才是正统并且泛用性比较高的方式,不过…笔者暂时还是用的第二种方式,当前的需求中实现起来较为简单,后续有时间,会再次尝试用第一种方式解决合批的问题。
    至于链接2里提到的方式,是使用v_color中的alpha通道代替自己想要实现的功能控制。相对应的,也会屏蔽掉原本的v_color.a的功能。
    借用这种思路,笔者用v_color.a执行闪白进度的控制,v_color.g实现消融的进度控制(消融的过渡色直接定义在了shader内部)v_color.r实现是否使用蓝色内置光(冰冻效果)。
    不过这种方式局限性不小,只是一种临时取巧的做法。
    另外在做消融处理的时候也尝试过另外一种降低打断合批副作用的思路,提前将一批要进入消融阶段的怪物怪物的层级置为0(在父节点中的渲染顺序)。这样虽然这一批怪物依旧是会打断合批,拥有单独的dc,但是却不会对下面的其他的怪物节点带来影响,而且从设计上来说割草的怪物,进入死亡状态被其他怪物遮挡也是符合游戏设计的。
    不过依旧是局限性很大的一种方法,只是作为一种思路提出,并不提倡使用哈。
    至于测试和控制播放闪白,蓝色内发光,以及消融的代码都整合在monsterEffectCtl中。
    shader中的效果并没有什么高深内容,还在学习中。各位看客有兴趣可以查看:

    处理后的dc已经恢复到第一期的状态。结果如图:
    Cocos Creator - snake02 和另外 17 个页面 - 用户配置 1 - Microsoft_ Edge 2023-04-04 21-58-18

至此第二期分享结束,感谢各位大佬花费的时间,希望不是浪费各位的光阴。demo也会免费开源官方市场,等到过审再补充上来。

第三期暂定目标,闪电链(还不确定用graphic+shader还是直接用uv动画),触屏反弹的投射物(子弹)
不过这一期可能要间隔一些时间,最近似乎要开始强制加班了= =不知道业余时间还能挤压出多少。

34赞

太强了,给大佬顶下帖

没有没有,共勉共勉。都是巨人披荆斩棘,我跟着匍匐前行。

如果单材质这么写,尽量不要用if 和discard,可以使用 step 和混合,或者step和乘颜色去处理这些效果

(a.b< v_color.g || a.r<v_color.g || o.g<v_color.g){
discard}

float disFactor = 1.0
disFactor *=step(a.b, v_color.g) * step(a.r, v_color.g) * step(a.g, v_color.g);
disFactor *=step(v_color.g,0.1) * step(o.b,v_color.g+0.1);
o.rgb = mix(o.rgb, vec3(.6,.2,.1), disFactor);

5赞

哇!二喵哥! 小弟shader才半只脚入门,谢谢大兄弟指点!是出于性能上的考量不?

是的PC上的现代GPU不怎么用考虑,

手机大部分Gpu效率低很多,可能会有分支
即使一个像素也会走完

image

discard 也严重影响性能,除了不得不 testalpha,比如opaque模式的树叶这些。。尽量少用

4赞

嗯嗯,多谢大哥指教,这方面我再查点资料,现在只能片面理解。

还有个优化的,比如多个材质,尽量提取相同部分做chunk,尽量少用宏去做材质的变种,减少编译时间,像自定义材质,use_local use_pixel_allign use_rt 这些都可以去掉,减少编译时间,宏多了变种就多,编译就慢

1赞

mark 一下 啊

mark 一下 啊

受教了,大佬

大佬,demo地址上了吗

mark!!!

不好意思啊 好像没通过,我今晚再申请下。最近太忙了。通过第一时间发出来哈。

不如,来个GitHub :yum:

markmarkmark

1赞

好主意…我把二喵那边提出的shader优化弄一下就放git得了

大佬,上商店了吗 :blush:

如果使用rvo2 c++版本, 编译成wasm, 效率会不会更高, 目标平台微信小程序

这要被福州的小游戏公司学了。又是一款流量小游戏。