Creator 3.7.x 引擎 "我的世界 "体素游戏的完整解决方案!
引言: 本文作者「董密」,他将介绍基于 Cocos Creator 3.7.0 引擎开发的《像素空间 3D》项目,干货满满,一起来看看。
大家好,我是董密!
目前正在找一份 Cocos Creator 的游戏开发工作。感谢晓衡哥的帮助和邀请,再次给大家做一点技术分享。
不过这次分享的内容会非常干,也非常丰富和有趣,包含大量的实机演示,建议收藏阅读。源码已上架,大家可以前往 Cocos Store 或 Cocos 官方微店进行下载。文末有特惠哟~
1、体素空间
2、地形随机
3、地图随机——平原、高山、雪山
4、体素物理——水中浮力与弹簧臂
5、NPC 和状态机——采集与战斗
6、背包系统——合成与熔炉
7、水流系统——湖泊与大海
8、光照系统——日照与天气
9、动态网格——火把道具
10、微信小游戏—— Worker 多线程
11、体素存储
12、其它要点
前言
22 年末,我参加了 Cocos 论坛的第五期征文活动,有幸凭借此作品获得了最终大奖:华为平板。晒一下第五期征文的奖品,哈哈哈????
再次感谢 Cocos 官方的认可,这让我产生一种无法抑制的冲动,誓必将《像素空间 3D》做成一个完整的游戏作品。
在此期间,我经历了多次重构优化、优化、再优化,真的是“朝发夕拾”。
游戏介绍
我制作的《像素空间 3D》参考了《我的世界》但目前包体仅 2.5M。
游戏中,实现了诸如地形随机、地图随机、体素物理、体素亮度、流水、合成、熔炉、战斗等等功能。
虽然相较于《我的世界》还缺少非常多的内容和功能,不过还是可以进行一番探索和生存了。
核心技术介绍
体素空间
我所理解的体素非常简单,就是给定任意一个坐标,对其进行 Math.floor 就可以获得其所在方块的坐标。以此建立起整个 3D 像素空间。
地形随机
地形随机用的是 NPM 里的一个柏林噪声函数(perlin-simplex),将其改成 TypeScript 形式进行使用。其可以进行 2D 和 3D 的随机,返回 -1 到 1 之间的渐变随机数,(r+1)*0.5 就可以返回 0~1。
地形的起伏用的是 Noise2D;矿洞、矿物的生成用的 Noise3D。
每构造一个噪声对象,需要传递一个随机对象,用来构造最初的随机数。
使用的是 Cocos 的 pseudoRandom 函数构造随机对象。只需要给一个世界种子即可。
世界种子基于某局游戏是一定的,所以就能保证每次进入都是相同的地形。
地图随机
游戏里主要使用了岛域的方式来划分地图,256 * 256 范围为 1 个岛域,每个岛域内是一组定义好的地貌。
岛域的随机是用 pseudoRandom 生成噪声二维数组来实现的,基于不同的世界种子,生成不同的数组。也能保证每次进入都是相同的岛域。
不过因为版本的变化,可能会增加不同的岛域地貌,所以缓存了已经修改过的岛域,没有修改过的岛域就会随着版本对地貌的影响而改变。
体素物理——水中浮力与弹簧臂
关于射线检测,之前版本使用的是八叉树来查找射线碰撞的方块。后来一想,不需要啊。虽然方块是多,但是都是均匀整齐排布的。
我使用了一种步进式的检测方法,步骤是由射线原点开始,查看是否处在空气块里,如果不是则直接返回。如果是,则用 Cocos 的 intersect.rayAABB 方法获得 aabb 内的射线距离射线方向最近面的距离。
然后将射线原点按照射线方向移动这么远的距离,然后步进一个非常小的数,然后再进行检测,直到返回找到,或者超出检测范围。
这样的话会省去非常多八叉树的创建和更新成本,检测性能也非常高!????
海、湖泊及流水
海是区块的表面高度到海平面的所有块会被设置为海水
湖泊是检测区块的最低点,然后用 BFS 查找空气区域
湖泊的水量是一定的,水会往空的块进行流动,水量为 1 的水无法流动。流动是在 worker 里每 1 秒一次执行当前区块的流水检测
海水的水量是无穷的,只要附近有空气块,就会被海水填满
水面的渲染是通过查询每个顶点周围的 4 个方块的水量求平均值,设置成块的渲染高度,最后还要乘以一个缩放,来让水面低于方块,看起来更真实一些
水下的效果是屏幕后处理,检测摄像机的位置是否有水,如果有则 shader 里乘上一定的蓝色
NPC和状态机
下面我介绍下游戏中的玩法功能,可以到我的 B 站号上看视频——杀羊取肉演示
目前生物 NPC 仅有羊和僵尸两种,不过也方便扩展。
NPC 现在分为三类:动物、怪物和特殊。动物现在就是羊,怪物现在就是僵尸,特殊现在就是船(对,我把船也变成了 NPC 目前看没啥不好的,等发现不适合了再说)。
现在设想的是所有动物公用 1 个材质和贴图,使用实例属性来设置材质偏移。怪物也是,特殊 NPC 也是。
写了一个简单的注册状态机。每个动物自己注册想要的状态,比如闲呆,巡逻,逃跑,被击,死亡。注册状态时配置相关参数,然后每帧执行当前状态的逻辑,并判断是否结束跳到下一个状态。
B 站视频—— AK47 打僵尸的
背包、合成、熔炉
游戏中地图探索,资源收集与合成,是游戏最为重要的玩法内容部。