本專案主要用作 cocos creator 練手使用,所有美術素材和音頻材料均來源于
游戲邏輯
整個游戲邏輯比較簡單,結合了俄羅斯方塊與消除游戲的核心玩法
在生成一個水果
點擊螢屏,水果移動到對應x軸位置并自由下落
每個水果會與其他水果發生碰撞,兩個相同的水果碰撞時會發生合并,升級成更高一級的水果
水果共有 11 種型別,

游戲目標是合成最高級的水果:大西瓜!當堆積的水果超過頂部紅線時則游戲結束
整理出需要實作的核心邏輯
生成水果
水果下落與碰撞
水果消除影片效果及升級邏輯
預備作業
cocos creator基本概念
整個專案使用cocos creator v2.4.3實作,建議初次了解的同學可以先過一下官方檔案,本文不會過多介紹creator的使用(主要是我也不太熟練hah)
官方檔案鏈接:
游戲素材
首先需要準備美術資源,本位所有美術素材和音頻材料均來源于 www.wesane.com/game/654/,
首先訪問游戲網站,打開network面板,可以看見游戲依賴的所有美術資源,我們下載自己所需的檔案即可

所需的圖片資源包括
11張水果貼圖
每種水果合成效果貼圖,均包含
一張果粒圖片
一張圓形水珠圖片
一張爆炸貼圖
兩個西瓜合成時有燈光和撒花的效果,時間有限暫不實作
音頻檔案同理,可以在Filter欄選擇.mp3后綴的請求快速篩選對應資源,
水果消除時的爆炸聲和水聲
創建游戲場景和背景
打開cocos creator,新建一個專案(也可以直接匯入從github下載的專案原始碼),
然后記得將剛才下載的素材資源拖拽到右下角的資源管理器中,
創建scene和背景節點
專案初始化之后,在左下角資源管理器新建一個游戲Scene,取名game作為游戲主場景

創建完畢后就可以在資源管理器的assets中看見剛才創建的名為game的scene,
選擇game場景,在左上角的層級管理器中可以看見場景的Canvas畫布根節點,cocos默認畫布是橫屏的960*640,可以選擇根節點然后再右側屬性檢查器中調整寬高為640*960

接下來創建背景層,我們在Canvas節點下面新建一個background節點,由于整個背景是純色#FBE79D的,因此使用一個單色Sprite填充即可

同樣將background節點寬高調整為整個畫布的大小,由于默認錨點均為0.5*0.5,此時整個畫布會被完全填充,
現在整個游戲場景大概是這個樣子的

接下來設計游戲的邏輯腳本部分
場景腳本組件
在assets目錄下新建一個js腳本,按照慣例命令成Game.js,creator會生成一個帶基礎cc.Class的模板檔案

先將腳本組件與節點關聯起來,選擇Canvas根節點,在右側屬性檢查器中添加組件,然后選擇剛才創建的這個Game組件

然后撰寫具體的代碼邏輯,打開Game.js檔案(建議使用vscode或者webstrom打開整個專案的根目錄進行編輯)
里面的初始代碼大概長這樣
// Game.js
cc.Class({
extends: cc.Component,
properties: {
},
onLoad(){
},
start(){ }
})
我們需要在這里維護整個游戲的邏輯,后面逐步添加代碼內容,
創建水果
水果是整個游戲的核心元素,在游戲中被頻繁創建和銷毀,
生成單個水果預制資源
這種動態創建的節點可以通過預制資源Prefab來控制,
制作prefab最簡單的方式就是將資源從資源管理器拖動到場景編輯器中,然后再將層級管理器中的節點拖回資源管理器,
這里以等級最低的水果“葡萄”為例


然后將層級管理器中的節點洗掉,這樣我們就得到了一個fruit的預制資源,在腳本組件中,就可以使用代碼通過預制資源動態生成節點了,
修改Game.js,添加一個屬性fruitPrefab,其型別為cc.Prefab,
// Game.js
properties: {
fruitPrefab: {
default: null,
type: cc.Prefab
},
}
回到creator,,選擇Canvas節點,可以在屬性檢查器中的Game組件欄目看見和修改該屬性了,我們將剛才制作的prefab資源從資源管理器拖動到這里,在初始化的時候,有cocos負責初始化對應的屬性資料

創建單個水果
回到Game.js,開始撰寫真正的邏輯:創建一個葡萄
// Game.js
onLoad(){
let fruit = cc.instantiate(this.fruitPrefab);
fruit.setPosition(cc.v2(0,400));
this.node.addChild(fruit);
}
預覽模式下就可以看見螢屏正上方有一個葡萄了

nice,非常好的開始!
此外,由于水果還包含一些特定的邏輯,我們可以向它添加一個Fruit腳本組件,雖然目前看起來還沒有什么用
創建Fruit腳本組件與上面創建Game組件類似,然后選擇剛才制作的prefab重新編輯,關聯上Fruit用戶腳本組件即可,
動態維護多種水果
整個游戲共11種水果(當然也可以添加或者改成其他的東西),如果每種水果都像上面去手動生成預制資源然后分別初始化,那也太繁瑣了,我們需要解決動態渲染多種水果的方式,
我們需要獲得每種水果的貼圖資訊,然后在實體化水果時選擇對應貼圖即可,最簡單的方式就是維護一個配置表,每行的資料欄位包括id和iconSF
constFruitItem = cc.Class({
name:'FruitItem',
properties: {
id:0,// 水果的型別
iconSF: cc.SpriteFrame// 貼圖資源
}
});
然后為Game腳本組件新增一個fruits屬性,用于保存每種水果的配置資訊,其型別是陣列,陣列內元素型別為剛才創建的FruitItem
// Game.js
properties: {
fruits: {
default: [],
type: FruitItem
},
}
回到編輯器,這時候可以發現Game組件的屬性下面多了一個Fruits屬性,將其長度修改為11,然后依次撰寫每個水果的id,同時將其貼圖資源從資源編輯器貼過來(體力活)

這樣我們只需要傳入想要制作的水果id,就可以獲取到對應的配置資訊,并動態修改貼圖了
這種初始化的邏輯應該由水果自己維護,因此放在剛才創建的Fruit組件中,我們暴露一個init介面出來
// Fruit.js
properties: {
id:0,
},
// 實體放在可以在其他組件中呼叫
init(data) {
this.id = data.id
// 根據傳入的引數修改貼圖資源
constsp = this.node.getComponent(cc.Sprite)
sp.spriteFrame = data.iconSF
},
然后修改一下上面的初始化水果的代碼
// Game.js
createOneFruit(num) {
let fruit = cc.instantiate(this.fruitPrefab);
// 獲取到配置資訊
constconfig = this.fruits[num -1]
// 獲取到節點的Fruit組件并呼叫實體方法
fruit.getComponent('Fruit').init({
id: config.id,
iconSF: config.iconSF
});
}
這樣就可以愉快的創建各種水果了
監聽點擊事件
cocos提供了各種事件監聽,前端和客戶端同學一定不會陌生,
整個游戲會在點擊螢屏時創建一個水果,這只要監聽一下全域點擊事件即可,這個邏輯同樣放在Game腳本組件中
onLoad() {
// 監聽點擊事件
this.node.on(cc.Node.EventType.TOUCH_START, this.onTouchStart, this)
},
onTouchStart(){
this.createOneFruit(1)// 生成水果
}
實際游戲中還需要處理隨機生成水果、上一個水果在點擊的x軸下落等細節邏輯,這里不再贅述,
物理系統:自由落體與剛體碰撞
上面處理了水果創建的邏輯,在整個游戲中,水果是可以產生下落及彈性碰撞等物理效果的,利用cocos內置的物理引擎,可以很方便的實作
對cocos引擎不熟悉的同學可以先看看這個官方demo,里面展示的比較詳細(起碼比檔案要更容易理解)
開啟物理引擎與碰撞檢測
首先是開啟物理引擎,以及設定重力大小
constinstance = cc.director.getPhysicsManager()
instance.enabled =true
// instance.debugDrawFlags = 4
instance.gravity = cc.v2(0,-960);
然后需要開啟碰撞檢測,默認是關閉的
constcollisionManager = cc.director.getCollisionManager();
collisionManager.enabled =true
然后設定四周的墻壁用于碰撞,這樣水果就不會無限制往下面掉落了
// 設定四周的碰撞區域
let width = this.node.width;
let height = this.node.height;
let node =newcc.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;
現在我們就開啟了游戲世界的物理引擎,然后還需要配置需要受引擎影響的節點,也就是我們的水果,
水果剛體組件與碰撞組件
回到creator,找到我們的水果prefab,然后添加物理組件
首先是Rigid Body(剛體)組件

然后是物理碰撞組件,因為我們的水果全是圓形的,都選擇PhysicsCircleCollider組件就可以了,如果有個香蕉之類不規則多邊形邊的話,作業量就會增加不少~

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

完美!!
水果碰撞回呼
添加完成之后,還需要開啟剛體組件的碰撞屬性Enabled Contact Listener,這樣可以接收到碰撞之后的回呼

這個碰撞回呼同樣寫在Fruit腳本組件里面,
// Fruit.js
onBeginContact(contact, self, other) {
// 檢測到是兩個相同水果的碰撞
if(self.node && other.node) {
consts = self.node.getComponent('Fruit')
consto = other.node.getComponent('Fruit')
if(s && o && s.id === o.id) {
self.node.emit('sameContact', {self, other});
}
}
},
為了保證Fruit組件功能的單一性,在兩個相同水果發生碰撞時,我們通過事件通知Game.js,這樣可以在初始化水果的時候注冊sameContact自定義事件的處理方法
// Game.js
createOneFruit(num) {
let fruit = cc.instantiate(this.fruitPrefab);
// ...其他初始化邏輯
fruit.on('sameContact', ({self, other}) => {
// 兩個node都會觸發,臨時處理,看看有沒有其他方法只展示一次的
other.node.off('sameContact')
// 處理水果合并的邏輯,下面再處理
this.onSameFruitContact({self, other})
})
}
這樣當水果發生碰撞時,我們就能夠監聽并處理消除升級邏輯了,
消除水果影片
無影片版本
簡單的消除邏輯就是將兩個節點洗掉,然后在原水果位置生成高一級的水果即可,沒有任何影片效果
self.node.removeFromParent(false)
other.node.removeFromParent(false)
const{x, y} = other.node// 獲取合并的水果位置
constid = other.getComponent('Fruit').id
constnextId = id +1
constnewFruit = this.createFruitOnPos(x, y, nextId)// 在指定位置生成新的水果
雖然看起來有點奇怪,但的確可以以玩了!
分析影片
打開源站,通過Performance面板分析一下影片效果(這里就不錄gif了)

可以看見合成的時候影片效果包括
碰撞水果向原水果中心移動
果粒爆炸的粒子效果
水珠爆炸的粒子效果
一灘果汁的縮放影片
此外還有爆炸聲和水聲的音效
管理爆炸素材資源
由于整個影片涉及到的素材較多,每種水果均包含3種顏色不同的貼圖,與上面FruitItem類似,我們也采用prefab加動態資源的做法來管理對應素材和影片邏輯,
首先定義一個JuiceItem,保存單種水果爆炸需要的素材
// Game.js
constJuiceItem = 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屬性下

然后新增一個空的預制資源,主要是為了掛載腳本組件,也就是下面的Juice腳本,然后記得將該預制資源掛載到Game的juicePrefab上,
最后,新建Juice組件,用來實作爆炸的影片邏輯,同樣需要暴露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節點,同時展示爆炸效果即可
// Game.js
let juice = cc.instantiate(this.juicePrefab);
this.node.addChild(juice);
constconfig = this.juices[id -1]
constinstance = juice.getComponent('Juice')
instance.init(config)
instance.showJuice(pos, n)// 對應的爆炸邏輯
爆炸粒子影片
關于粒子影片,網上能查到不少資料,如果感興趣,也可以移步我之前整理的前端常見影片實作原理,
粒子影片的主要的實作思路為:初始化N個粒子,控制他們的速度大小、方向和生命周期,然后控制每個粒子按照對應的引數執行影片,所有粒子匯集在一起的效果就組成了粒子影片,
話雖如此,要把影片效果調好還是挺麻煩的,需要控制各種隨機引數,
showJuice(pos, width) {
// 果粒
for(let i =0; i <10; ++i) {
constnode =newcc.Node('Sprite');
constsp = node.addComponent(cc.Sprite);
sp.spriteFrame = this.particle;
node.parent = this.node;
// ... 一堆隨機的引數
node.position = pos;
node.runAction(
cc.sequence(
// ...各種action對應的影片邏輯
cc.callFunc(function () {
// 影片結束后消除粒子
node.active =false
}, this))
)
}
// 水珠
for(let f =0; f <20; f++) {
// 同果粒,使用的spriteFrame切換成 this.circle
}
// 果汁只有一張貼圖,使用this.slash,展示常規的action縮放和透明影片即可
},
源專案的代碼中使用createFruitL這個方法來處理爆炸影片,雖然經過了代碼壓縮,但依稀能看出對應的影片引數邏輯,如果不想調整影片引數,可以借鑒一下

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

音效
通過cc.audioEngine直接播放AudioClip資源來實作音效
在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);
}
這樣就可以在碰撞的時候聽到聲音了,
構建打包
完成整個游戲的開發之后,可以選擇構建發布,打包成web-mobile版本,然后部署在服務器上,就可以給其他人快樂地玩耍了

小結
不知不就就寫到了最后,貌似!!已經大工告成了!!
雖然還有很多細節沒有實作,比如添加得分、合成西瓜之后的撒花等功能,感興趣的同學可以自己克隆去嘗試修改一下,本文所有代碼及素材都放在github上面了,也可以通過在線預覽地址體驗,
本文所有代碼及素材都放在 Github上:
也可以通過在線預覽地址體驗:
轉自:shymean
使用cocos實作一個合成大西瓜

如果你也想要學習編程,掌握炫酷技能,小編推薦一個企鵝群【點擊進入】!
涉及到了:編程入門、游戲編程、網路編程、Windows編程、Linux編程、Qt界面開發、黑客等等......
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/257662.html
標籤:其他
