用 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 关卡创作和微信关卡分享的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:https://blog.csdn.net/weixin_44053279/article/details/129570029
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/586504

相关文章

JDK9到JDK21中值得掌握的29个实用特性分享

《JDK9到JDK21中值得掌握的29个实用特性分享》Java的演进节奏从JDK9开始显著加快,每半年一个新版本的发布节奏为Java带来了大量的新特性,本文整理了29个JDK9到JDK21中值得掌握的... 目录JDK 9 模块化与API增强1. 集合工厂方法:一行代码创建不可变集合2. 私有接口方法:接口

电脑系统Hosts文件原理和应用分享

《电脑系统Hosts文件原理和应用分享》Hosts是一个没有扩展名的系统文件,当用户在浏览器中输入一个需要登录的网址时,系统会首先自动从Hosts文件中寻找对应的IP地址,一旦找到,系统会立即打开对应... Hosts是一个没有扩展名的系统文件,可以用记事本等工具打开,其作用就是将一些常用的网址域名与其对应

SpringBoot后端实现小程序微信登录功能实现

《SpringBoot后端实现小程序微信登录功能实现》微信小程序登录是开发者通过微信提供的身份验证机制,获取用户唯一标识(openid)和会话密钥(session_key)的过程,这篇文章给大家介绍S... 目录SpringBoot实现微信小程序登录简介SpringBoot后端实现微信登录SpringBoo

Python开发文字版随机事件游戏的项目实例

《Python开发文字版随机事件游戏的项目实例》随机事件游戏是一种通过生成不可预测的事件来增强游戏体验的类型,在这篇博文中,我们将使用Python开发一款文字版随机事件游戏,通过这个项目,读者不仅能够... 目录项目概述2.1 游戏概念2.2 游戏特色2.3 目标玩家群体技术选择与环境准备3.1 开发环境3

Python实现微信自动锁定工具

《Python实现微信自动锁定工具》在数字化办公时代,微信已成为职场沟通的重要工具,但临时离开时忘记锁屏可能导致敏感信息泄露,下面我们就来看看如何使用Python打造一个微信自动锁定工具吧... 目录引言:当微信隐私遇到自动化守护效果展示核心功能全景图技术亮点深度解析1. 无操作检测引擎2. 微信路径智能获

SpringBoot请求参数接收控制指南分享

《SpringBoot请求参数接收控制指南分享》:本文主要介绍SpringBoot请求参数接收控制指南,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Spring Boot 请求参数接收控制指南1. 概述2. 有注解时参数接收方式对比3. 无注解时接收参数默认位置

SpringBoot实现微信小程序支付功能

《SpringBoot实现微信小程序支付功能》小程序支付功能已成为众多应用的核心需求之一,本文主要介绍了SpringBoot实现微信小程序支付功能,文中通过示例代码介绍的非常详细,对大家的学习或者工作... 目录一、引言二、准备工作(一)微信支付商户平台配置(二)Spring Boot项目搭建(三)配置文件

Python通过模块化开发优化代码的技巧分享

《Python通过模块化开发优化代码的技巧分享》模块化开发就是把代码拆成一个个“零件”,该封装封装,该拆分拆分,下面小编就来和大家简单聊聊python如何用模块化开发进行代码优化吧... 目录什么是模块化开发如何拆分代码改进版:拆分成模块让模块更强大:使用 __init__.py你一定会遇到的问题模www.

微信公众号脚本-获取热搜自动新建草稿并发布文章

《微信公众号脚本-获取热搜自动新建草稿并发布文章》本来想写一个自动化发布微信公众号的小绿书的脚本,但是微信公众号官网没有小绿书的接口,那就写一个获取热搜微信普通文章的脚本吧,:本文主要介绍微信公众... 目录介绍思路前期准备环境要求获取接口token获取热搜获取热搜数据下载热搜图片给图片加上标题文字上传图片

SpringKafka消息发布之KafkaTemplate与事务支持功能

《SpringKafka消息发布之KafkaTemplate与事务支持功能》通过本文介绍的基本用法、序列化选项、事务支持、错误处理和性能优化技术,开发者可以构建高效可靠的Kafka消息发布系统,事务支... 目录引言一、KafkaTemplate基础二、消息序列化三、事务支持机制四、错误处理与重试五、性能优