在Cocos2d-x中实现较为真实的云彩效果
【前言】
这个效果是公司里上一个项目中用到的。因为项目已经死掉了,并且效果是我自己实现的,与其连着项目工程一起删掉,不如所以共产主义一下给大家作参考。
使用版本:cocos 2d-x 3.6(适用于所有3.x版本,稍作改动亦适用于2.x版本)
有时候我们需要在游戏的某些场景加入这样的效果:大地图上没有开拓的区域使用云遮挡,已开拓的部分则没有云(战阵迷雾效果),或者纯粹用云彩作为一些装饰。
一些网站上讲了一种使用瓦片地图的方式制作,比如:http://blog.csdn.net/musicvs/article/details/8760937。看了看实现挺复杂的,而且效果看起来也不太自然。如果是做地表的贴图比如草丛还行,做云雾的话就大材小用了。
所以我设计了另一种简单粗暴的实现模式,最后可以达到这样的效果:
原理其实非常简单,就是用四张不同的云彩的贴图拼接出来,和瓦片地图类似,但是没有复杂的算法。
【所需资源】
所需的资源就是这四张云的贴图(也可以用三张五张六张或者更多)和一张背景了:
云的贴图实际上带有透明通道,为了能看见加上了一个灰色背景。美术制作贴图的时候应当避免贴图被图像边缘裁剪,不要留下所谓的“硬边”。
*场景由公司主美独家授权使用所以请勿用于别处(
【实现思路】
前面之所以说和瓦片地图类似,是因为如果我们把云贴图按照铺砖块的方式排列的话,由于贴图边缘有透明的像素,会变成这样的效果:
所以为了做到看起来比较自然的效果,贴图与贴图之间是有相互重叠的。简单地说就是排列的时候贴图与贴图之间的间距应当小于贴图自身的长宽。而少多少就取决于贴图本身了,应当多次尝试最后取一个合适的值。以我使用的资源为例,我使用256px × 256px的贴图,间距值取96px。
【实现代码】
剩下的事就是用程序来实现了。用一个二维数组来存放所有的云块。进行填充的时候,应当使用随机数决定使用哪个贴图,可以让显示更自然。
同时留出一个接口用于控制云块的现实与否,很简单:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | #ifndef _CLOUDLAYER_H_ #define _CLOUDLAYER_H_ #include "cocos2d.h" USING_NS_CC; #define MAX_CLOUD_ROW 8 #define MAX_CLOUD_COL 11 class CloudLayer : public Layer { public : CREATE_FUNC(CloudLayer); void SetCloudShow( int pRowIndex, int pColIndex, bool pIsShow); public : ~CloudLayer(){} private : CloudLayer(){} private : bool init(); private : Sprite* m_BlockMatrix[MAX_CLOUD_COL][MAX_CLOUD_ROW]; }; #endif |
实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | #include "CloudLayer.h" #define BLOCK_WIDTH 96 bool CloudLayer::init() { if (!Layer::init()) { return false ; } for ( int i = 0; i < MAX_CLOUD_ROW; i++) { for ( int j = 0; j < MAX_CLOUD_COL; j++) { Sprite* cloudBlock; switch (( int )(CCRANDOM_0_1() * 4)) { case 1: cloudBlock = Sprite::create( "cloud1.png" ); break ; case 2: cloudBlock = Sprite::create( "cloud2.png" ); break ; case 3: cloudBlock = Sprite::create( "cloud3.png" ); break ; default : cloudBlock = Sprite::create( "cloud4.png" ); break ; } cloudBlock->setPosition(j * BLOCK_WIDTH, i * BLOCK_WIDTH); this ->addChild(cloudBlock); this ->m_BlockMatrix[j][i] = cloudBlock; } } return true ; } void CloudLayer::SetCloudShow( int pRowIndex, int pColIndex, bool pIsShow) { CC_ASSERT(pRowIndex < MAX_CLOUD_ROW && pColIndex < MAX_CLOUD_COL); auto cloudBlock = this ->m_BlockMatrix[pColIndex][pRowIndex]; if (pIsShow) { cloudBlock->runAction(FadeIn::create(1.5f)); } else { cloudBlock->runAction(FadeOut::create(1.5f)); } } |
然后在场景中加入云彩:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | bool HelloWorld::init() { if ( !Layer::init() ) { return false ; } Size visibleSize = Director::getInstance()->getVisibleSize(); Vec2 origin = Director::getInstance()->getVisibleOrigin(); auto bg = Sprite::create( "bg.jpg" ); bg->setPosition(Vec2( origin.x + visibleSize.width / 2, origin.y + visibleSize.height / 2)); this ->addChild(bg); auto cl = CloudLayer::create(); this ->addChild(cl); // 设置一部分云彩不显示 // for ( int i = 2; i < 6; i++) { for ( int j = 3; j < 8; j++) { cl->SetCloudShow(i, j, false ); } } return true ; } |
只要合理控制云块的显示,可以做出更加漂亮的效果。其他效果就留给读者自己开脑洞去实现了,比如给云块编组,按组移动做云飘的效果。
【后记】
最近确实有点懒散了,博文也没怎么更,从现在开始写谱面编辑器的制作吧,自己挖的坑流着泪也要填完
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端