用 Cocos Creator 做一个物理画线游戏!支持 UGC 关卡创作和微信关卡分享

2024-01-09 08:30

本文主要是介绍用 Cocos Creator 做一个物理画线游戏!支持 UGC 关卡创作和微信关卡分享,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

引言:在 3D 跑酷游戏和 3D 三消游戏之后,本次孙二喵带来了一个 2D 物理画线游戏源码,使用 Cocos Creator 3.6.2 开发。源码见文末。

7380f7d1bfa90ea5f039a275e669f1b5.gif

演示效果

物理画线是一种比较经典的 2D 游戏玩法,这几年也出了一系列的爆款产品。本文将从立项、游戏逻辑和具体功能点的实现,来讲解如何基于 Cocos Creator 3.x 开发一款物理画线游戏,并实现 UGC 关卡创作和微信关卡分享。

立项与准备

游戏立项

游戏的核心玩法是玩家通过画线保护自己的小鸡,让其免受黑洞中掉下的障碍小鸡、或地图上的其他障碍伤害。

69f65d4bc107be8144d8cd817261bb8f.jpeg

游戏关卡

考虑到制作成本,游戏美术使用了简单的手绘风格,用 paletton 选择类似纸张的颜色,拖动色盘,把比较顺眼的方案保存起来,确定游戏整体的风格。

2a38e63b33b3f16f11c409da5fb940e2.jpeg

色板中用到的颜色统一可以使用圆角矩形缩到最小(比如 15px,就输出成 15+15+2=32px,预留2个 px 给九宫格拉伸用),游戏所有的 UI 框架加起来就只有几 KB,减少显存的同时,还可以提高加载速度。

6ecec98d005956e5bc02437d3711fced.jpeg

考虑到 spine 专业版数千元的价格,游戏内的动画效果统一使用了 Cocos 内置的动画编辑器+序列帧动画。序列帧动画使用 PS 制作,在画好我们的角色后,PS 内复制数个分组,调整角色的五官,输出序列帧,一些相似的做了剔除,减少动画的体积占用。

6ad8cc15c63ff68de5e4a213ea3eae03.jpeg

在 Cocos 内制作序列帧动画比较简单。帧动画使用30帧,新建好动画,并在精灵上面创建好动画组件,在对应的关键帧替换图片即可。

80be5c227d44f7012d8b52cb972ff358.jpeg

制作好的序列帧动画无需进行合并,拖入到一个文件夹内,使用 Cocos 自带的自动图集打包即可。

cb8d3925cf7feef5eecc3dd66153e074.jpeg

自定义网格背景

考虑到游戏的背景是一个纸上世界、同时需要支持 UGC 和简单的 AI,我们需要一个图片背景+网格。然而使用图片背景+网格图片不够灵活,同时做出来的效果会比较死板,缺少随机性,因此我从 shadertoy 上移植了一个纸张网格的效果。

原 shader 的 for 循环比较多,且风格比较写实,这里进行了一定的简化。

c1f33cbc54300ced6f9fd928fa9767ff.jpeg

这里把 shader 中常用的属性都进行了暴露,整体风格调整到和色卡一致。

c23ac73571b128fb6d2fa027215949c5.jpeg

游戏内的3个场景(游戏界面、游戏内、游戏编辑)都用到了这个 shader 的图片作为背景,这里使用精灵图自带的颜色 a_color 来控制网格颜色。

11fccb941201dcf9bf5e8097be68e63d.jpeg

并使用了简单的脚本接受全局事件,可以修改网格的颜色(这里只修改了透明度)。

78d74b652286a53a396d1d9cd8818fe7.jpeg

效果如下:

0932bf28f02b367f685f4ca2baa6a351.gif

考虑到游戏的 UGC 地图编辑需要使用到格子,Astar 网格导航也需要。以图片的视觉方向为例,下图左是在 shader 里 uv 的 xy 方向,下图右是 astar 算法的格子序号从小到大。

ea8bb17411384212e85c31442d789c9b.jpeg

所以我们需要在 shader 里对格子进行转换。

604798948c0a3c74227c210d78d23b59.jpeg

同时考虑到算法简单,这里不做屏幕分辨率的适配了,默认的设计分辨率是 750x1334,支持的最大显示高度是 750x2.2倍=1650(绝大多数全面屏手机的最大高度)。

uv 统一后,我们需要设置一下网格显示,默认黄色是安全区域坐标,表示可以放置物体或者有物体,红色是危险区域,表示不可以放置物体。

a54fbfa1b007d0b7b4e014a4e5cc77a3.jpeg

定义好颜色和颜色的顺序,在 shader 中使用简单的 aabb 四个方向进行判断,在范围内的就会把颜色改成黄色安全色或者红色警告色。

56749dc4801da5b380b55685e122048e.jpeg

同时 shader 把 worley 褶皱效果也加进材质的宏里,方便自定义开关。

36d85dd7515aa2d338f8379d68356d14.jpeg

如果需要使用自己的图片作为背景,可以打开 Use_Texture 的宏,使用 750x1650 的背景拖即可。

有了上述的准备工作,我们就可以开始地图编辑器的制作了。

地图编辑

在地图编辑之前,我们先确定整体的网格大小为75像素,设计的最大分辨率是 750x1650,也就是 10x22 个格子,这里定义一个全局的 class 去记录下这些配置。

272cb781a1e80b5d4bab129dec659a82.jpeg

每个物品的格子数量,可以用物体的图片长和宽分别除以75,然后四舍五入。

bce26cf66e915e9975e29464049d53a3.jpeg

如尖刺,是 60x148 分辨率,正好是 1*2 个格子

这部分数据我们在初始化物体时候会提前处理,避免重复计算。

fcff2e93451ebdd6f0ac26acf2596e6b.jpeg

接下来根据格子的奇数或者偶数决定落点的位置,可以分为 x 和 y 两周轴向分开处理。

如果是偶数就不需要做偏移,在格子中间落点即可,如果是奇数,需要偏移1个格子单位,同时偶数的格子用 Math.floor 求最小的整数格子,奇数用 Math.round 四舍五入求最近的格子。

e7666b0c081342b7b27471b0bdf01ca4.jpeg

检测上使用了 map 做查询,当检测到数据时候我们要把有碰撞的格子范围乘0.1,这样格子的 x 范围从 0-10,变成了 0-1,y 范围从 0-22,变成了 0-2.2,正好和我们 shader 的 uv 对应(shader 内部对原始的 uv.y 也乘了2.2,并不是 0-1了)。

3eac7e1e27db8c407b553e9090a30728.jpeg

当我们检测到碰撞体时候,当前物体的周围就会变红,存在碰撞体的周围位置会表黄。

游戏内定义了几种物体的名字的枚举,当他们的名字一致时候,初始化时候就会标记为是画线工具,删除工具或者旋转工具,当使用这些工具检测到结果时候,就会对选中物体标亮并进行对应操作。

当保存关卡时候,我们只需要记录物件的格子开始和结束范围,也就是之前 map 保存的数据,同时记录物件的 scale.x 和 scale.y 记录左右和上下方向的旋转,保存为 json 数据,再把 json 数据 Stringify 即可。

3571f7a271243066216eb4e42210090d.jpeg

在地图编辑器和游戏内读取关卡都采用相同的逻辑,如果是 runtime 时候,我们会顺便初始化一下 Astar Graph 里的网格权重。

5d09ad29263c64d21eabbadd2bee1a69.jpeg

这样即便是在复杂的关卡中,障碍小鸡也可以精准定位我们的游戏角色。

513691a5ac2e4acfc84ad01a3119c36b.gif

玩法核心逻辑

画线算法

下面介绍游戏的核心逻辑部分。

游戏的核心逻辑是使用 Graphics 画线,并把画线的路径点记录下来,同时我们的地图编辑器也会使用到这个功能来画辅助线。

这里使用了曼哈顿距离来记录移动的距离。当距离大于设定值,我们就会存储一次路径点,同时使用 graphics 绘制一次路径。

82606c437fe269df82367c2ac011bf32.jpeg

游戏环境和编辑器环境使用了不同的长度设置,编辑器会更短,来保证储存的关卡长度足够小。

画线的第一个点,我们使用了开销最低的 testPoint,记录是否存在碰撞体。第二个点开始,从上个点到当前点发射一条射线进行检测。

48181a2de48c3c65007d613811e5085f.jpeg

需要注意的是,这里的坐标点需要使用物体的世界坐标。

当画线结束,就可以根据路径点去生成碰撞体。这里直接使用了 polygon 多边形生成碰撞体,已经生成的碰撞体在关卡开始的时候,会回收使用到的 vec2 类,减少 GC。

我们首先把每2个点连成一条线,再对比每条线之间方向向量的斜率。考虑到性能,这里没有使用三角函数,斜率在一定范围内,就判断为是平行的,只会去推第二条线的最后一个点。

8b9817b24c2f6ae2ba12e508330a37bb.jpeg

这样我们参与计算的路径点就可以减少 30%-40%,我们用优化过的路径点再来算需要生成的 polygon 多边形,这里把起始点定为1,结束点定为2,其他中间点是0。

先计算出2个点之前的方向向量。

6203bc293196cdd8f680e5eb6cd07cb1.jpeg

再计算方向向量上,2个垂直方向的向量,分别乘以我们线段一半的宽度,最后起始点和结束点分辨加上这2个向量,就可以得到3个或者4个路径点,可以构建出一个三角形或者平行四边形(考虑到起始点和结束点可能贴边,这里使用了三角形,避免碰撞冲突的修正)。

生成了多边形的路径点后,我们需要额外 apply() 一下,我们所有的 vec2 都从 VecPool 单例内存储,减少 GC。

这里额外支持了 Graphic 的自定义材质,玩家可以在游戏内更换画笔的颜色。

163cda5fb668fcf66fda4d07bd58b8ab.jpeg

我们把材质的颜色和材质名在入口脚本里进行配置,商店和 gameplay 根据配置进行加载即可。

ad3468c6750f4da2a0ed9fb998b5a351.jpeg

感谢社区大佬的 Shader~

419507f9bf5e06c00927fad82f968505.gif

状态机

画好线后,就可以通知障碍出发去攻击我们的角色了。

411bc96f0440b33d0928e2a247e69cff.jpeg

这里使用了 Cocos 原本的 update,当切换状态时候会先执行 onEnter 方法,再执行 onUpdate 方法,这里可以把当前状态和之前状态传入,方便做逻辑切换,这里会记录下 dt 和 duration 时长,方便继承状态机的类使用。

小黑子的 AI 继承了 FSM 状态机,整个状态比较简单,只有寻路和攻击两个状态。

7fde549bfddc4e08adeccf39345aacf5.jpeg

寻路阶段使用了 Astar 算法,每找到一个路径点,就会向下一个路径点前进,寻路时候会使用人物的方向向量乘以一定距离,来检测是否存在物理画线。

20b8ee26b2d6875c6518b22acf0c2d11.jpeg

当检测到物理画线的时候就会对物理画线的 rigidbody2d 进行攻击,对 rigidbody2d 施加速度向量,就可以出现线条被抬起来的行为了。

64fd2d4f444002f1622ee0cf96567d59.jpeg

我们会在 x 方向上做左右的随机,y 方向以向上围住,也会随机一定的数值。

39aeaca52e96278cdf7efb080664349b.gif

小鸡的状态机就相对比较简单,只有基本的碰撞检测,当检测到危险的碰撞体就会触发受伤然后游戏失败。

cb8df6b33de474d21d0a86c6428ec3d8.jpeg

寻路导航

这里使用到了和之前 EasyNavmesh 同款的 A* 导航算法,不同的是我们使用了一个单例进行管理。

6c2a7a77409b6223119921e777abfb97.jpeg

这里把 Astar 翻译成了 TS 版本,方法都加了强类型判断,同时把距离算法改成了曼哈顿距离。

fc7a7f0db72aa6270426962b010a2011.jpeg

游戏内 FSM 同样使用了曼哈顿距离,当我们的路径点走完,且离目标超过2个格子距离时候就会再次寻路一次。

558f732e2966264a94ce371822c27358.jpeg

到这里整个游戏大的逻辑就分解完了,下面介绍一下游戏关卡分享的逻辑。

关卡分享逻辑

游戏内拍照

游戏内把物体和 UI 分辨分成了 Default 和 UI_2D 分组,并创建了2个相机,Screencam 平时的可见分组为空,只有当拍照时候才能看到 Default 分组。

e1b6db8a4cfd6b7f12522399ff4a6e22.png

截图后一瞬间,我们会读取相机 RenderTexture 的像素点,并把角色的偏移量传进来,保证截图范围不会太大,同时保证相机对着角色不会出框。

b7134525477ddd23e3f49c8f0c11bbb8.gif

关卡分享逻辑

关卡分享并没有使用云服务器,这里使用了微信分享里的 query 参数,query 最大可以存储2048长度的 string(测试中4096也可以跑,担心部分手机可能存在兼容问题,这里最大设置成了2046)。

ecf81652af4de5b1801f4668516c290e.jpeg

我们在分享时候可以把当前关卡都转换成 string,放到 query 里。

665a3ff7e7f03c9d58782fe216d3140f.jpeg

当我们分享给其他玩家,其他玩家打开后,在游戏初始化和微信 onshow 时候就会检测到是否有对应的 query。

微信的 getLaunchOption 是第一次进入游戏时候会有的,wx.onShow 是后台切换回来触发的时间,当检测到 query 且 query 内的关卡数据有效,就可以初始化这个关卡了。

d49000b59697d4995accf41541260411.jpeg

游戏内显示好友 UGC 关卡效果:

2a7aba87fe194d9146731bbdc2871ace.gif

资源链接

  • 源码下载:

https://store.cocos.com/app/detail/4240

  • 在线体验:

http://learncocos.com/chick

  • 论坛专贴:

https://forum.cocos.org/t/topic/142673

demo 源码现已发布到 Cocos Store,希望可以对大家有所帮助!如有疑问或者其他想交流的,欢迎移步论坛专贴。

往期精彩

d02b42314c3191892b8bb7f25589849b.png

34edce0f6bd47cf29774ac669b79dc45.png

60141ee0c52642f2dd3e7bf110c2f3cd.png126d398f83c5ec4895a7c2d12ba3c104.gif

这篇关于用 Cocos Creator 做一个物理画线游戏!支持 UGC 关卡创作和微信关卡分享的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/586504

相关文章

QT Creator配置Kit的实现示例

《QTCreator配置Kit的实现示例》本文主要介绍了使用Qt5.12.12与VS2022时,因MSVC编译器版本不匹配及WindowsSDK缺失导致配置错误的问题解决,感兴趣的可以了解一下... 目录0、背景:qt5.12.12+vs2022一、症状:二、原因:(可以跳过,直奔后面的解决方法)三、解决方

Python内存优化的实战技巧分享

《Python内存优化的实战技巧分享》Python作为一门解释型语言,虽然在开发效率上有着显著优势,但在执行效率方面往往被诟病,然而,通过合理的内存优化策略,我们可以让Python程序的运行速度提升3... 目录前言python内存管理机制引用计数机制垃圾回收机制内存泄漏的常见原因1. 循环引用2. 全局变

Linux从文件中提取特定内容的实用技巧分享

《Linux从文件中提取特定内容的实用技巧分享》在日常数据处理和配置文件管理中,我们经常需要从大型文件中提取特定内容,本文介绍的提取特定行技术正是这些高级操作的基础,以提取含有1的简单需求为例,我们可... 目录引言1、方法一:使用 grep 命令1.1 grep 命令基础1.2 命令详解1.3 高级用法2

Python38个游戏开发库整理汇总

《Python38个游戏开发库整理汇总》文章介绍了多种Python游戏开发库,涵盖2D/3D游戏开发、多人游戏框架及视觉小说引擎,适合不同需求的开发者入门,强调跨平台支持与易用性,并鼓励读者交流反馈以... 目录PyGameCocos2dPySoyPyOgrepygletPanda3DBlenderFife

使用IDEA部署Docker应用指南分享

《使用IDEA部署Docker应用指南分享》本文介绍了使用IDEA部署Docker应用的四步流程:创建Dockerfile、配置IDEADocker连接、设置运行调试环境、构建运行镜像,并强调需准备本... 目录一、创建 dockerfile 配置文件二、配置 IDEA 的 Docker 连接三、配置 Do

OpenCV在Java中的完整集成指南分享

《OpenCV在Java中的完整集成指南分享》本文详解了在Java中集成OpenCV的方法,涵盖jar包导入、dll配置、JNI路径设置及跨平台兼容性处理,提供了图像处理、特征检测、实时视频分析等应用... 目录1. OpenCV简介与应用领域1.1 OpenCV的诞生与发展1.2 OpenCV的应用领域2

游戏闪退弹窗提示找不到storm.dll文件怎么办? Stormdll文件损坏修复技巧

《游戏闪退弹窗提示找不到storm.dll文件怎么办?Stormdll文件损坏修复技巧》DLL文件丢失或损坏会导致软件无法正常运行,例如我们在电脑上运行软件或游戏时会得到以下提示:storm.dll... 很多玩家在打开游戏时,突然弹出“找不到storm.dll文件”的提示框,随后游戏直接闪退,这通常是由于

Spring Boot 结合 WxJava 实现文章上传微信公众号草稿箱与群发

《SpringBoot结合WxJava实现文章上传微信公众号草稿箱与群发》本文将详细介绍如何使用SpringBoot框架结合WxJava开发工具包,实现文章上传到微信公众号草稿箱以及群发功能,... 目录一、项目环境准备1.1 开发环境1.2 微信公众号准备二、Spring Boot 项目搭建2.1 创建

Python中你不知道的gzip高级用法分享

《Python中你不知道的gzip高级用法分享》在当今大数据时代,数据存储和传输成本已成为每个开发者必须考虑的问题,Python内置的gzip模块提供了一种简单高效的解决方案,下面小编就来和大家详细讲... 目录前言:为什么数据压缩如此重要1. gzip 模块基础介绍2. 基本压缩与解压缩操作2.1 压缩文

java向微信服务号发送消息的完整步骤实例

《java向微信服务号发送消息的完整步骤实例》:本文主要介绍java向微信服务号发送消息的相关资料,包括申请测试号获取appID/appsecret、关注公众号获取openID、配置消息模板及代码... 目录步骤1. 申请测试系统2. 公众号账号信息3. 关注测试号二维码4. 消息模板接口5. Java测试