cocos creator游戲開發(fā)
1. 初來乍到
打開 Cocos Creator 點(diǎn)擊新建空白項(xiàng)目,在默認(rèn)布局的左下區(qū)域,一個(gè)黃黃assets文件夾映入眼簾。作為前端的你對這個(gè)文件是不是再熟悉不過了。是的,和你想象的一樣,開發(fā)游戲中所有資源,腳本都會(huì)放置到該文件。
2. 初步探索
項(xiàng)目建立好以后,對各區(qū)域的功能大致了解下,作為前端的你,主要還是要迅速的掌握cc提供的各種NB的功能。所以,還得趕緊打開 [官網(wǎng)](https://docs.cocos.com/creator/manual/zh/) 快速瀏覽一遍。官網(wǎng)也寫得很好,提供中文和英文,對于英文能力不好的伙伴來說,簡直是不能太好了。是不是找到了當(dāng)初學(xué)習(xí)Vue的感覺。作為前端的你,整天寫了一堆業(yè)務(wù)控制,處理各種布局,各種兼容,對奇怪的css優(yōu)先級搞得云里霧里的。所以是時(shí)候換一個(gè)更有意思開發(fā)場景,給自己做個(gè)游戲解悶多好
cc是一個(gè)跨平臺框架,一端編譯多端發(fā)布。想想前端的 mpvue taro uni-app,無不是解決此類問題,再加上gulp,webpack,再來一堆node_modules,啥less sass stylus.各種環(huán)境配置那是相當(dāng)?shù)膹?fù)雜。所以業(yè)界流傳,前端已經(jīng)進(jìn)入深水區(qū),真的一點(diǎn)不假。 然而cc依然可以讓你舒適的寫JS或者TS ,并且沒有繁雜的配置,一鍵搞定打包發(fā)布。
3. 小試牛刀
上邊說了一大堆,其實(shí)并沒有什么鳥用。在官網(wǎng)首頁中,給開發(fā)者提供了個(gè)完整坑爹的游戲《摘星星》,如果打包到微信小游戲,需要橫屏,不太友好。本著舉一反三的求學(xué)態(tài)度,我利用此場景,換了一個(gè)游戲玩法。開發(fā)了自己第一款小游戲《坦克俠》,當(dāng)然也很坑爹
游戲開發(fā)主要是確定游戲規(guī)則,我新改編的玩法就是在星空中隨機(jī)生成不同數(shù)量的星星,并一直往下掉落,我的主角坦克必須在星星掉落前接住。丟失一顆星星生命減一,生命為0游戲結(jié)束。當(dāng)然我們主角每收集一顆星星,根據(jù)當(dāng)前的難度會(huì)添加一定的分?jǐn)?shù)。累計(jì)到一定的分?jǐn)?shù),又可以給主角添加一點(diǎn)生命值
在官網(wǎng) [下載初始項(xiàng)目](https://github.com/cocos-creator/tutorial-first-game/releases/download/v2.0/start_project.zip) 下載一個(gè)基礎(chǔ)項(xiàng)目,該項(xiàng)目中只有一些項(xiàng)目基本圖片和聲音。接下來,我們需要建立場景,制作預(yù)制資源,添加控制腳本,編譯發(fā)布微信小游戲,[快速開始](https://docs.cocos.com/creator/manual/zh/getting-started/quick-start.html)
制作一個(gè)游戲場景,與官網(wǎng)不同的是,我將Canvas的Size屬性,在屬性檢查器中設(shè)置為 288 x 512 ,并且勾選了 Fit Height以及 Fit Width 用以適應(yīng)同的手機(jī)屏幕。然后拖動(dòng)背景圖片到層級管理器中,并在場景編輯器中設(shè)置背景Size屬性,使其等于Canvas的Size屬性。然后依次在層級管理器中新建三個(gè)Label控件,依次拖動(dòng)到背景圖片左上角和右上角,用以記錄生命值,當(dāng)前分?jǐn)?shù),以及最高分?jǐn)?shù)。接著在場景中間添加一個(gè)Label控件和一個(gè)Button按鈕用于顯示游戲結(jié)束和開始游戲。在場景底部拖動(dòng)放置我們的主角坦克。所以最新場景的效果應(yīng)該是如下顯示的那樣

4. 一頓操作猛如虎
游戲場景設(shè)計(jì),看似酷炫,無非就是拖拖拖。依稀找到了當(dāng)年C#開發(fā)winform的感覺,隨便搞整一下,一個(gè)界面就出來了。所以導(dǎo)致很多人開發(fā)winform,webform很簡單,很傻瓜,其實(shí)不是的。重要的還是后邊的業(yè)務(wù)邏輯,解決方案,這些都是超越語言之上的東西。所以cc的場景編輯,就不多說了,直接分析我們游戲?qū)崿F(xiàn)邏輯。開始之前我們先初始一下typescript開發(fā)環(huán)境,操作如下圖
依次點(diǎn)擊安裝vs code 擴(kuò)展插件,添加 Typescript項(xiàng)目配置。接下來就要編寫腳本了,所有還是有必要了解下cc腳本的生命周期
-
onLoad 首次激活時(shí)觸發(fā),一般做一些初始化操作。對比Vue我覺得最合適的應(yīng)該是beforeMount回調(diào)
-
start 首次激活時(shí)觸發(fā),一般初始化一些中間狀態(tài)的數(shù)據(jù),改方法在onLoad之后,在第一次update之前,對比Vue自然應(yīng)該是mounted回調(diào)
-
update 該回調(diào)會(huì)頻繁調(diào)用,每一幀調(diào)用一次。對比Vue應(yīng)該是beforeUpdate回調(diào),雖然他們性質(zhì)不一樣
-
lateUpdate 該回調(diào)會(huì)頻繁調(diào)用,也是每幀調(diào)用一次,對比Vue應(yīng)該updated回調(diào)
-
onDestroy 根據(jù)條件調(diào)用,當(dāng)組件調(diào)用了自身的 destroy()方法,會(huì)觸發(fā)此回調(diào)
-
onEnable 根據(jù)條件調(diào)用, enabled 屬性從 false 變?yōu)?true 或 active 屬性從 false 變?yōu)?true 觸發(fā)此回調(diào)
-
onDisable 根據(jù)條件調(diào)用, enabled 屬性從 true 變?yōu)?false 或active 屬性從 true 變?yōu)?false觸發(fā)此回調(diào)
4.1 讓主角動(dòng)起來
做過前端的你一定知道,要想拖動(dòng)一個(gè)DIV,一定是在Body中監(jiān)聽鼠標(biāo)的移動(dòng)事件。在移動(dòng)端一定是監(jiān)聽觸摸移動(dòng)事件。是的,在cc里邊做游戲,希望一個(gè)組件動(dòng)起來依然是這么操作的,那么cc里邊是如何注冊事件的呢?兩個(gè)方式,一個(gè)在場景編輯器下角的屬性中添加腳本里邊的方法,另外一種就是直接在腳本里邊添加。當(dāng)然我推薦第二種。雖然IDE會(huì)幫我們生成很多代碼,如果不自己寫一遍,就永遠(yuǎn)不曉得數(shù)據(jù)流向。就像當(dāng)年開發(fā)winform時(shí),很多人拖動(dòng)一個(gè)按鈕控件,然后雙擊控件,IDE就自動(dòng)幫你注冊好了一個(gè)用戶點(diǎn)擊事件。殊不知,IDE是在xx.design.cs中通過代碼替你注冊好的。所以既然剛開始學(xué),一定要了解清楚它的原理。
-
cc.systemEvent.on(cc.SystemEvent.EventType.KEY_UP, this.onKeyUp, this) 注冊一個(gè)系統(tǒng)事件 ,支持按鍵事件和重力感應(yīng)事件
-
this.node.parent.on(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this) 在某個(gè)節(jié)點(diǎn)注冊一個(gè)Node 支持的事件類型
所以,主角移動(dòng)無非實(shí)在TouchMove時(shí)改自己的X/Y
// author:herbert qq:464884492 onTouchMove(e: cc.Event.EventTouch) { let deltaX = e.getDeltaX(); //獲取本次和上次移動(dòng)的增量 let deltaY = e.getDeltaY(); //左移 if (deltaX < 0 && this.node.x <= this.leftMinX) return; if (deltaX > 0 && this.node.x >= this.rightMaxX) return; if (deltaY > 0 && this.node.y >= this.topMaxY) return; if (deltaY < 0 && this.node.y <= this.bottomMinY) return; this.node.x += deltaX; this.node.y += deltaY; }
4.2 生成坑爹的星星
在cc里邊需要重復(fù)生成的對象,我們一般會(huì)制作成一個(gè)預(yù)制資源。然后在基本中通過代碼實(shí)例化。何為預(yù)制資源,就權(quán)當(dāng)它是一個(gè)模板吧。現(xiàn)在生成我們第一顆小星星
// author:herbert qq:464884492 buildOneStar() { let star = cc.instantiate(this.starPrefab); this.node.addChild(star); return star; }
是的,就是這么簡單,有沒有class.newInstance()的感覺,當(dāng)然這個(gè)只是在場景的默認(rèn)位置生成了一個(gè)星星而已。我們需要更多的信息,位置肯定也不是默認(rèn)位置,所以還得繼續(xù)碼代碼
// author:herbert qq:464884492 buildRandomStar() { let tempX = 0; let tempY = 0; tempX = Math.floor(this.starMaxX - Math.random() * this.starMaxX);//生成一個(gè)不大于MaxX的坐標(biāo) tempY = Math.floor(this.starMaxY - Math.random() * this.starMaxY); if (Math.random() < 0.5) tempX = tempX * -1; let star = this.buildOneStar(); star.setPosition(tempX, tempY); star.zIndex = this.tank.zIndex - 1; star.name = "star"; star.getComponent("Star").index = this; }
這樣感覺好多了,可以生成很多星星了,不過,我們的星星也得往下掉才行,作為前端的你首先想到的是不是更新星星的Y值,是的,我就是這么做的。利用生命周期中start方法,定義一個(gè)從上往最小Y運(yùn)動(dòng)的動(dòng)畫。后來才了解到所有的游戲引擎都有物理特性,開啟了自己就掉下來了。不過原理肯定還是改變y值。何況這么簡單的游戲完全沒必要使用
start() { // 定義一個(gè)Action let downAction = cc.moveTo(this.index.starFallSpeed, this.node.x, this.minY - 60); downAction.easing(cc.easeSineOut()); this.node.runAction(downAction); }
4.3 是時(shí)候接住星星了
只要是游戲少不了做碰撞檢測,如果在CC中開啟了物理引擎還好,直接跟星星和主角添加一個(gè)剛體就好了,不過我們沒開啟,那就自己來了。不過碰撞檢測無非就是判斷兩個(gè)區(qū)域有沒有重疊地方,簡單判斷就上下左右,左上右上左下右下八個(gè)點(diǎn)。不過我這里偷了個(gè)懶,直接判斷星星和主角間向量的距離。
//author:herbert qq:464884492 ... let distance = this.node.position.sub(this.tank.getPosition()).mag(); if (distance < (this.tank.width / 2 - 5)) { console.log("接住了"); } ...
4.4 來點(diǎn)刺激的
游戲嘛,總不能一成不變那多沒意思,所以隨著時(shí)間的推移我們的調(diào)整點(diǎn)難度。我這個(gè)游戲難度無非就一下兩個(gè)方面
-
生成星星的速度加快
-
星星掉落的速度加快
//author:herbert qq:464884492 ... this.index.scoreNum += this.index.starScoreSpeed; this.index.score.string = "得分:" + this.index.scoreNum; // 降落速度加 if (Math.floor(this.index.scoreNum / 100) == this.index.starScoreSpeed - 4 && this.index.starFallSpeed > 1) { this.index.starFallSpeed -= 0.2; //下降速度加快 if (this.index.starBuildTimeOut > 200) { this.index.starBuildTimeOut -= 100; //生成速度加快 } this.index.lifeNum += 1; if (this.index.starScoreSpeed < 10) { this.index.starScoreSpeed += 1; } } cc.audioEngine.play(this.index.scoreClip, false, 0.2); this.index.allStars.splice(this.index.allStars.indexOf(this.node), 1) this.node.destroy(); ...
4.5 是時(shí)候結(jié)束了
游戲嘛,也不能一直玩下去。不然多沒挑戰(zhàn)。自從調(diào)整游戲難度后我的最高分重來就沒有超過4000.
//author:herbert qq:464884492 ... if (this.node.y <= this.minY) { this.index.lifeNum -= 1; this.index.life.string = "生命:" + this.index.lifeNum; this.node.destroy(); this.index.allStars.splice(this.index.allStars.indexOf(this.node), 1) if (this.index.lifeNum <= 0) { this.index.gameOver.node.active = true; this.index.btnPlay.node.active = true; this.index.starIsRunning = false; let storageValue = cc.sys.localStorage.getItem(this.index.HIGHSTORAGEKEY); if (storageValue && parseInt(storageValue) > this.index.scoreNum) { return; } cc.sys.localStorage.setItem(this.index.HIGHSTORAGEKEY, this.index.scoreNum); this.index.highScore.string = "最高分:" + this.index.scoreNum; } } ...
5. 來點(diǎn)實(shí)際的
做技術(shù)嘛,大多都是 Talk is cheap,Show me your code.做點(diǎn)總結(jié)吧
-
在基本中定義的屬性,切記在編輯器中拖動(dòng)綁定
-
多看官網(wǎng)api,多開實(shí)例代碼
-
發(fā)布微信小游戲一定不要有英文,會(huì)導(dǎo)致審核不通過
- 轉(zhuǎn)載請注明來源
- 作者:楊瀚博
- QQ:464884492

浙公網(wǎng)安備 33010602011771號