<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          為了女朋友!熬夜擼了一個“合成大西瓜”!(附源碼)

          共 7849字,需瀏覽 16分鐘

           ·

          2021-02-04 09:22



          點(diǎn)擊上方[全棧開發(fā)者社區(qū)]右上角[...][設(shè)為星標(biāo)?]

          最近微博上曝出了很多瓜,"合成大西瓜"這個游戲也很火熱,玩了一陣還挺有意思的。研究了一下原理,發(fā)現(xiàn)目前流傳的版本都是魔改編譯后的版本,代碼經(jīng)過壓縮不具備可讀性,因此決定自己照著實(shí)現(xiàn)一個。

          本項(xiàng)目主要用作 cocos creator 練手使用,所有美術(shù)素材和音頻材料均來源于 www.wesane.com/game/654/

          游戲邏輯

          整個游戲邏輯比較簡單,結(jié)合了俄羅斯方塊與消除游戲的核心玩法

          • 在生成一個水果
          • 點(diǎn)擊屏幕,水果移動到對應(yīng)x軸位置并自由下落
          • 每個水果會與其他水果發(fā)生碰撞,兩個相同的水果碰撞時會發(fā)生合并,升級成更高一級的水果

          水果共有 11 種類型,

          游戲目標(biāo)是合成最高級的水果:大西瓜!當(dāng)堆積的水果超過頂部紅線時則游戲結(jié)束

          整理出需要實(shí)現(xiàn)的核心邏輯

          • 生成水果
          • 水果下落與碰撞
          • 水果消除動畫效果及升級邏輯

          預(yù)備工作

          cocos creator基本概念

          整個項(xiàng)目使用cocos creator v2.4.3實(shí)現(xiàn),建議初次了解的同學(xué)可以先過一下官方文檔,本文不會過多介紹creator的使用(主要是我也不太熟練hah)

          官方文檔鏈接:https://docs.cocos.com/creator/2.3/manual/zh/

          游戲素材

          首先需要準(zhǔn)備美術(shù)資源,本位所有美術(shù)素材和音頻材料均來源于 www.wesane.com/game/654/。

          首先訪問游戲網(wǎng)站,打開network面板,可以看見游戲依賴的所有美術(shù)資源,我們下載自己所需的文件即可

          所需的圖片資源包括

          • 11張水果貼圖
          • 每種水果合成效果貼圖,均包含
            • 一張果粒圖片
            • 一張圓形水珠圖片
            • 一張爆炸貼圖
          • 兩個西瓜合成時有燈光和撒花的效果,時間有限暫不實(shí)現(xiàn)

          音頻文件同理,可以在Filter欄選擇.mp3后綴的請求快速篩選對應(yīng)資源。

          • 水果消除時的爆炸聲和水聲

          創(chuàng)建游戲場景和背景

          打開cocos creator,新建一個項(xiàng)目(也可以直接導(dǎo)入從github下載的項(xiàng)目源碼)。

          然后記得將剛才下載的素材資源拖拽到右下角的資源管理器中。

          創(chuàng)建scene和背景節(jié)點(diǎn)

          項(xiàng)目初始化之后,在左下角資源管理器新建一個游戲Scene,取名game作為游戲主場景

          創(chuàng)建完畢后就可以在資源管理器的assets中看見剛才創(chuàng)建的名為game的scene。

          選擇game場景,在左上角的層級管理器中可以看見場景的Canvas畫布根節(jié)點(diǎn),cocos默認(rèn)畫布是橫屏的960*640,可以選擇根節(jié)點(diǎn)然后再右側(cè)屬性檢查器中調(diào)整寬高為640*960

          接下來創(chuàng)建背景層,我們在Canvas節(jié)點(diǎn)下面新建一個background節(jié)點(diǎn),由于整個背景是純色#FBE79D的,因此使用一個單色Sprite填充即可

          同樣將background節(jié)點(diǎn)寬高調(diào)整為整個畫布的大小,由于默認(rèn)錨點(diǎn)均為0.5*0.5,此時整個畫布會被完全填充。

          現(xiàn)在整個游戲場景大概是這個樣子的

          接下來設(shè)計游戲的邏輯腳本部分

          場景腳本組件

          在assets目錄下新建一個js腳本,按照慣例命令成Game.js,creator會生成一個帶基礎(chǔ)cc.Class的模板文件

          先將腳本組件與節(jié)點(diǎn)關(guān)聯(lián)起來,選擇Canvas根節(jié)點(diǎn),在右側(cè)屬性檢查器中添加組件,然后選擇剛才創(chuàng)建的這個Game組件

          然后編寫具體的代碼邏輯,打開Game.js文件(建議使用vscode或者webstrom打開整個項(xiàng)目的根目錄進(jìn)行編輯)

          里面的初始代碼大概長這樣

          //?Game.js
          cc.Class({
          ????extends:?cc.Component,

          ????properties:?{

          ????},
          ????onLoad(){

          ????},
          ????start(){?}
          })

          我們需要在這里維護(hù)整個游戲的邏輯,后面逐步添加代碼內(nèi)容。

          創(chuàng)建水果

          水果是整個游戲的核心元素,在游戲中被頻繁創(chuàng)建和銷毀。

          生成單個水果預(yù)制資源

          這種動態(tài)創(chuàng)建的節(jié)點(diǎn)可以通過預(yù)制資源Prefab來控制,

          制作prefab最簡單的方式就是將資源從資源管理器拖動到場景編輯器中,然后再將層級管理器中的節(jié)點(diǎn)拖回資源管理器。

          這里以等級最低的水果“葡萄”為例

          然后將層級管理器中的節(jié)點(diǎn)刪除,這樣我們就得到了一個fruit的預(yù)制資源,在腳本組件中,就可以使用代碼通過預(yù)制資源動態(tài)生成節(jié)點(diǎn)了。

          修改Game.js,添加一個屬性fruitPrefab,其類型為cc.Prefab,

          //?Game.js
          properties:?{
          ????fruitPrefab:?{
          ????????default:?null,
          ????????type:?cc.Prefab
          ????},
          }

          回到creator,。選擇Canvas節(jié)點(diǎn),可以在屬性檢查器中的Game組件欄目看見和修改該屬性了。我們將剛才制作的prefab資源從資源管理器拖動到這里,在初始化的時候,有cocos負(fù)責(zé)初始化對應(yīng)的屬性數(shù)據(jù)

          創(chuàng)建單個水果

          回到Game.js,開始編寫真正的邏輯:創(chuàng)建一個葡萄

          //?Game.js
          onLoad(){
          ????let?fruit?=?cc.instantiate(this.fruitPrefab);
          ????fruit.setPosition(cc.v2(0,?400));

          ????this.node.addChild(fruit);
          }

          預(yù)覽模式下就可以看見屏幕正上方有一個葡萄了

          nice,非常好的開始!

          此外,由于水果還包含一些特定的邏輯,我們可以向它添加一個Fruit腳本組件,雖然目前看起來還沒有什么用

          創(chuàng)建Fruit腳本組件與上面創(chuàng)建Game組件類似,然后選擇剛才制作的prefab重新編輯,關(guān)聯(lián)上Fruit用戶腳本組件即可。

          動態(tài)維護(hù)多種水果

          整個游戲共11種水果(當(dāng)然也可以添加或者改成其他的東西),如果每種水果都像上面去手動生成預(yù)制資源然后分別初始化,那也太繁瑣了,我們需要解決動態(tài)渲染多種水果的方式。

          我們需要獲得每種水果的貼圖信息,然后在實(shí)例化水果時選擇對應(yīng)貼圖即可,最簡單的方式就是維護(hù)一個配置表,每行的數(shù)據(jù)字段包括idiconSF

          const?FruitItem?=?cc.Class({
          ????name:?'FruitItem',
          ????properties:?{
          ????????id:?0,?//?水果的類型
          ????????iconSF:?cc.SpriteFrame?//?貼圖資源
          ????}
          });

          然后為Game腳本組件新增一個fruits屬性,用于保存每種水果的配置信息,其類型是數(shù)組,數(shù)組內(nèi)元素類型為剛才創(chuàng)建的FruitItem

          //?Game.js
          properties:?{
          ????fruits:?{
          ????????default:?[],
          ????????type:?FruitItem
          ????},
          }

          回到編輯器,這時候可以發(fā)現(xiàn)Game組件的屬性下面多了一個Fruits屬性,將其長度修改為11,然后依次編寫每個水果的id,同時將其貼圖資源從資源編輯器貼過來(體力活)

          這樣我們只需要傳入想要制作的水果id,就可以獲取到對應(yīng)的配置信息,并動態(tài)修改貼圖了

          這種初始化的邏輯應(yīng)該由水果自己維護(hù),因此放在剛才創(chuàng)建的Fruit組件中,我們暴露一個init接口出來

          //?Fruit.js
          properties:?{
          ????id:?0,
          },
          //?實(shí)例放在可以在其他組件中調(diào)用
          init(data)?{
          ????this.id?=?data.id
          ????//?根據(jù)傳入的參數(shù)修改貼圖資源
          ????const?sp?=?this.node.getComponent(cc.Sprite)
          ????sp.spriteFrame?=?data.iconSF
          },

          然后修改一下上面的初始化水果的代碼

          //?Game.js
          createOneFruit(num)?{
          ????let?fruit?=?cc.instantiate(this.fruitPrefab);
          ????//?獲取到配置信息
          ????const?config?=?this.fruits[num?-?1]

          ????//?獲取到節(jié)點(diǎn)的Fruit組件并調(diào)用實(shí)例方法
          ????fruit.getComponent('Fruit').init({
          ????????id:?config.id,
          ????????iconSF:?config.iconSF
          ????});
          }

          這樣就可以愉快的創(chuàng)建各種水果了

          監(jiān)聽點(diǎn)擊事件

          cocos提供了各種事件監(jiān)聽,前端和客戶端同學(xué)一定不會陌生。

          整個游戲會在點(diǎn)擊屏幕時創(chuàng)建一個水果,這只要監(jiān)聽一下全局點(diǎn)擊事件即可,這個邏輯同樣放在Game腳本組件中

          onLoad()?{
          ????//?監(jiān)聽點(diǎn)擊事件
          ????this.node.on(cc.Node.EventType.TOUCH_START,?this.onTouchStart,?this)
          },
          onTouchStart(){
          ????this.createOneFruit(1)?//?生成水果
          }

          實(shí)際游戲中還需要處理隨機(jī)生成水果、上一個水果在點(diǎn)擊的x軸下落等細(xì)節(jié)邏輯,這里不再贅述。

          物理系統(tǒng):自由落體與剛體碰撞

          上面處理了水果創(chuàng)建的邏輯,在整個游戲中,水果是可以產(chǎn)生下落及彈性碰撞等物理效果的,利用cocos內(nèi)置的物理引擎,可以很方便的實(shí)現(xiàn)

          對cocos引擎不熟悉的同學(xué)可以先看看這個官方demo,里面展示的比較詳細(xì)(起碼比文檔要更容易理解)

          開啟物理引擎與碰撞檢測

          首先是開啟物理引擎,以及設(shè)置重力大小

          const?instance?=?cc.director.getPhysicsManager()
          instance.enabled?=?true
          //?instance.debugDrawFlags?=?4
          instance.gravity?=?cc.v2(0,?-960);

          然后需要開啟碰撞檢測,默認(rèn)是關(guān)閉的

          const?collisionManager?=?cc.director.getCollisionManager();
          collisionManager.enabled?=?true

          然后設(shè)置四周的墻壁用于碰撞,這樣水果就不會無限制往下面掉落了

          ?//?設(shè)置四周的碰撞區(qū)域
          let?width?=?this.node.width;
          let?height?=?this.node.height;

          let?node?=?new?cc.Node();

          let?body?=?node.addComponent(cc.RigidBody);
          body.type?=?cc.RigidBodyType.Static;

          const?_addBound?=?(node,?x,?y,?width,?height)?=>?{
          ????let?collider?=?node.addComponent(cc.PhysicsBoxCollider);
          ????collider.offset.x?=?x;
          ????collider.offset.y?=?y;
          ????collider.size.width?=?width;
          ????collider.size.height?=?height;
          }

          _addBound(node,?0,?-height?/?2,?width,?1);
          _addBound(node,?0,?height?/?2,?width,?1);
          _addBound(node,?-width?/?2,?0,?1,?height);
          _addBound(node,?width?/?2,?0,?1,?height);

          node.parent?=?this.node;

          現(xiàn)在我們就開啟了游戲世界的物理引擎,然后還需要配置需要受引擎影響的節(jié)點(diǎn),也就是我們的水果。

          水果剛體組件與碰撞組件

          回到creator,找到我們的水果prefab,然后添加物理組件

          首先是Rigid Body(剛體)組件

          然后是物理碰撞組件,因?yàn)槲覀兊乃菆A形的,都選擇PhysicsCircleCollider組件就可以了,如果有個香蕉之類不規(guī)則多邊形邊的話,工作量就會增加不少~

          接下來可以看看整體效果,(記得把剛才的點(diǎn)擊事件加上,然后控制一下隨機(jī)生成水果類型)

          完美!!

          水果碰撞回調(diào)

          添加完成之后,還需要開啟剛體組件的碰撞屬性Enabled Contact Listener,這樣可以接收到碰撞之后的回調(diào)

          這個碰撞回調(diào)同樣寫在Fruit腳本組件里面,

          //?Fruit.js
          onBeginContact(contact,?self,?other)?{
          ????//?檢測到是兩個相同水果的碰撞
          ????if?(self.node?&&?other.node)?{
          ????????const?s?=?self.node.getComponent('Fruit')
          ????????const?o?=?other.node.getComponent('Fruit')
          ????????if?(s?&&?o?&&?s.id?===?o.id)?{
          ????????????self.node.emit('sameContact',?{self,?other});
          ????????}
          ????}
          },

          為了保證Fruit組件功能的單一性,在兩個相同水果發(fā)生碰撞時,我們通過事件通知Game.js,這樣可以在初始化水果的時候注冊sameContact自定義事件的處理方法

          //?Game.js
          createOneFruit(num)?{
          ????let?fruit?=?cc.instantiate(this.fruitPrefab);
          ????//?...其他初始化邏輯
          ?????fruit.on('sameContact',?({self,?other})?=>?{
          ????????//?兩個node都會觸發(fā),臨時處理,看看有沒有其他方法只展示一次的
          ????????other.node.off('sameContact')?
          ????????//?處理水果合并的邏輯,下面再處理
          ????????this.onSameFruitContact({self,?other})
          ?????})
          }

          這樣當(dāng)水果發(fā)生碰撞時,我們就能夠監(jiān)聽并處理消除升級邏輯了。

          消除水果動畫

          無動畫版本

          簡單的消除邏輯就是將兩個節(jié)點(diǎn)刪除,然后在原水果位置生成高一級的水果即可,沒有任何動畫效果

          self.node.removeFromParent(false)
          other.node.removeFromParent(false)

          const?{x,?y}?=?other.node?//?獲取合并的水果位置
          const?id?=?other.getComponent('Fruit').id

          const?nextId?=?id?+?1
          const?newFruit?=?this.createFruitOnPos(x,?y,?nextId)?//?在指定位置生成新的水果

          雖然看起來有點(diǎn)奇怪,但的確可以以玩了!

          分析動畫

          打開源站,通過Performance面板分析一下動畫效果(這里就不錄gif了)

          可以看見合成的時候動畫效果包括

          • 碰撞水果向原水果中心移動
          • 果粒爆炸的粒子效果
          • 水珠爆炸的粒子效果
          • 一灘果汁的縮放動畫

          此外還有爆炸聲和水聲的音效

          管理爆炸素材資源

          由于整個動畫涉及到的素材較多,每種水果均包含3種顏色不同的貼圖,與上面FruitItem類似,我們也采用prefab加動態(tài)資源的做法來管理對應(yīng)素材和動畫邏輯。

          首先定義一個JuiceItem,保存單種水果爆炸需要的素材

          //?Game.js
          const?JuiceItem?=?cc.Class({
          ????name:?'JuiceItem',
          ????properties:?{
          ????????particle:?cc.SpriteFrame,?//?果粒
          ????????circle:?cc.SpriteFrame,?//?水珠
          ????????slash:?cc.SpriteFrame,?//?果汁
          ????}
          });

          然后為Game組件新增一個juices屬性

          //?Game.js
          properties:?{
          ????juices:?{
          ????????default:?[],
          ????????type:?JuiceItem
          ????},
          ????juicePrefab:?{
          ????????default:?null,
          ????????type:?cc.Prefab
          ????},
          }

          接下來又是賣勞力的時候了,將貼圖資源都拖放到juices屬性下

          然后新增一個空的預(yù)制資源,主要是為了掛載腳本組件,也就是下面的Juice腳本,然后記得將該預(yù)制資源掛載到Game的juicePrefab上。

          最后,新建Juice組件,用來實(shí)現(xiàn)爆炸的動畫邏輯,同樣需要暴露init接口

          //?Juice.js
          cc.Class({
          ????extends:?cc.Component,

          ????properties:?{
          ????????particle:?{
          ????????????default:?null,
          ????????????type:?cc.SpriteFrame
          ????????},
          ????????circle:?{
          ????????????default:?null,
          ????????????type:?cc.SpriteFrame
          ????????},
          ????????slash:?{
          ????????????default:?null,
          ????????????type:?cc.SpriteFrame
          ????????}
          ????},
          ????//?同樣暴露一個init接口
          ????init(data)?{
          ????????this.particle?=?data.particle
          ????????this.circle?=?data.particle
          ????????this.slash?=?data.slash
          ????},
          ????//?動畫效果
          ????showJuice(){

          ????}
          }

          這樣,在合并的時候,我們初始化一個Juice節(jié)點(diǎn),同時展示爆炸效果即可

          //?Game.js
          let?juice?=?cc.instantiate(this.juicePrefab);
          this.node.addChild(juice);

          const?config?=?this.juices[id?-?1]
          const?instance?=?juice.getComponent('Juice')
          instance.init(config)
          instance.showJuice(pos,?n)?//?對應(yīng)的爆炸邏輯

          爆炸粒子動畫

          關(guān)于粒子動畫,網(wǎng)上能查到不少資料,如果感興趣,也可以移步我之前整理的前端常見動畫實(shí)現(xiàn)原理。

          粒子動畫的主要的實(shí)現(xiàn)思路為:初始化N個粒子,控制他們的速度大小、方向和生命周期,然后控制每個粒子按照對應(yīng)的參數(shù)執(zhí)行動畫,所有粒子匯集在一起的效果就組成了粒子動畫。

          話雖如此,要把動畫效果調(diào)好還是挺麻煩的,需要控制各種隨機(jī)參數(shù)。

          showJuice(pos,?width)?{
          ????//?果粒
          ????for?(let?i?=?0;?i?10;?++i)?{
          ????????const?node?=?new?cc.Node('Sprite');
          ????????const?sp?=?node.addComponent(cc.Sprite);
          ????????sp.spriteFrame?=?this.particle;
          ????????node.parent?=?this.node;
          ????????//?...?一堆隨機(jī)的參數(shù)

          ????????node.position?=?pos;
          ????????node.runAction(
          ????????????cc.sequence(
          ????????????????//?...各種action對應(yīng)的動畫邏輯
          ????????????????cc.callFunc(function?()?{
          ????????????????????//?動畫結(jié)束后消除粒子
          ????????????????????node.active?=?false
          ????????????????},?this))
          ????????)
          ????}

          ????//?水珠
          ????for?(let?f?=?0;?f?20;?f++)?{
          ????????//?同果粒,使用的spriteFrame切換成?this.circle
          ????}
          ????
          ????//?果汁只有一張貼圖,使用this.slash,展示常規(guī)的action縮放和透明動畫即可
          },

          源項(xiàng)目的代碼中使用createFruitL這個方法來處理爆炸動畫,雖然經(jīng)過了代碼壓縮,但依稀能看出對應(yīng)的動畫參數(shù)邏輯,如果不想調(diào)整動畫參數(shù),可以借鑒一下

          這樣,就完成了爆炸效果的展示,大概類似于這樣,雖然有點(diǎn)丑

          音效

          通過cc.audioEngine直接播放AudioClip資源來實(shí)現(xiàn)音效

          在Game組件下新增兩個類型為AudioClip的資源,方便腳本組件訪問

          properties:?{
          ????boomAudio:?{
          ????????default:?null,
          ????????type:?cc.AudioClip
          ????},
          ????waterAudio:?{
          ????????default:?null,
          ????????type:?cc.AudioClip
          ????}
          }

          同上,在屬性檢查器中將兩個音頻資源從資源管理器拖動到Game組件的屬性下方

          onSameFruitContact(){
          ????cc.audioEngine.play(this.boomAudio,?false,?1);
          ????cc.audioEngine.play(this.waterAudio,?false,?1);
          }

          這樣就可以在碰撞的時候聽到聲音了。

          構(gòu)建打包

          完成整個游戲的開發(fā)之后,可以選擇構(gòu)建發(fā)布,打包成web-mobile版本,然后部署在服務(wù)器上,就可以給其他人快樂地玩耍了

          小結(jié)

          不知不就就寫到了最后,貌似??!已經(jīng)大工告成了??!

          雖然還有很多細(xì)節(jié)沒有實(shí)現(xiàn),比如添加得分、合成西瓜之后的撒花等功能,感興趣的同學(xué)可以自己克隆去嘗試修改一下。本文所有代碼及素材都放在github上面了,也可以通過在線預(yù)覽地址體驗(yàn)。

          本文所有代碼及素材都放在 Github上:

          https://github.com/tangxiangmin/cocos-big-watermelon

          也可以通過在線預(yù)覽地址體驗(yàn):

          https://web-game-9gh6nrus14fec37e-1252170212.tcloudbaseapp.com/

          轉(zhuǎn)自:shymean

          www.shymean.com/article/使用cocos實(shí)現(xiàn)一個合成大西瓜

          覺得本文對你有幫助?請分享給更多人

          關(guān)注「全棧開發(fā)者社區(qū)」加星標(biāo),提升全棧技能

          本公眾號會不定期給大家發(fā)福利,包括送書、學(xué)習(xí)資源等,敬請期待吧!

          如果感覺推送內(nèi)容不錯,不妨右下角點(diǎn)個在看轉(zhuǎn)發(fā)朋友圈或收藏,感謝支持。


          好文章,留言、點(diǎn)贊、在看和分享一條龍吧??

          瀏覽 28
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  A∨视频在线免费观看 | 天天射久久 | 中文字幕综合在线观看 | 大香蕉亚洲在线 | 派遣素描模特儿居家作画 却假藉 |