【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.pswp.cn/news/38175.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/38175.shtml
英文地址,請注明出處:http://en.pswp.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…

Spring Boot Maven package時顯式的跳過test內容

在pom.xml的編譯插件部分顯式的增加一段內容&#xff1a; <plugin> <!-- maven打包時&#xff0c;顯式的跳過test部分 --><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><version>3.…

流量日志分析--實操

[鶴城杯 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;并且我們的高度與我們的子元素內容一樣高。我們的總寬度和高度是我們的內容 內邊距…

Flink筆記

下面是你提供的文字整理后的結果&#xff1a; 1. Flink是一個針對流數據和批數據的分布式處理引擎&#xff0c;同時支持原生流處理的開源框架。 - 延遲低(毫秒級)&#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; 對導航使用動畫&#…

HTML-文本標簽

歷史上&#xff0c;網頁的主要功能是文本展示。所以&#xff0c;HTML 提供了大量的文本處理標簽。 <div> <div>是一個通用標簽&#xff0c;表示一個區塊&#xff08;division&#xff09;。它沒有語義&#xff0c;如果網頁需要一個塊級元素容器&#xff0c;又沒有…

leetcode 494. 目標和

2023.8.14 一杯茶&#xff0c;一包煙&#xff0c;一道dp做一天... ps&#xff1a;nums[i]均大于等于0。本題先轉化為0-1背包問題&#xff1a;將數組元素分成兩堆&#xff1a;一堆為正號&#xff0c;另一堆為負號。設正號堆的和為x&#xff0c;則負號堆的和為sum-x。&#xff08…

CentOS系統環境搭建(十)——CentOS7定時任務

centos系統環境搭建專欄&#x1f517;點擊跳轉 使用CentOS系統環境搭建&#xff08;九&#xff09;——centos系統下使用docker部署項目的項目做定時任務。 CentOS7定時任務 查看現有的定時任務 crontab -l編輯定時任務 crontab -e示例 每天凌晨兩點運行腳本 清理內存 0 2 *…

【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多用戶…

【SpringBoot】88、SpringBoot中使用Undertow替代Tomcat容器

SpringBoot 中我們既可以使用 Tomcat 作為 Http 服務,也可以用 Undertow 來代替。Undertow 在高并發業務場景中,性能優于 Tomcat。所以,如果我們的系統是高并發請求,不妨使用一下 Undertow,你會發現你的系統性能會得到很大的提升。 1、Tomcat 介紹 Tomcat是一個開源的Ja…

【數據結構】“單鏈表”的練習題(二)

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;個人主頁 &#xff1a;阿然成長日記 …