【Cocos Creator 项目实战 】消灭星星加强版(附带完整源码工程)

本文乃Siliphen原创,转载请注明出处

目录

概述

游戏整体流程

游戏框架设计

单一职责的类

主要流程控制类

核心玩法模块

UI:

游戏世界:

本文项目的代码组织结构

作者项目实践总结

场景只有一个入口脚本

尽量少在节点上挂载脚本

构建游戏世界

ECS 设计

消除物

棋盘地图

逻辑计算和显示分离

消除的实现

查找联通分量

逐步由内向外扩张的消除动画

掉落的实现

合并的实现

道具的实现

本文的完整实现源码工程


概述

《消灭星星》是一个爆款休闲游戏,累计用户5亿+。

目前(2023.08.06)在 App Store 上39.6万个评分,评分4.6,益智解谜类第7名。

参考链接:‎‎App Store 上的“消灭星星全新版®”

本文讲解用 Cocos Creator 实现一款加强效果版的《消灭星星》的核心流程和算法。

本文实现的游戏效果如下:

 

可在这个地址运行体验下本文实现的版本:Cocos Creator | 消灭星星

文本末尾给出完整实现的源码工程。

游戏整体流程

游戏执行一轮玩家操作的流程:等待玩家点击操作 -> 用户点击 -> 消除-> 掉落 -> 合并 -> 等待玩家点击操作

以上流程是游戏玩家操作一次,游戏执行一轮的分解动作循环。

整个游戏的组成:游戏由N关组成,一关由N轮玩家操作组成。

游戏框架设计

单一职责的类

可以把一轮中的每个动作都独立成一个控制类,每个控制类只负责一种动作,比如A类只负责消除控制,B类只负责掉落控制。

这是敏捷开发中的重要原则:单一职责。一个类的功能越是单一,它就越内聚、越和其他系统解耦合。

每种控制类在它负责的单一动作执行完成后,用回调通知其他系统,它已经完成,可以进行下一步操作。

比如:消除控制系统处理消除完成后,用一个 onComplete 回调通知外界,已经完成了消除这个动作。

掉落控制系统监听消除控制系统的 onComplete ,处理消除后下一步的掉落控制。

主要流程控制类

从调用先后顺序开始依次如下:

类名

作用

UiTouch

处理用户触摸输入

Eliminate

处理消除。消除上下左右连色的实体。

Fall

消除后会留下空位,控制消除实体掉落下来。

Merge

掉落后,如果有空的列,那么向左边靠拢合并起来。

核心玩法模块

核心玩法分成2大部分:UI、游戏世界

UI:

包括:按钮、弹窗、分数显示、玩家输入 等部分。是所有用户界面的集合。

这个部分的开发有点类似于做 APP。可以用 MVC 等 APP 常用开发模式。

游戏世界:

这是游戏开发独有的部分。处理游戏世界中游戏实体的行为、游戏实体之间的关系和交互、游戏世界的规则等。

游戏核心玩法的开发主要关注这部分。

因为游戏世界不可能简单分为几个层,比如,什么显示层,逻辑层,数据层等。

有可能实体之间的关系和交互很复杂,MVC 等传统 APP 开发模式并不适用。一般大型游戏会采用 ECS 等设计。

本文项目的代码组织结构

如下图:

作者项目实践总结

场景只有一个入口脚本

一个场景只挂一个入口脚本,各种节点的引用使用 find、node.getChildByPath 等去查找。

就像 C/C++ 语言有一个唯一入口函数 main 。

这样做的好处是:在代码中初始化各个系统,有明确的初始化顺序。

在多个节点上挂多个脚本,默认情况下有个问题,哪个脚本先执行哪个脚本后执行。有时候执行顺序是非常重要的。

编辑器可以指定节点上挂的脚本的执行顺序,但这是额外的维护负担。不如在代码中指定的维护性好。

尽量少在节点上挂载脚本

少挂载脚本的好处是:

  • 降低脚本Missing情况的维护成本。
  • 节约性能。
  • 提高项目移植性。比如移植到其他引擎上。

想象一个情况,一个场景中有很多节点,很多节点都挂有脚本。出于某些原因,脚本和节点的挂载关系丢失了。

编辑器节点上要么不显示脚本,要么脚本显示为丢失(Missing)。

场景简单还好,重新手动拖脚本到节点上。场景复杂,那就很麻烦。绝大部分情况,只是知道节点Missing了脚本,但不知道Missing的是哪个脚本。

为什么有时候会Missing脚本?原因很多,可能有如下几种:

* 用户误操作。比如 破坏了 *.meta 文件。

* 多人协作 *.meta 文件冲突,导致脚本丢失。

* 引擎版本多次低级高级来回切换。

* 一些说不清楚的,莫名其妙的情况。

构建游戏世界

《消灭星星》的游戏世界只有2个实体:消除物、棋盘地图。

棋盘没有画面表现。棋盘是消除物的容器,棋盘限定了消除物计算规则和运动规则。

后面的查找消除算法和掉落控制,都是作用在棋盘上计算的。

ECS 设计

本项目使用类似 ESC 的设计,非严格意义上的 ECS ,是如下定义:

Entity 是 Componet 的容器。Component 只有数据,没有逻辑。System 没有数据,只有逻辑。

实体和游戏世界的交互实现,实体和实体之间的交互实现,都放在 System 中。

这种设计的好处是:高扩展性。高维护性。易于移植到其他引擎。易于引擎升级。

消除物

定义如下:

// 消除物实体
export class Elimination 
{// 类型IDpublic kindId = "" ;public presentaion = new EliminationPresentaion() ;}// 消除物表现组件
export class EliminationPresentaion
{// 根节点public node : Node  = null ;// 动画public amin : Animation = null ; }

Elimination 是消除物实体类。EliminationPresentaion 是消除物实体的表现组件类。

实体类只是组件类的容器。实体类和组件类都只有定义,没有逻辑。

棋盘地图

棋盘数据本质是个二维数组。定义如下:

// 地图数据
export class MapData 
{// 单件/*  */public static ins = new MapData() ;// 数据网格public grid = new Array< Array< Cell > >() ;// 地图大小public size = new Size();// 是否是有效地坐标public isValid(coord : Vec2) : boolean{if( coord.x < 0 || coord.y < 0 || coord.x >= this.size.x || coord.y >= this.size.y ) return false ;return true ;}}// 地图单元格
export class Cell 
{// 消除物public elimination : Elimination = null ;// 坐标public coord = new Vec2();// 在世界空间中单元格的位置。public pt = new Vec3(); }

二位数组对应的位置如下图:

左下角的索引是(0,0),右上角是(9,9)。

逻辑计算和显示分离

先计算好结果后再播放达到这个结果的过渡动画。逻辑计算和播放显示动画的分离可以让代码结构更清晰,维护性更高。

后面的处理都是先在内存中计算好地图状态:消除后地图哪些单元格为空,掉落后消除物实体都落在哪个单元格上 等。

计算好地图状态后再处理画面显示:播放消除动画,播放掉落动画等。

消除的实现

先看下文本实现的消除效果:

 大部分《消灭星星》的实现都是点击后瞬间一起消除。

本文做了不一样的效果,从点击的消除物开始逐步由内向外扩张的消除。

不管是瞬间消除,还是某种控制动画消除,第一步都是“查找相邻的同类消除物”。

查找联通分量

术语“查找联通分量”很多《数据结构》的书都会有介绍。此处,我们用来查找相邻的同类消除物。

使用深度优先搜索(DFS)实现,输出一颗树。树的根结点是玩家点击的那个消除物。

为什么要输出一棵树?因为要按照树的层次进行消除才能实现逐步由内向外扩张的动画。

具体实现可查看工程源码的 ConnectionFind.find 函数。

这里为了讲解算法原理,用伪代码说明算法的核心思想。

// start 是点击的消除物
dfs( start )
{// 结果数据结构,用 Map 表示一棵树。key 是一个被发现的消除物,value 是这个消除物的父节点。let ret = new Map< Elimination , Elimination >() ; // 创建一个栈 stack q ;let q = new Stack() ; // 访问记录。该数据结构是为了防止重复访问那些已经访问过的消除物let visit = Set< Elimination >() ;q.push( start ) ; // 起始点入栈ret.set( start , null ) ; // 点击的消除物是根结点,根结点没有父节点。for( ; q.count > 0 ; ) // 栈不为空就一直循环{let t = q.pop() ; // 出栈一个节点let list = expand( t ) ; // 查找出栈节点上下左右4个方向相邻的同样的节点foreach( let t2 in list ) // 所有查找出来的节点入栈{if( visit.has( t2 ) ) continue ; // 跳过访问过的消除物q.push( t2 ) ;        ret.add( t2 , t ) ; // 发现一个行节点t2,它的父节点是t。visit.add( t2 ) ;} // end for} // end forreturn ret ;                                        
}

《消灭星星》最难的算法就是这个“查找联通分量”了。

如果一下子不理解也没关系,可以反复琢磨下本文作者的伪代码和具体实现。

或者是查阅数据结构或算法的书籍,深入、详细的学习下。加油!:)

逐步由内向外扩张的消除动画

在上一步中,我们获得了一颗消除物节点树。是一个键值对数据结构,key 表示发现的节点,value 表示发现的节点的父节点。

这里,我们处理这棵树结构为按照树的层次划分的数据结构:let levels = new Array< Array< Elimination > >()

levels[ 0 ] 表示树第 1 层的节点集合。树根只有一个起始节点。

levels[ 1 ] 表示树第 2 层的节点集合。

... 以此类推

间隔一层层的整体消除即可。

如何把 Map< Elimination , Elimination > 处理成 Array< Array< Elimination > > 的层次结构呢?

遍历这个 Map,对每个 key 向上查找,直到查到 null 遇到根结点为止。就可以得知当前 key 所在的层次。

按照层次放入对应的 Array 数组容器中即可。

具体实现查看源码工程的类 SeqCtrl。

掉落的实现

消除后,棋盘地图的一些被消除的消除物所在的单元格会被设为空。上面的消除物会掉落下来。

从棋盘底部向上一行行遍历,遇到一个消除物后,向下查找一个空位,如果能找到一个空位,就把这个消除物设置到那个空位上。

先设置棋盘的逻辑状态。后计算被移动的消除物的新的显示位置,做一个移动动画即可。

具体实现查看源码工程的类 Fall。

合并的实现

本文实现的合并效果如下图:

 

合并的处理在掉落之后。

遍历棋盘最底部的那一行,遍历顺序从左到右。

因为之前已经执行了掉落,最底部的一行有空位的话,就说明有棋盘地图有一列为空。

如果发现了一个空位,就说明需要合并,向后查找一个非空列,整体移动那一列的消除物到空位即可。

具体实现查看源码工程的类 Merge。

道具的实现

经典的消灭星星有3个道具:指定一个消除物替换为另一个指定的消除物、九宫格炸弹,全体消除物随机变换。

九宫格炸弹

具体实现查看源码工程的类 PropBombNine、TouchPropBombNine

全体消除物随机变换

遍历整个棋盘地图,随机替换消除物即可。

具体实现查看源码工程的类 PropChangeAll。

单点替换

这个道具的实现相对以上2个比较特殊,耦合了点击操作。

先要设置触摸模式为使用道具,然后玩家点击后,如果点击的是一个消除物,

就在这个消除物的上方显示替换UI,供玩家选择变换后的消除物。

具体实现查看源码工程的类 PropChangeOne、TouchPropChangeOne

本文的完整实现源码工程

源码工程下载地址:Cocos Store

作者创作不易,您的支持让我创造出更多更好的作品。​:)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/38175.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从零构建深度学习推理框架-8 卷积算子实现

其实这一次课还蛮好理解的&#xff1a; 首先将kernel展平&#xff1a; for (uint32_t g 0; g < groups; g) {std::vector<arma::fmat> kernel_matrix_arr(kernel_count_group);arma::fmat kernel_matrix_c(1, row_len * input_c_group);for (uint32_t k 0; k < k…

macOS(m芯片)连接服务器及其进行文件传输的各种方式的详解

说明&#xff1a;使用了macOS后发现&#xff0c;win系统能使用的xshell、xftp等连接服务器及其文件传输等软件均不能使用了&#xff0c;没有兼容的版本。所以我们刚切换到mac系统该如何去适应呢。 一、连接远程服务器 macOS中前文也说道我们使用的是iterm2进行终端控制的&…

基于深度信念神经网络的矿石产量预测,基于DBN的矿石产量预测,DBN的详细原理

目录 背影 DBN神经网络的原理 DBN神经网络的定义 受限玻尔兹曼机(RBM) DBN的矿石产量预测 基本结构 主要参数 数据 MATALB代码 结果图 展望 背影 DBN是一种深度学习神经网络,拥有提取特征,非监督学习的能力,是一种非常好的分类算法,本文将DBN算法进行矿石产量预测 DB…

流量日志分析--实操

[鹤城杯 2021]流量分析 <--第一道流量分析不难,主要就是布尔盲注的流量包分析,直接查看http请求包即可我们可以通过观察看到注入成功的响应长度不同,这里成功的为978字节,失败的994字节.不要问为什么.其实也可以直接判断.978的流量比994的少了非常多 显然就是成功的(因为这里…

Docker中部署redis

1.部署redis要求 2.部署教程 连接容器中的redis redis部署完毕

大模型基础:GPT家族与提示学习

大模型基础:GPT 家族与提示学习 从 GPT-1 到 GPT-3.5 GPT(Generative Pre-trained Transformer)是 Google 于2018年提出的一种基于 Transformer 的预训练语言模型。它标志着自然语言处理领域从 RNN 时代进入 Transformer 时代。GPT 的发展历史和技术特点如下: GPT-12018年6月…

QQ附近人引流的几个详细方法,qq附近人引流脚本实操演示教程

大家好我是你们的小编一辞脚本&#xff0c;今天给大家分享新的知识&#xff0c;很开心可以在CSDN平台分享知识给大家,很多伙伴看不到代码我先录制一下视频 在给大家做代码&#xff0c;给大家分享一下qq引流脚本的知识和视频演示 不懂的小伙伴可以认真看一下&#xff0c;我们一…

【CSS】CSS 布局——常规流布局

<h1>基础文档流</h1><p>我是一个基本的块级元素。我的相邻块级元素在我的下方另起一行。</p><p>默认情况下&#xff0c;我们会占据父元素 100%的宽度&#xff0c;并且我们的高度与我们的子元素内容一样高。我们的总宽度和高度是我们的内容 内边距…

echarts-convert.js使用

echarts-convert.js demo 点击下载 1、本地安装phantom.js插件 点击下载 2、更改文件路径 &#xff08;D:\phantomjs-2.1.1-windows\bin&#xff09;改为本地项目文件路径 3、打开cmd命令行&#xff0c;并格式化语言 运行以下命令 将命令行语言改为中文简体 chcp 65001…

(二分查找) 11. 旋转数组的最小数字 ——【Leetcode每日一题】

❓剑指 Offer 11. 旋转数组的最小数字 难度&#xff1a;简单 把一个数组最开始的若干个元素搬到数组的末尾&#xff0c;我们称之为数组的旋转。 给你一个可能存在 重复 元素值的数组 numbers &#xff0c;它原来是一个升序排列的数组&#xff0c;并按上述情形进行了一次旋转…

springboot整合kafka多数据源

整合kafka多数据源 项目背景依赖配置生产者消费者消息体 项目背景 在很多与第三方公司对接的时候&#xff0c;或者处在不同的网络环境下&#xff0c;比如在互联网和政务外网的分布部署服务的时候&#xff0c;我们需要对接多台kafka来达到我们的业务需求&#xff0c;那么当kafk…

【Vue-Router】路由过渡动效

在 Vue Router 中&#xff0c;你可以通过过渡动效&#xff08;Transition Effects&#xff09;为路由切换添加平滑的过渡效果&#xff0c;从而提升用户体验。过渡动效可以使用 Vue 的 <transition> 组件和 CSS 过渡来实现。 基本使用&#xff1a; 对导航使用动画&#…

leetcode 494. 目标和

2023.8.14 一杯茶&#xff0c;一包烟&#xff0c;一道dp做一天... ps&#xff1a;nums[i]均大于等于0。本题先转化为0-1背包问题&#xff1a;将数组元素分成两堆&#xff1a;一堆为正号&#xff0c;另一堆为负号。设正号堆的和为x&#xff0c;则负号堆的和为sum-x。&#xff08…

【Linux的开胃小菜】常用的RPM软件包与YUM仓库包管理器使用

一、系统初始化进程 systemd与System V init的区别以及作用&#xff1a; System V init运行级别systemd目标名称systemd目标作用0poweroff.target关机1rescue.target单用户模式2multi-user.target多用户的文本界面3multi-user.target多用户的文本界面4multi-user.target多用户…

【数据结构】“单链表”的练习题(二)

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;个人主页 &#xff1a;阿然成长日记 …

Django框架 靓号管理(增删改查)

Django框架 靓号管理&#xff08;增删改查&#xff09; 新建一个项目 backend 使用pycharm创建app startapp app项目目录 C:\code\backend ├── app | ├── admin.py | ├── apps.py | ├── migrations | ├── models.py | ├── tests.py | ├── views.…

关于微信临时文件wxfile://tmp文件如何处理,微信小程序最新获取头像和昵称

分享-2023年资深前端进阶&#xff1a;前端登顶之巅-最全面的前端知识点梳理总结&#xff0c;前端之巅 *分享一个使用比较久的&#x1fa9c; 技术栈&#xff1a;taro框架 vue3版本 解决在微信小程序获取微信头像时控制台报错&#xff1a;找不着wxfile://tmp 文件路径,失败&…

java spring cloud 企业电子招标采购系统源码:营造全面规范安全的电子招投标环境,促进招投标市场健康可持续发展 tbms

​ 项目说明 随着公司的快速发展&#xff0c;企业人员和经营规模不断壮大&#xff0c;公司对内部招采管理的提升提出了更高的要求。在企业里建立一个公平、公开、公正的采购环境&#xff0c;最大限度控制采购成本至关重要。符合国家电子招投标法律法规及相关规范&#xff0c;以…

支持M1 Syncovery for mac 文件备份同步工具

Syncovery for Mac 是一款功能强大、易于使用的文件备份和同步软件&#xff0c;适用于需要备份和同步数据的个人用户和企业用户。Syncovery 提供了一个直观的用户界面&#xff0c;使用户可以轻松设置备份和同步任务。用户可以选择备份的文件类型、备份目录、备份频率等&#xf…

解读2023年上半年财报:营收净利双增长,珀莱雅离高端还有多远?

夏季炎热&#xff0c;防晒类产品的销量暴涨。根据千牛数据&#xff0c;防晒衣今年5月全网搜索人数同比增长15%&#xff0c;加购人数同比增长29.8%&#xff0c;访问人数同比增加42%。消费者狂热的防晒需求&#xff0c;孕育着巨大的商机&#xff0c;许多企业开始瞄准这一机会。而…