CreatorPrimer | 飛機大戰(一)

前兩天在Cocos官方公衆號上學習了「大掌教」的Cocos Creator 2.x Camera教程,總算是對攝像機組件有了一個初步的認識。乘熱打鐵,Shawn即刻就使用Camera攝像機練習了一個飛機遊戲的,目前主要實現3個功能:

  1. 無限滾動背景
  2. 控制飛機移動
  3. 子彈發射

下面是遊戲視頻:
image.png
視頻地址:https://v.youku.com/v_show/id_XNDA4NDAxODMyNA==.html?spm=a2hzp.8244740.0.0

1. 無限滾動背景

滾動背景我們當然是使用最新的攝像機來實現,我這裏做了一個卷軸攝像機組件ScrollCamera,我們現來看一下組件暴露的屬性:
滾動攝像機

ScrollCamera組件很像真實世界中的攝像機的推進器,Speed是推進速度,LoopGrounds是一個節點數組,他們是一組可首尾銜接的精靈節點,看下圖:
可首尾銜接的精靈節點

我們再看一下ScrollCamera組件的代碼:


cc.Class({
    editor: {
        requireComponent: cc.Camera,  //前置要求攝像機組件
    },
    extends: cc.Component,

    properties: {
        speed: 300,              //滾動速度
        loopGrounds: [cc.Node],  //循環節點
    },

    start () {
        //獲取節點上的攝像機組件
        this.camera = this.getComponent(cc.Camera);
    },

    /**
    *每幀更新函數
    *1. 更新攝像機位置
    *2. 檢查循環節點,設置新位置
    **/
    update(dt) {
        //獲取當前節點
        let current = this.loopGrounds[0];
        //計算當前節點在攝像機中的位置
        let pt = this.camera.getWorldToCameraPoint(current.position);
        //當前節點超出攝像機範圍(攝像機可視範圍就是屏幕大小)
        if (pt.y <= -cc.winSize.height) {
            //取最後一個地圖節點
            let last = this.loopGrounds[this.loopGrounds.length - 1];
            //將當前節點從數組中移除
            this.loopGrounds.shift();
            //將當前節點放到數組最後 
            this.loopGrounds.push(current);
            //將當前節點位置移動到最頂部位置
            current.y = last.y + (last.height + current.height) / 2;
        }
        //更新攝像機節點位置
        this.node.y += dt * this.speed;
    }
});

推動攝像機的代碼很簡單,看update函數中的最後一行:

this.node.y += dt * this.speed;

update中前面的幾行代碼是在做loopGrounds節點的檢查和位置更新,每一行都註釋,這裏就不再過多贅述了。

將這個組件直接拖動到場景編輯器或層級管理器,設置background節點爲background分組:

分組設置

同時設置ScrollCamera的cullingMask屬性只勾選background,看下圖:
攝像機分組

通過上面的設置和ScrollCamera的十幾代碼,無限滾動背景就搞定了。

2. 控制飛機移動

不知道大家還記得公衆號之前的一篇文章《Cocos Creator基礎教程(11)—可拖拽組件》,我直接將Dragable.js組件腳本拿過來,掛載到飛機節點上就OK了,代碼也很簡單:

/**
 * 可拖動組件
 */
cc.Class({
    extends: cc.Component,

    onLoad() {
        //註冊TOUCH_MOVE事件
        this.node.on(cc.Node.EventType.TOUCH_MOVE, this._onTouchMove, this);
        cc.log('onload');
    },

    _onTouchMove(touchEvent) {
        //let location = touchEvent.getLocation();
        //this.node.position = this.node.parent.convertToNodeSpaceAR(location); 

        //獲取觸摸移動增量
        let delta = touchEvent.getDelta();
        //當前節點位置+增量,更新節點位置
        this.node.position = delta.add(this.node.position);
    }
});

_onTouchMove函數稍微調整了一下,之前使用方法的是當前節點設置爲觸摸點位置,需要將全局座標轉換爲當前節點的父節點座標(設置一個節點的位置,是設置它在其父節點中的位置),拖動時節點總是保持在移動點的中心,特別是在第一次拖動節點時會有一個跳躍感,不夠平滑。

我這裏簡單改進了一下,通過獲取移動增量再加上當前節點位置,可以拖動節點的任意位置,不會出現突然將節點拉動到手指中心的突兀感。

Shawn在做這個飛機遊戲過程中也嘗試了一下消滅病毒當下這個火熱的遊戲,他的整個屏幕任意位置都可以控制飛機的移動,它是怎麼做的呢,大家先可以思考一下?

我們這裏再修改一下Dragable組件,增加一個target節點屬性,將它從飛機節點上移到外層foreground節點,看下圖:

可拖拽目標節點

觸摸事件發生在foreground節點上,但移動的是target屬性所指向的節點,我們看下代碼:

/**
 * 可拖動組件
 */
cc.Class({
    extends: cc.Component,
    properties: {
        target: cc.Node,
    },
    ...
    _onTouchMove(touchEvent) {
        //獲取觸摸移動增量
        let delta = touchEvent.getDelta();
        //如果this.target未設置,使用移動當前節點(兼容之前的用法)
        let node = this.target || this.node;
        //當前節點位置+增量,更新節點位置
        node.position = delta.add(node.position);
    }
});

代碼就增加了一個target節點的定義,在TouchMove事件中檢查this.target存在就用它,不存在默認移動當前節點,這樣可以兼容曾經該組件的地方,不用做修改。

3. 子彈發射

飛機遊戲的一個亮點就是子彈發射的華麗視覺效果,Shawn這裏在網上找了些子彈特效圖片,然後編輯了一個子彈Bullet的預製體,使用到之前文章《Cocos Creator基礎教程(12)—精靈變身》中的SpriteEx.js組件,在上面配置了幾張子彈圖片,使用index屬性可以方便切換子彈的表現效果,看下圖:

SpriteEx.gif

Bullet子彈只是表現效果,要讓子彈運動起來,我這裏編寫了一個LineEmmiter.js(線性發射器)的腳本,將它掛載到飛機節點上,用它來實例化Bullet預製體並讓它動起來,先看一下LineEmmiter組件的屬性:

線性發射器.png

之前的文章中提到過:組件爲節點賦予能力,飛機節點上有一個Sprite可顯示圖片紋理,我們再掛上LineEmmiter組件,讓它具有發射子彈的能力。

發射器的主要屬性是子彈預製體、發射頻率、子彈飛行速度,OffsetX屬性要特別一點,它可以控制子彈與飛機的偏移位置,以實現同時發射多行子彈的效果,看下圖:

多行發射.png

我們再看下發射器的組件代碼:

cc.Class({
    extends: cc.Component,

    properties: {
        prefab: cc.Prefab,
        rate: 1,        //發射間隔
        speed: 1000,    //移動速度
        offsetX: 0,
    },

    start() {
        this.schedule(this._emmitNode, this.rate);
    },

    _emmitNode() {
        //實例化節點,設置位置&父節
        let node = cc.instantiate(this.prefab);
        node.position = this.node.position;
        node.x += this.offsetX;
        node.parent = this.node.parent;
        //計算子彈需要飛行的距離,飛行時間 = 距離 / 速度
        let distance = ((cc.winSize.height / 2) - this.node.y);
        let duration = distance / this.speed;
        //使用moveBy動作,完成後刪除子彈節點
        let moveBy = cc.moveBy(duration, cc.v2(0, distance));
        let removeSelf = cc.removeSelf();
        let sequence = cc.sequence(moveBy, removeSelf);
        node.runAction(sequence);    
    }
});

發射器代碼也很簡單:

  1. 實例化子彈節點
  2. 讓子彈飛起來

我們這裏子彈是垂直飛行的,直接使moveBy動作就可以完成,子彈從當前飛機節點出發直到屏幕頂部結束,這是它飛行的距離根據公式:距離/速度=時間,計算每顆子彈的飛行時間,保證飛機在不同位置,所有子彈都是按同樣的速度飛行。

4. 小結

本次教程我們實現了一個最小飛機遊戲的簡單原型,我們的核心地圖滾動與子彈發射代碼只有70多行,有沒有覺得使用Cocos Creator開發遊戲飛一般的簡單呢…

不過還有很多欠缺的地方,比如:限制飛機不要跑出屏幕之外、子彈應該使用內存池進行優化,在功能上還缺少敵機生成、少子彈碰撞、得分計算等等,這些內容我們留到下次繼續。

想獲得源碼的同學可以在,公衆號回覆:“飛機”或“飛機大戰”,如果你對飛機遊戲有不同的實現方案,歡迎一起討論!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章