CocosCreator經典入門項目之flappybird

開發環境

CocosCreator v2.3.1

node.js v10.16.0

vscode 1.46.1

遊戲引擎概念

可以理解為一套已經編寫好的代碼,它封裝瞭對底層接口的使用,是遊戲開發的核心功能提供者。

一般分為6各部分:

  1. 圖像渲染:控制電腦對遊戲繪畫的繪畫操作,直接影響遊戲質量
  2. 音頻UI:提供音頻特效,以及遊戲UI部分,讓遊戲與用戶交互更好
  3. 設備輸入:鍵盤、鼠標、陀螺儀等
  4. 腳本引擎:提供腳本接口,為遊戲開發者提供“筆墨”
  5. 網絡引擎:數據交互模塊,用服務器為客戶端提供交互
  6. 物理引擎(高級):模擬現實的物理效果(重力加速度、物體間的碰撞等)。

關於Cocos Creator

項目結構

ProjectName(項目文件夾)
├──assets 資源文件夾———-用來放置遊戲中所有的本地資源、腳本和第三方庫文件
├──library 資源庫—————-這裡文件的結構和資源格式將被處理成最終遊戲發佈時需要的形式
├──local 本地設置————-存放項目本機刪的配置信息(編輯器面板佈局、窗口大小、位置等)
├──packages 擴展插件文件夾—存放項目的自定義擴展插件
├──settings 項目設置————-保存項目的相關設置,如構建發佈菜單裡的包名、場景和平臺選擇
├──temp 臨時文件夾———-用於緩存CocosCreator在本地的臨時文件
└──project.json 驗證文件————-作為驗證CocosCreator項目合法性的標志

下面開始進入真正的項目上手

配置代碼編輯環境

Visual Studio Code (以下簡稱 VS Code)是微軟新推出的輕量化跨平臺 IDE,支持 Windows、Mac、Linux 平臺,安裝和配置非常簡單。使用 VS Code 管理和編輯項目腳本代碼,可以輕松實現語法高亮、智能代碼提示等功能。

安裝 Cocos Creator API 適配插件

該操作會將 Cocos Creator API 適配插件安裝到 VS Code 全局的插件文件夾中,安裝成功後在 控制臺 會顯示綠色的提示:VS Code extension installed to ...。這個插件的主要功能是為 VS Code 編輯狀態下註入符合 Cocos Creator 組件腳本使用習慣的語法提示。

在項目中生成智能提示數據

如果希望在代碼編寫過程中自動提示 Cocos Creator 引擎 API,需要通過菜單生成 API 智能提示數據並自動放進項目路徑下。

選擇主菜單的 開發者 -> VS Code 工作流 -> 更新 VS Code 智能提示數據。該操作會將根據引擎 API 生成的 creator.d.ts 數據文件復制到項目根目錄下(註意是在 assets 目錄外面),操作成功時會在 控制臺 顯示綠色提示:API data generated and copied to ...

使用 VS Code 激活腳本編譯

使用外部文本編輯器修改項目腳本後,要重新激活 Cocos Creator 窗口才能觸發腳本編譯,我們在新版本的 Creator 中增加瞭一個預覽服務器的 API,可以通過向特定地址發送請求來激活編輯器的編譯。

新建項目

1.新建一個空白項目

2.資源管理器

然後你需要在資源管理中創建項目中最重要場景、腳本文件,以及導入遊戲所需要的紋理(圖片資源)。這裡的文件夾不是默認創建的,你需要手動創建,便於管理你的項目。需要說明的是resources是CocosCreator(以下簡述cocos)中特殊的資源文件夾,所有需要通過cc.loader.loadRes動態加載(後續會提到這個方法)的資源,都必須放置在resources文件夾和它的子文件夾下。如果一份資源僅僅是被resources中的其他資源所依賴,而不需要直接被cc.loader.loadRes調用,就不需要放在resources文件夾裡。

3.場景

在scenes中新建場景,scenes–右鍵–新建scenes場景,在 Cocos Creator 中,遊戲場景(Scene) 是開發時組織遊戲內容的中心,也是呈現給玩傢所有遊戲內容的載體。遊戲場景中一般會包括以下內容:

  • 場景圖像和文字(Sprite,Label)
  • 角色
  • 以組件形式附加在場景節點上的遊戲邏輯腳本

當玩傢運行遊戲時,就會載入遊戲場景,遊戲場景加載後就會自動運行所包含組件的遊戲腳本,實現各種各樣開發者設置的邏輯功能。所以除瞭資源以外,遊戲場景是一切內容創作的基礎。現在,讓我們來新建一個場景。入門項目flappybird隻需要新建一個場景,你完成這個項目後的效果大致是這個亞子。

4.場景編輯器、層級管理器、屬性檢查器

雙擊你所創建的bird場景,cocos就會在 場景編輯器層級管理器 中打開這個場景。打開場景後, 層級管理器 中會顯示當前場景中的所有節點和它們的層級關系。我們剛剛新建的場景中隻有一個名叫 Canvas 的節點,Canvas 可以被稱為畫佈節點或渲染根節點,點擊選中 Canvas,可以在 屬性檢查器 中看到他的屬性。

從資源包裡面的texture目錄下將名為的sky背景圖片拖到Canvas中,作為遊戲背景。調整Canvas和sky的size尺寸大小。sky的size至少要大於Canvas,不然你制作的遊戲可能會有很大的黑邊。然後用相似的方法把bird0(其他兩張是為瞭配合作出簡易幀動畫,模擬小鳥的飛行)、pipe1(下管道)、pipe2(上管道)添加到Canvas下。上下管道為一組,我復制瞭4組,一共5組。通過腳本控制背景和每組管道向左移動來達到小鳥持續向前飛行的效果。

5.節點綁定

需要註意,Canvas下的元素都是以node節點的形式來被管理的。在script中新建腳本文件—game.js,將其拖入Canvas中,或者直接綁定到Canvas上。確保在加載場景時腳本被一並加載。

6.生命周期回調

Cocos Creator 為組件腳本提供瞭生命周期的回調函數。用戶隻要定義特定的回調函數,Creator 就會在特定的時期自動執行相關腳本,用戶不需要手工調用它們。

目前提供給用戶的生命周期回調函數主要有:

  • onLoad onLoad 回調會在節點首次激活時觸發,比如所在的場景被載入,或者所在節點被激活的情況下。而且onLoad 總是會在任何 start 方法調用前執行,通常我們會在 onLoad 階段去做一些初始化相關的操作。
  • start start 回調函數會在組件第一次激活前,也就是第一次執行 update 之前觸發。start 通常用於初始化一些需要經常修改的數據,這些數據可能在 update 時會發生改變。
  • update 遊戲開發的一個關鍵點是在每一幀渲染前更新物體的行為,狀態和方位。這些更新操作通常都放在 update 回調中。以下四個回調函數在此項目中不會用到
  • lateUpdate
  • onDestroy
  • onEnable
  • onDisable

主要代碼

game.js

cc.Class({
    extends: cc.Component,

    properties: {
        skyNode: cc.Node,//定義天空節點
        pipeNode: cc.Node,//定義管道節點
        birdNode: cc.Node,//定義小鳥節點
        clickLayerNode: cc.Node,//定義監聽節點  監聽鼠標點擊事件
        scoreNode: cc.Node,//定義得分節點    總得分節點
        buttonNode: cc.Node,//定義按鈕節點   開始遊戲按鈕
        numberNode: cc.Node,//定義數字節點   加分combo
        overNode: cc.Node,//定義遊戲結束節點  結束按鈕
        spriteFrame: {//定義精靈框架節點,
            default: [],//數組類型,將會綁定bird0、bird1、bird2三張圖片精靈,通過在update()方法中不斷更換,形成動畫
            type: cc.SpriteFrame //圖片精靈類型
        },
        clip: {//定義音效節點
            default: [],//同樣為數組類型,便於綁定多個資源。後續學習,可嘗試使用動態加載
            type: cc.AudioClip  //音頻類型
        }
    },
    onClickButton() {//設置點擊按鈕方法   
        this.num = 0;//將num重置為0
        this.sign = true;//設置控制遊戲是否繼續的標識符為真
        this.buttonNode.active = false;//讓按鈕節點不可見
        this.overNode.active = false;//讓控制“遊戲結束”文本的overNode節點不可見
        this.birdNode.y = 50;//點擊按鈕後小鳥的位置歸位
        this.power = 0;//將力量因素變為0,防止小鳥復活後下落太快
        this.scoreNode.getComponent(cc.Label).string = "" + this.num;//將分數節點的string值變為0,this.scoreNode.getComponent(cc.Label).string
        let list = this.pipeNode.children;//用一個list存儲金屬管道的子節點(.children)
        for (let i = 0; i < list.length; i++) {//設置一個循環,終止條件是i小於list的長度
            let child = list[i];//let 一個child變量用於在循環中存儲每個list[i]
            child.x += 1000;//將管道節點的x右移1000
        }
        cc.audioEngine.playMusic(this.clip[0], true);
    },
    onClickBagButton(event, data) {  //定義背包按鈕方法
        // cc.log(event, data);
        if (data == "bag") {//判斷傳過來的參數等於某event的CustomEventData
            this.showBag();  // 調用顯示背包函數
        }
    },
    showBag() {  //定義顯示背包函數
        if (this.bagPrefab == null) {  //如果資源加載沒有成功
            setTimeout(() => {  //設置延時0.5s後繼續調用顯示bag方法
                this.showBag();
            }, 500);
            return;
        }
        //資源加載完成
        let node = null;    //定義一個node賦值為空
        if(this.isOpen){  //判斷背包是否打開,this.isOpen初始值為false
            node = cc.find("Canvas/panelBag");
            node.active = true;
        }
        else{
            node = cc.instantiate(this.bagPrefab);  //加載具體的預置資源並賦值給node
            cc.find("Canvas").addChild(node);  //將node節點添加到Canvas幕佈下
        }
        node.opacity = 0;//設置node節點的透明度為0;
        node.scale = 0.1;//設置node節點的初始縮放為0.1;
        let ac = cc.spawn(  //封裝並行的動畫並賦值給ac
            cc.fadeIn(0.5),  //0.5s的速度淡入
            cc.scaleTo(0.5,1),//0.5s的速度縮放到1
        );
        node.runAction(ac); //用runAction函數執行封裝好的ac
        this.isOpen = true;//將背包打開參數賦值true
    },
    gameOver() {    //設置遊戲結束方法
        this.sign = false;//遊戲結束,將遊戲繼續標識符變為false
        this.checkStill = false;//檢查遊戲是否進行參數變為false
        this.buttonNode.active = true;//遊戲結束,讓開始按鈕this.buttonNode為可見
        this.overNode.active = true;//遊戲結束,讓“遊戲結束”文本的overNode節點可見
        cc.audioEngine.stopMusic(this.clip[0]);  //遊戲結束停止背景音樂
    },
    addScore() {    //設置加分方法
        this.numberNode.opacity = 255;//讓分數節點numberNode的.opacity元素(透明度)為255
        this.num++;//讓num值++
        this.scoreNode.getComponent(cc.Label).string = "" + this.num;//讓分數節點的string元素=空的的字符串“” 加num
        this.numberNode.y = this.birdNode.y;//讓加分combo節點numberNode的y和小鳥節點的y相等
        this.numberNode.runAction(//讓加分combo節點numberNode漸入漸出runAction,spawn,fadeOut,moveBy
            cc.spawn(
                cc.fadeOut(0.5),
                cc.moveBy(0.5, cc.v2(0, 50))
            )
        )
        cc.audioEngine.playEffect(this.clip[2]);  //加分音樂
    },

    // LIFE-CYCLE CALLBACKS:

    onLoad() {
        // cc.director.getCollisionManager().enabled = true;     //打開碰撞管理系統cc.director.getCollisionManager().
        this.bagPrefab = null;//定義bagPrefab變量賦值為空
        // cc.loader.loadRes(路徑,資源類型,回調函數);error如果錯誤,打印錯誤信息,data為加載成功的資源
        cc.loader.loadRes("prefab/panelBag", cc.Prefab, (error, data) => {
            if (error) {//判斷如果錯誤信息不為空
                cc.log(error);//打印錯誤信息
                return;         
            }
            this.bagPrefab = data; //將加載到的資源賦值給this.bafPrefab
        });
    },

    start() {
        this.isOpen = false;//定義背包是否打開變量並置為false;
        this.num = 0;//將num參數變為0,防止遊戲再開始時,得分繼承上局的分數
        this.scoreNode.getComponent(cc.Label).string = "" + 0;//設置分數初始值為0
        this.speed = 5;//設置相對位移速度為5
        this.power = 0;//設置力量參數為0
        this.checkStill = true;//檢查遊戲是否進行參數變為true
        this.curFrame = 0;//定義一個變量用於循環skinnode列表
        this.sign = false;//定義一個標識符控制遊戲是否開始,初始值為false
        this.checkState = false;// false-非碰撞檢測狀態 true-碰撞檢測狀態
        this.up = 0;//
        this.clickLayerNode.on(cc.Node.EventType.TOUCH_START, () => {//誰.on(cc.Node.EventType類型.事件,執行匿名方法() =>)
            this.power = 4;//將初始的力量參數直接由0置為4,確保每次監聽到點擊小鳥有比較明顯的上升
            this.up++;
            cc.audioEngine.playEffect(this.clip[1]);
        })

        cc.audioEngine.playMusic(this.clip[0], true);
    },

    update(dt) {
        if (!this.sign) {//設置讓遊戲暫停的標識符
            return;
        }
        cc.log(2);
        this.skyNode.x -= this.speed;//通過控制天空節點的x值來控制背景移動   
        this.birdNode.y += this.power + this.up;//通過小鳥節點的y值和初始的力量參數來控制小鳥自由下落的速度
        this.power -= 0.2;//通過讓power小幅度值漸變達到讓小鳥平滑移動
        this.birdNode.angle = this.speed * this.power;//通過力量和速度參數控制小鳥上升和下降的角度
        if (this.skyNode.x < -1200) {//判斷當背景和起點相隔1200像素時,讓背景節點skyNode.x歸位=0(無限循環背景)
            this.skyNode.x = 0;
        }
        //node.children即管道節點的子節點
        let list = this.pipeNode.children;//用一個list存儲金屬管道的子節點(.children)
        let checkNode = null;//定義檢查管道節點變量並賦值為null
        for (let i = 0; i < list.length; i++) {//用循環賦值所有管道節點 並賦予速度
            let child = list[i];//let一個child變量來存儲list中的每個元素
            child.x -= this.speed;//控制管道節點的x-=this.speed
            // cc.log(child);
            if (child.x < -600) {
                child.x = 600;//判斷child出界< -600時讓child歸位到600
                child.y = (Math.random() - 0.5) * 200;//通過Math.random()(其值在0-1之間)函數來控制管道通過口隨機出現,緩和值為200
            }
            let dis = Math.abs(this.birdNode.x - child.x)//let一個變量dis用於計算小鳥和管道的x的差值(Math.abs取絕對值)
            let width = (this.birdNode.width + child.children[0].width) / 2;//定義width變量用於存儲小鳥和管道碰撞的臨界值
            if (dis < width) {//判斷 dis <= width,就給檢查管道節點變量賦值child
                checkNode = child;
            }
        }
        if(this.birdNode.y + this.birdNode.height / 2 > cc.winSize.height / 2  //判斷小鳥的頭部大於屏幕的上邊緣或者小鳥的底部小於屏幕的下邊緣
            || this.birdNode.y - this.birdNode.height / 2 < -cc.winSize.height / 2){
                this.gameOver();//執行遊戲結束方法
            }
        if(checkNode) {//直接判斷checkNode,如果未被賦值即為空
            this.checkState = true;//狀態從無到有,將檢查狀態變量checkState賦值為true
            //判斷矩形小鳥的上邊框(.y + height/2)大於等於通道上邊框(checkNode.y+100)或者小鳥的下邊框小於等於通道
            if (this.birdNode.y + this.birdNode.height / 2 > checkNode.y + 100
                || this.birdNode.y - this.birdNode.height / 2 < checkNode.y) {
                this.gameOver();//遊戲結束
            }
        }else{
            if (this.checkState && this.checkStill) {//判斷檢查狀態變量和檢查遊戲是否進行變量是否都為true(&&)
                this.addScore();//調用加分函數
            }
            this.checkStill = true; //將檢查遊戲是否進行變量賦值true
            this.checkState = false;//將檢查狀態變量賦值為false
            this.up = 0;
        }
        this.curFrame++;//小鳥幀率變量自增
        if (this.curFrame > 2) {//判斷如果幀率變量大於2,將幀率變量變為0;
            this.curFrame = 0;
        }
        if (this.birdNode.y) {//如果力量參數大於0
            //讓小鳥節點的Sprite組件的spriteFrame參數隨幀率參數變化
            this.birdNode.getComponent(cc.Sprite).spriteFrame = this.spriteFrame[this.curFrame];
        }
    }
})

總結

上述關於小鳥、鋼管是否碰撞的檢測是通過數學計算的方法實現的。不過我的項目文件中還保留瞭使用cocos碰撞組件的版本,具體表現為每個pipe節點、entrance節點身上的BoxCollider組件,以及bird.js。另外還有我學習制作的一個背包,主要通過預置(cc.prefab)節點實現瞭背包窗口以及在窗口中動態加載道具圖片(sprite)。本人也在學習階段,有問題歡迎評論區交流。筆者後續還準備分享一些其他項目!包括單機和局域網聯機版本的對比項目;可能還會用到一些優化策略如:資源管理器、網絡通訊管理器、信號槽等,不足之處希望各位大佬輕噴。

以上就是CocosCreator經典入門項目之flappybird的詳細內容,更多關於CocosCreator制作flappybird的資料請關註WalkonNet其它相關文章!

推薦閱讀:

    None Found