這節咱們從頭作一個比較有意思的小遊戲——一步兩步。javascript
下面是最終效果(跳一步得一分,跳兩步得三分,電腦端左右鍵12步):html
一步兩步java
這是本教程第一個遊戲,因此我會講的詳細一點,可是也不能避免遺漏,因此有什麼問題你能夠先嚐試查閱文檔本身解決或者在下方留言,後面我會跟進完善。node
另外這個遊戲並不是原創,參照的是騰訊的微信小遊戲《一步兩步H5》,請不要直接搬過去,微信裏重複的遊戲太多了。git
選擇空白項目建立工程github
你能夠從這裏下載遊戲素材,而後將素材導入工程(直接拖進編輯器,或者放在工程目錄)算法
也能夠從https://github.com/potato47/one-two-step下載完整代碼進行參照。chrome
準備工做作完後,我會把這個遊戲製做過程分爲若干個小過程,讓你體會一下實際的遊戲製做體驗。
在res文件夾下新建一個scenes文件夾,而後在scenes裏新建兩個場景menu和game(右鍵->新建->Scene)。而後雙擊menu進入menu場景。windows
在層級管理器中選中Canvas節點,在右側屬性檢查器中將其設計分辨率調整爲1280x720,而後將background圖片拖入Canvas節點下,併爲其添加Widget組件(添加組件->UI組件->Widget),使其充滿畫布。api
在Canvas下新建一個Label節點(右鍵->建立節點->建立渲染節點->Label),而後調整文字大小,並添加標題文字
咱們知道節點和組件一般是一塊兒出現的,帶有常見組件的節點在編輯器裏能夠直接建立,好比剛纔的帶有Label組件的節點和帶有Sprite組件的節點,可是咱們也能夠新建一個空節點而後爲其添加對應的組件來組裝一個帶有特殊功能的節點。
新建節點->UI節點下有一個Button,若是你直接建立Button,你會發現它是一個帶有Button組件的節點,而且有一個Label的子節點。如今咱們用另外一種方法建立Button:在Canvas右鍵新建一個空節點,而後爲其添加Button組件,這時你會發現按鈕並無背景,因此咱們再添加一個Sprite組件,拖入資源中的按鈕背景圖片,最後添加一個Label子節點給按鈕添加上文字。
下面咱們給這個按鈕添加點擊事件。
在資源管理器中新建src文件夾用來存放腳本,而後新建一個TypeScript腳本,名字爲Menu(注意腳本組件名稱區分大小寫,這裏建議首字母大寫)。
雙擊用VS Code打開腳本,更改以下:
const { ccclass } = cc._decorator; @ccclass // 讓編輯器可以識別這是一個組件 export class Menu extends cc.Component { private onBtnStart() { cc.director.loadScene('game'); //加載game場景 } }
一個類只有加上@ccclass才能被編輯器識別爲腳本組件,若是你去掉@ccclass,你就不能把這個組件拖到節點上。另外能夠看到代碼中出現了幾回cc這個東西,cc實際上是Cocos的簡稱,在遊戲中是引擎的主要命名空間,引擎代碼中全部的類、函數、屬性和常量都在這個命名空間中定義。
很明顯,咱們想在點擊開始按鈕的時候調用onBtnStart函數,而後跳轉到game場景。爲了測試效果咱們先打開game場景,而後放一個測試文字(將Canvas的設計分辨率也改成1280x720)。
保存game場景後再回到Menu場景。
Button組件點擊後會發出一個事件,這個事件能夠跟某個節點上的某個腳本內的某個函數綁定在一塊兒。聽着有點繞,動手作一遍就會明白這個機制。
首先將Menu腳本添加爲Canvas節點的組件,而後在開始按鈕的Button組件裏添加一個Click Event,將其指向Canvas節點下的Menu腳本里的onBtnStart函數。
咱們再調整一下Button的點擊效果,將Button組件的Transition改成scale(伸縮效果),另外還有顏色變化和圖片變化,能夠本身嘗試。
最後點擊上方的預覽按鈕,不出意外的話就能夠在瀏覽器中看見預期效果。
如今咱們來編寫遊戲邏輯。
首先我來說一下我看到的一種現象:
不少新手很是喜歡問,「看代碼我都能看懂啊,可是要我本身寫我就沒思路啊」
這時一位經驗頗多的長者就會甩給他一句,「多寫寫就有思路了「
不知道大家發現沒有,這居然是一個死循環。
對於一個剛開始學習作遊戲的人,首先要了解的是如何組織你的代碼,這裏我教給你們一個最容易入門的代碼結構——單向分權結構(這是我想了足足兩分鐘的自認爲很酷炫的一個名字)
腳本分層:
這個結構最重要的就是「權」這個字,咱們把一個場景中使用的腳本按照「權力」大小給它們分層,權力最大的在最上層且只有一個,這個腳本里保存着它直接控制的若干個腳本的引用,被引用的腳本權力就小一級,被引用的腳本還會引用比它權力更小的腳本,依此類推。
腳本互操做:
寫了這麼多,但你確定沒看懂,如今你能夠翻到最上面再分析一下游戲的game場景,如何組織這個場景的腳本結構?
首先,一個場景的根節點會掛載一個腳本,一般以場景名命名,這裏就是Game。
而後跳躍的人物也對應着一個腳本Player。
跟Player同層的還應該有Block也就是人物踩着的地面方塊。
由於Player和Block之間互相影響而且我想讓Game腳本更簡潔,因此這裏再加一個Stage(舞臺)腳原本控制Player和Block。
最終它們的層級關係以下:
Game
Stage
上面這些都是咱們的思考過程,下面咱們落實到場景中。
先新建幾個腳本
如今搭建場景,先添加一個跟menu場景同樣的全屏背景
而後添加一個空節點Stage,在Stage下添加一個Player節點和一個Block節點
在Stage同層添加兩個按鈕來控制跳一步兩步
先添加第一個按鈕,根據實際效果調整文字大小(font size)顏色(node color)和按鈕的縮放倍數(scale)
第二個按鈕能夠直接由第一個按鈕複製
這兩個按鈕顯然是要放置在屏幕左下角和右下角的,可是不一樣屏幕大小可能致使這兩個按鈕的位置跑偏,因此最好的方案是給這兩個按鈕節點添加Widget組件,讓它們跟左下角和右下角保持固定的距離,這裏就不演示了,相信你能夠本身完成(實際上是我忘錄了。。。)
添加一個Label節點記錄分數,系統字體有點醜,這裏替換成咱們本身的字體
最後把腳本掛在對應的節點上。
場景搭建到這裏基本完成了,如今能夠編寫腳本了。
Game做爲一個統領全局的腳本,必定要控制關鍵的邏輯,,好比開始遊戲和結束遊戲,增長分數,還有一些全局的事件。
Game.ts
import { Stage } from './Stage'; const { ccclass, property } = cc._decorator; @ccclass export class Game extends cc.Component { @property(Stage) private stage: Stage = null; @property(cc.Label) private scoreLabel: cc.Label = null; private score: number = 0; protected start() { this.startGame(); } public addScore(n: number) { this.score += n; this.scoreLabel.string = this.score + ''; } public startGame() { this.score = 0; this.scoreLabel.string = '0'; this.stage.init(this); } public overGame() { cc.log('game over'); } public restartGame() { cc.director.loadScene('game'); } public returnMenu() { cc.director.loadScene('menu'); } private onBtnOne() { this.stage.playerJump(1); } private onBtnTwo() { this.stage.playerJump(2); } }
Stage做爲Game直接控制的腳本,要給Game暴露出操做的接口而且保存Game的引用,當遊戲狀態發生改變時,通知Game處理。
Stage.ts
import { Game } from './Game'; import { Player } from './Player'; const { ccclass, property } = cc._decorator; @ccclass export class Stage extends cc.Component { @property(Player) private player: Player = null; private game: Game = null; public init(game: Game) { this.game = game; } public playerJump(step: number) { this.player.jump(step); } }
而Player做爲最底層的一個小員工,別人讓你作啥你就作啥。
Player.ts
const {ccclass, property} = cc._decorator; @ccclass export class Player extends cc.Component { public jump(step: number) { if (step === 1) { cc.log('我跳了1步'); } else if (step === 2) { cc.log('我跳了2步'); } } public die() { cc.log('我死了'); } }
以前講了@ccclass
是爲了讓編輯器識別這是一個組件類,能夠掛在節點上,如今咱們又看到了一個@property
,這個是爲了讓一個組件的屬性暴露在編輯器屬性中,觀察最上面的Game
腳本,發現有三個成員變量,stage
,scoreLabel
和score
,而只有前兩個變量加上了@property
,因此編輯器中只能看到stage
和scoreLabel
。
@property
括號裏一般要填一個編輯器能夠識別的類型,好比系統自帶的cc.Label
,cc.Node
,cc.Sprite
,cc.Integer
,cc.Float
等,也能夠是用戶腳本類名,好比上面的Stage
和Player
。
回到編輯器,咱們把幾個腳本暴露在編輯器的變量經過拖拽的方式指向帶有類型組件的節點。
再把one,two兩個按鈕分別綁定在game裏的onBtnOne,onBtnTwo兩個函數上。
這時咱們已經有了一個簡單的邏輯,點擊1或2按鈕,調用Game裏的onBtnOne或onBtnTwo,傳遞給Stage調用playerJump,再傳遞給Player調用jump,player就會表現出跳一步仍是跳兩步的反應。
點擊預覽按鈕,進行測試:
你能夠按F12(windows)或cmd+opt+i(mac)打開chrome的開發者工具。
如今咱們來讓Player跳起來,人物動做的實現大概能夠藉助如下幾種方式實現:
能夠看到這個遊戲人物動做比較簡單,跳躍路徑是固定的,因此咱們選擇用動做系統實現人物的跳躍動做。
creator自帶一套基於節點的動做系統,形式如node.runAction(action)
。
修改Player.ts,添加幾個描述跳躍動做的參數,而且添加一個init函數由上層組件即Stage初始化時調用並傳入所需參數。另外更改jump函數內容讓Player執行jumpBy動做。
Player.ts
... private stepDistance: number; // 一步跳躍距離 private jumpHeight: number; // 跳躍高度 private jumpDuration: number; // 跳躍持續時間 public canJump: boolean; // 此時是否能跳躍 public init(stepDistance: number, jumpHeight: number, jumpDuration: number) { this.stepDistance = stepDistance; this.jumpHeight = jumpHeight; this.jumpDuration = jumpDuration; this.canJump = true; } public jump(step: number) { this.canJump = false; this.index += step; let jumpAction = cc.jumpBy(this.jumpDuration, cc.v2(step * this.stepDistance, 0), this.jumpHeight, 1); let finishAction = cc.callFunc(() => { this.canJump = true; }); this.node.runAction(cc.sequence(jumpAction, finishAction)); } ...
Stage.ts
... @property(cc.Integer) private stepDistance: number = 200; @property(cc.Integer) private jumpHeight: number = 100; @property(cc.Float) private jumpDuration: number = 0.3; @property(Player) private player: Player = null; private game: Game = null; public init(game: Game) { this.game = game; this.player.init(this.stepDistance, this.jumpHeight, this.jumpDuration); } public playerJump(step: number) { if (this.player.canJump) { this.player.jump(step); } } ...
這裏要介紹一下 Cocos Creator 的動做系統,動做系統基於節點,你可讓一個節點執行一個瞬時動做或持續性的動做。好比讓一個節點執行一個「3秒鐘向右移動100」的動做,就能夠這樣寫
let moveAction = cc.moveBy(3, cc.v2(100, 0)); // cc.v2能夠建立一個二位的點(向量),表明方向x=100,y=0 this.node.runAction(moveAction);
更多的動做使用可查詢文檔 http://docs.cocos.com/creator...
回頭看Player的jump方法,這裏咱們的意圖是讓Player執行一個跳躍動做,當跳躍動做完成時將this.canJump改成true,cc.CallFunc也是一個動做,這個動做能夠執行你傳入的一個函數。因此上面的finishAction執行的時候就能夠將this.canJump改成true,cc.sequence用於將幾個動做鏈接依次執行。
能夠看到jumpAction傳入了不少參數,有些參數能夠直接根據名字猜到,有一些可能不知道表明什麼意思,這時你就要善於搜索api,另外要充分利用ts提示的功能,你能夠直接按住ctrl/cmd+鼠標單擊進入定義文件查看說明示例。
再來看Stage,能夠看到Player初始化的幾個參數是由Stage傳遞的,而且暴露在了編輯器界面,咱們能夠直接在Stage的屬性面板調整參數,來直觀的編輯動做效果,這也是Creator編輯器的方便之處。
上面的幾個參數是我調整事後的,你也能夠適當的修改,保存場景後預覽效果。
顯而易見,咱們不可能提早設置好全部的地面(Block),而是要根據Player跳躍的時機和地點動態添加Block,這就涉及到一個新的知識點——如何用代碼建立節點?
每個Block節點都是同樣的,對於這樣相同的節點能夠抽象出一個模板,Creator裏管這個模板叫作預製體(Prefab),想要一個新的節點時就能夠經過複製Prefab獲得。
製做一個Prefab很簡單,咱們先在res目錄下新建一個prefabs目錄,而後將Block節點直接拖到目錄裏就能夠造成一個Prefab了。
你能夠雙擊這個prefab進入其編輯模式,若是以前忘了將Block腳本掛在Block節點上,這裏也能夠掛在Block的Prefab上。
有了Prefab後,咱們就能夠利用函數cc.instance
來建立出一個節點。
根據以前講的組織代碼原則,建立Block的職責應該交給他的上級,也就是Stage。
以前編寫Player代碼時設置了一個index變量,用來記錄Player跳到了「第幾格」,根據遊戲邏輯每當Player跳躍動做完成後就要有新的Block出如今前面。修改Stage以下:
Stage.ts
import { Game } from './Game'; import { Player } from './Player'; import { Block } from './Block'; const { ccclass, property } = cc._decorator; @ccclass export class Stage extends cc.Component { @property(cc.Integer) private stepDistance: number = 200; @property(cc.Integer) private jumpHeight: number = 100; @property(cc.Float) private jumpDuration: number = 0.3; @property(Player) private player: Player = null; @property(cc.Prefab) private blockPrefab: cc.Prefab = null; // 編輯器屬性引用 private lastBlock = true; // 記錄上一次是否添加了Block private lastBlockX = 0; // 記錄上一次添加Block的x座標 private blockList: Array<Block>; // 記錄添加的Block列表 private game: Game = null; public init(game: Game) { this.game = game; this.player.init(this.stepDistance, this.jumpHeight, this.jumpDuration); this.blockList = []; this.addBlock(cc.v2(0, 0)); for (let i = 0; i < 5; i++) { this.randomAddBlock(); } } public playerJump(step: number) { if (this.player.canJump) { this.player.jump(step); this.moveStage(step); let isDead = !this.hasBlock(this.player.index); if (isDead) { cc.log('die'); this.game.overGame(); } else { this.game.addScore(step === 1 ? 1 : 3); // 跳一步得一分,跳兩步的三分 } } } private moveStage(step: number) { let moveAction = cc.moveBy(this.jumpDuration, cc.v2(-this.stepDistance * step, 0)); this.node.runAction(moveAction); for (let i = 0; i < step; i++) { this.randomAddBlock(); } } private randomAddBlock() { if (!this.lastBlock || Math.random() > 0.5) { this.addBlock(cc.v2(this.lastBlockX + this.stepDistance, 0)); } else { this.addBlank(); } this.lastBlockX = this.lastBlockX + this.stepDistance; } private addBlock(position: cc.Vec2) { let blockNode = cc.instantiate(this.blockPrefab); this.node.addChild(blockNode); blockNode.position = position; this.blockList.push(blockNode.getComponent(Block)); this.lastBlock = true; } private addBlank() { this.blockList.push(null); this.lastBlock = false; } private hasBlock(index: number): boolean { return this.blockList[index] !== null; } }
首先咱們在最上面添加了幾個成員變量又來記錄Block的相關信息。
而後修改了playerJump方法,讓player跳躍的同時執行moveStage,moveStage方法裏調用了一個moveBy動做,這個動做就是把節點相對移動一段距離,這裏要注意的是moveStage動做和player裏的jump動做水平移動的距離絕對值和時間都是相等的,player向前跳,stage向後移動,這樣兩個相反的動做,就會讓player始終處於屏幕中的固定位置而不會跳到屏幕外了。
再看moveStage方法裏會調用randomAddBlock,也就是隨機添加block,隨機算法要根據遊戲規則推理一下:
這個遊戲的操做分支只有兩個:1步或者是2步。因此每2個Block的間隔只能是0步或者1步。所以randomAddBlock裏會判斷最後一個Block是否爲空,若是爲空那新添加的必定不能爲空。若是不爲空則50%的機率隨機添加或不添加Block。這樣就能獲得無限隨機的地圖了。
爲了激勵玩家多按2步,因此設定跳1步的1分,跳2步得3分。
另外Player跳幾步randomAddBlock就要調用幾回,這樣才能保證地圖與Player跳躍距離相匹配。
再說一下addBlock方法,blockNode是由blockPrefab複製出來的,你必須經過addChild方法把它添加場景中的某個節點下才能讓它顯示出來,這裏的this.node就是Stage節點。爲了方便咱們把lastBlockX初始值設爲0,也就是水平第一個block的橫座標應該等於0,因此咱們要回到編輯器調整一下stage,player,block三個節點的位置,讓block和player的x都等於0,而且把Block的寬度設爲180(一步的距離設爲200,爲了讓兩個相鄰的Block有一點間距,要適當窄一些),最後不要忘記把BlockPrefab拖入對應的屬性上。
playerJump的的最後有一段判斷遊戲結束的邏輯,以前咱們在player裏設置了一個變量index,記錄player當前跳到第幾格,stage裏也有一個數組變量blockList保存着全部格子的信息,當player跳完後判斷一下落地點是否有格子就能夠判斷遊戲是否結束。
捋順上面的邏輯後,你就能夠預覽一下這個看起來有點樣子的遊戲了
若是每一步都讓玩家想好久,那這個遊戲就沒有盡頭了。如今咱們給它加點難度。
設置的效果是:地面每隔一段時間就會下落,若是玩家沒有及時跳到下一個格子就會跟着地面掉下去,爲了實現這我的物和地面同時下墜的效果,咱們要讓Player和Block執行相同的動做,因此在Stage上新加兩個變量fallDuration和fallHeight用來表明下落動做的時間和高度,而後傳給Player和Block讓它們執行。
另外這種小遊戲的難度必定是要隨着時間增長而增大的,因此Block的下落時間要愈來愈快。
下面咱們來修改Block,Player,Stage三個腳本
Block.ts
const { ccclass } = cc._decorator; @ccclass export class Block extends cc.Component { public init(fallDuration: number, fallHeight: number, destroyTime: number, destroyCb: Function) { this.scheduleOnce(() => { let fallAction = cc.moveBy(fallDuration, cc.v2(0, -fallHeight)); // 下沉動做 this.node.runAction(fallAction); destroyCb(); }, destroyTime); } }
這裏補充了Block的init方法,傳入了四個參數,分別是墜落動做的持續時間,墜落動做的高度,銷燬時間,銷燬的回調函數。
scheduleOnce是一個一次性定時函數,存在於cc.Component裏,因此你能夠在腳本里直接經過this來調用這個函數,這裏要實現的效果就是延遲destroyTime時間執行下落動做。
Player.ts
const { ccclass } = cc._decorator; @ccclass export class Player extends cc.Component { private stepDistance: number; // 一步跳躍距離 private jumpHeight: number; // 跳躍高度 private jumpDuration: number; // 跳躍持續時間 private fallDuration: number; // 墜落持續時間 private fallHeight: number; // 墜落高度 public canJump: boolean; // 此時是否能跳躍 public index: number; // 當前跳到第幾格 public init(stepDistance: number, jumpHeight: number, jumpDuration: number, fallDuration: number, fallHeight: number) { this.stepDistance = stepDistance; this.jumpHeight = jumpHeight; this.jumpDuration = jumpDuration; this.fallDuration = fallDuration; this.fallHeight = fallHeight; this.canJump = true; this.index = 0; } ... public die() { this.canJump = false; let dieAction = cc.moveBy(this.fallDuration, cc.v2(0, -this.fallHeight)); this.node.runAction(dieAction); } }
首先將init裏多傳入兩個變量fallDuration和fallHeight用來實現下落動做,而後補充die方法,這裏的下落動做實際上是個上面的Block裏的下落動做是同樣的。
Stage.ts
... @property(cc.Integer) private fallHeight: number = 500; @property(cc.Float) private fallDuration: number = 0.3; @property(cc.Float) private initStayDuration: number = 2; // 初始停留時間 @property(cc.Float) private minStayDuration: number = 0.3; // 最小停留時間,不能再快了的那個點,否則玩家就反應不過來了 @property(cc.Float) private speed: number = 0.1; private stayDuration: number; // 停留時間 ... public init(game: Game) { this.game = game; this.stayDuration = this.initStayDuration; this.player.init(this.stepDistance, this.jumpHeight, this.jumpDuration, this.fallDuration, this.fallHeight); this.blockList = []; this.addBlock(cc.v2(0, 0)); for (let i = 0; i < 5; i++) { this.randomAddBlock(); } } public addSpeed() { this.stayDuration -= this.speed; if (this.stayDuration <= this.minStayDuration) { this.stayDuration = this.minStayDuration; } cc.log(this.stayDuration); } public playerJump(step: number) { if (this.player.canJump) { this.player.jump(step); this.moveStage(step); let isDead = !this.hasBlock(this.player.index); if (isDead) { cc.log('die'); this.scheduleOnce(() => { // 這時還在空中,要等到落到地面在執行死亡動畫 this.player.die(); this.game.overGame(); }, this.jumpDuration); } else { let blockIndex = this.player.index; this.blockList[blockIndex].init(this.fallDuration, this.fallHeight, this.stayDuration, () => { if (this.player.index === blockIndex) { // 若是Block下落時玩家還在上面遊戲結束 this.player.die(); this.game.overGame(); } }); this.game.addScore(step === 1 ? 1 : 3); } if (this.player.index % 10 === 0) { this.addSpeed(); } } } ...
Player和Block下落動做都須要的fallDuration和fallHeight咱們提取到Stage裏,而後又添加了幾個屬性來計算Block存留時間。
在playerJump方法裏,補充了Player跳躍後的邏輯:若是Player跳空了,那麼就執行死亡動畫也就是下落動做,若是Player跳到Block上,那麼這個Block就啓動下落計時器,當Block下落時Player尚未跳走,那就和Player一塊兒掉下去。
最後增長下落速度的方式是每隔十個格子加速一次。
回到編輯器,調整fallDuration,fallHeight,initStayDuration,minStayDuration,speed的值。
預覽遊戲
前面講了這麼多,相信你能本身拼出下面這個界面。
上面掛載的OverPanel腳本以下:
OverPanel.ts
import { Game } from "./Game"; const { ccclass, property } = cc._decorator; @ccclass export class OverPanel extends cc.Component { @property(cc.Label) private scoreLabel: cc.Label = null; private game: Game; public init(game: Game) { this.game = game; } private onBtnRestart() { this.game.restartGame(); } private onBtnReturnMenu() { this.game.returnMenu(); } public show(score: number) { this.node.active = true; this.scoreLabel.string = score + ''; } public hide() { this.node.active = false; } }
不要忘了將兩個按鈕綁定到對應的方法上。
最後修改Game,讓遊戲結束時顯示OverPanel
Game.ts
import { Stage } from './Stage'; import { OverPanel } from './OverPanel'; const { ccclass, property } = cc._decorator; @ccclass export class Game extends cc.Component { @property(Stage) private stage: Stage = null; @property(cc.Label) private scoreLabel: cc.Label = null; @property(OverPanel) private overPanel: OverPanel = null; private score: number = 0; protected start() { this.overPanel.init(this); this.overPanel.hide(); this.startGame(); } public addScore(n: number) { this.score += n; this.scoreLabel.string = this.score + ''; } public startGame() { this.score = 0; this.scoreLabel.string = '0'; this.stage.init(this); } public overGame() { this.overPanel.show(this.score); } public restartGame() { cc.director.loadScene('game'); } public returnMenu() { cc.director.loadScene('menu'); } private onBtnOne() { this.stage.playerJump(1); } private onBtnTwo() { this.stage.playerJump(2); } }
將OverPanel的屬性拖上去。
爲了避免影響編輯器界面,你能夠將OverPanel節點隱藏
預覽效果
若是你玩過這個遊戲,確定知道聲音纔是其靈魂。
既然是Player發出的聲音,就掛在Player身上吧
Player.ts
const { ccclass, property } = cc._decorator; @ccclass export class Player extends cc.Component { @property({ type: cc.AudioClip }) private oneStepAudio: cc.AudioClip = null; @property({ type:cc.AudioClip }) private twoStepAudio: cc.AudioClip = null; @property({ type:cc.AudioClip }) private dieAudio: cc.AudioClip = null; ... public jump(step: number) { ... if (step === 1) { cc.audioEngine.play(this.oneStepAudio, false, 1); } else if (step === 2) { cc.audioEngine.play(this.twoStepAudio, false, 1); } } public die() { ... cc.audioEngine.play(this.dieAudio, false, 1); } }
這裏你可能比較奇怪的爲何這樣寫
@property({ type: cc.AudioClip }) private oneStepAudio: cc.AudioClip = null;
而不是這樣寫
@property(cc.AudioClip) private oneStepAudio: cc.AudioClip = null;
其實上面的寫法纔是完整寫法,除了type還有displayName等參數可選,當只須要type這個參數時能夠寫成下面那種簡寫形式,但例外的是有些類型只能寫完整形式,否則就會抱警告,cc.AudioClip就是其一。
在電腦上點擊兩個按鈕很難操做,因此咱們添加鍵盤的操做方式。
Game.ts
import { Stage } from './Stage'; import { OverPanel } from './OverPanel'; const { ccclass, property } = cc._decorator; @ccclass export class Game extends cc.Component { ... protected start() { ... this.addListeners(); } ... private addListeners() { cc.systemEvent.on(cc.SystemEvent.EventType.KEY_DOWN, (event: cc.Event.EventKeyboard) => { if (event.keyCode === cc.macro.KEY.left) { this.onBtnOne(); } else if (event.keyCode === cc.macro.KEY.right) { this.onBtnTwo(); } }, this); } }
在遊戲初始化的時候經過cc.systemEvent註冊鍵盤事件,按左方向鍵跳一步,按右方向鍵跳兩步。
至此咱們的遊戲就作完了。
若是你有基礎,這個遊戲並不難,若是這是你的第一篇教程,你可能會很吃力,不管前者後者,遇到任何問題均可以在下方留言,我也會隨時更新。
另外不要忘了加QQ交流羣哦 863758586