CreatorPrimer|飛機(jī)大戰(zhàn)(一)

前兩天在Cocos官方公眾號(hào)上學(xué)習(xí)了「大掌教」的Cocos Creator 2.x Camera教程碉纺,總算是對(duì)攝像機(jī)組件有了一個(gè)初步的認(rèn)識(shí)。乘熱打鐵刻撒,Shawn即刻就使用Camera攝像機(jī)練習(xí)了一個(gè)飛機(jī)游戲的骨田,目前主要實(shí)現(xiàn)3個(gè)功能:

  1. 無(wú)限滾動(dòng)背景
  2. 控制飛機(jī)移動(dòng)
  3. 子彈發(fā)射

下面是游戲視頻:

image.png

視頻地址:https://v.youku.com/v_show/id_XNDA4NDAxODMyNA==.html?spm=a2hzp.8244740.0.0

1. 無(wú)限滾動(dòng)背景

滾動(dòng)背景我們當(dāng)然是使用最新的攝像機(jī)來(lái)實(shí)現(xiàn)优质,我這里做了一個(gè)卷軸攝像機(jī)組件ScrollCamera渠啤,我們現(xiàn)來(lái)看一下組件暴露的屬性:


滾動(dòng)攝像機(jī)

ScrollCamera組件很像真實(shí)世界中的攝像機(jī)的推進(jìn)器,Speed是推進(jìn)速度次企,LoopGrounds是一個(gè)節(jié)點(diǎn)數(shù)組醋火,他們是一組可首尾銜接的精靈節(jié)點(diǎn)悠汽,看下圖:


可首尾銜接的精靈節(jié)點(diǎn)

我們?cè)倏匆幌耂crollCamera組件的代碼:


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

    properties: {
        speed: 300,              //滾動(dòng)速度
        loopGrounds: [cc.Node],  //循環(huán)節(jié)點(diǎn)
    },

    start () {
        //獲取節(jié)點(diǎn)上的攝像機(jī)組件
        this.camera = this.getComponent(cc.Camera);
    },

    /**
    *每幀更新函數(shù)
    *1. 更新攝像機(jī)位置
    *2. 檢查循環(huán)節(jié)點(diǎn),設(shè)置新位置
    **/
    update(dt) {
        //獲取當(dāng)前節(jié)點(diǎn)
        let current = this.loopGrounds[0];
        //計(jì)算當(dāng)前節(jié)點(diǎn)在攝像機(jī)中的位置
        let pt = this.camera.getWorldToCameraPoint(current.position);
        //當(dāng)前節(jié)點(diǎn)超出攝像機(jī)范圍(攝像機(jī)可視范圍就是屏幕大薪娌怠)
        if (pt.y <= -cc.winSize.height) {
            //取最后一個(gè)地圖節(jié)點(diǎn)
            let last = this.loopGrounds[this.loopGrounds.length - 1];
            //將當(dāng)前節(jié)點(diǎn)從數(shù)組中移除
            this.loopGrounds.shift();
            //將當(dāng)前節(jié)點(diǎn)放到數(shù)組最后 
            this.loopGrounds.push(current);
            //將當(dāng)前節(jié)點(diǎn)位置移動(dòng)到最頂部位置
            current.y = last.y + (last.height + current.height) / 2;
        }
        //更新攝像機(jī)節(jié)點(diǎn)位置
        this.node.y += dt * this.speed;
    }
});

推動(dòng)攝像機(jī)的代碼很簡(jiǎn)單柿冲,看update函數(shù)中的最后一行:

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

update中前面的幾行代碼是在做loopGrounds節(jié)點(diǎn)的檢查和位置更新,每一行都注釋?zhuān)@里就不再過(guò)多贅述了兆旬。

將這個(gè)組件直接拖動(dòng)到場(chǎng)景編輯器或?qū)蛹?jí)管理器姻采,設(shè)置background節(jié)點(diǎn)為background分組:

分組設(shè)置

同時(shí)設(shè)置ScrollCamera的cullingMask屬性只勾選background,看下圖:


攝像機(jī)分組

通過(guò)上面的設(shè)置和ScrollCamera的十幾代碼爵憎,無(wú)限滾動(dòng)背景就搞定了慨亲。

2. 控制飛機(jī)移動(dòng)

不知道大家還記得公眾號(hào)之前的一篇文章《Cocos Creator基礎(chǔ)教程(11)—可拖拽組件》,我直接將Dragable.js組件腳本拿過(guò)來(lái)宝鼓,掛載到飛機(jī)節(jié)點(diǎn)上就OK了刑棵,代碼也很簡(jiǎn)單:

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

    onLoad() {
        //注冊(cè)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); 

        //獲取觸摸移動(dòng)增量
        let delta = touchEvent.getDelta();
        //當(dāng)前節(jié)點(diǎn)位置+增量,更新節(jié)點(diǎn)位置
        this.node.position = delta.add(this.node.position);
    }
});

_onTouchMove函數(shù)稍微調(diào)整了一下愚铡,之前使用方法的是當(dāng)前節(jié)點(diǎn)設(shè)置為觸摸點(diǎn)位置蛉签,需要將全局坐標(biāo)轉(zhuǎn)換為當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn)坐標(biāo)(設(shè)置一個(gè)節(jié)點(diǎn)的位置胡陪,是設(shè)置它在其父節(jié)點(diǎn)中的位置),拖動(dòng)時(shí)節(jié)點(diǎn)總是保持在移動(dòng)點(diǎn)的中心碍舍,特別是在第一次拖動(dòng)節(jié)點(diǎn)時(shí)會(huì)有一個(gè)跳躍感柠座,不夠平滑。

我這里簡(jiǎn)單改進(jìn)了一下片橡,通過(guò)獲取移動(dòng)增量再加上當(dāng)前節(jié)點(diǎn)位置妈经,可以拖動(dòng)節(jié)點(diǎn)的任意位置,不會(huì)出現(xiàn)突然將節(jié)點(diǎn)拉動(dòng)到手指中心的突兀感捧书。

Shawn在做這個(gè)飛機(jī)游戲過(guò)程中也嘗試了一下消滅病毒當(dāng)下這個(gè)火熱的游戲吹泡,他的整個(gè)屏幕任意位置都可以控制飛機(jī)的移動(dòng),它是怎么做的呢经瓷,大家先可以思考一下爆哑?

我們這里再修改一下Dragable組件,增加一個(gè)target節(jié)點(diǎn)屬性舆吮,將它從飛機(jī)節(jié)點(diǎn)上移到外層foreground節(jié)點(diǎn)揭朝,看下圖:

可拖拽目標(biāo)節(jié)點(diǎn)

觸摸事件發(fā)生在foreground節(jié)點(diǎn)上,但移動(dòng)的是target屬性所指向的節(jié)點(diǎn)色冀,我們看下代碼:

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

代碼就增加了一個(gè)target節(jié)點(diǎn)的定義呐伞,在TouchMove事件中檢查this.target存在就用它敌卓,不存在默認(rèn)移動(dòng)當(dāng)前節(jié)點(diǎn)慎式,這樣可以兼容曾經(jīng)該組件的地方伶氢,不用做修改。

3. 子彈發(fā)射

飛機(jī)游戲的一個(gè)亮點(diǎn)就是子彈發(fā)射的華麗視覺(jué)效果瘪吏,Shawn這里在網(wǎng)上找了些子彈特效圖片癣防,然后編輯了一個(gè)子彈Bullet的預(yù)制體,使用到之前文章《Cocos Creator基礎(chǔ)教程(12)—精靈變身》中的SpriteEx.js組件掌眠,在上面配置了幾張子彈圖片蕾盯,使用index屬性可以方便切換子彈的表現(xiàn)效果,看下圖:

SpriteEx.gif

Bullet子彈只是表現(xiàn)效果蓝丙,要讓子彈運(yùn)動(dòng)起來(lái)级遭,我這里編寫(xiě)了一個(gè)LineEmmiter.js(線性發(fā)射器)的腳本,將它掛載到飛機(jī)節(jié)點(diǎn)上渺尘,用它來(lái)實(shí)例化Bullet預(yù)制體并讓它動(dòng)起來(lái)挫鸽,先看一下LineEmmiter組件的屬性:

線性發(fā)射器.png

之前的文章中提到過(guò):組件為節(jié)點(diǎn)賦予能力,飛機(jī)節(jié)點(diǎn)上有一個(gè)Sprite可顯示圖片紋理鸥跟,我們?cè)賿焐螸ineEmmiter組件丢郊,讓它具有發(fā)射子彈的能力盔沫。

發(fā)射器的主要屬性是子彈預(yù)制體、發(fā)射頻率枫匾、子彈飛行速度架诞,OffsetX屬性要特別一點(diǎn),它可以控制子彈與飛機(jī)的偏移位置干茉,以實(shí)現(xiàn)同時(shí)發(fā)射多行子彈的效果谴忧,看下圖:

多行發(fā)射.png

我們?cè)倏聪掳l(fā)射器的組件代碼:

cc.Class({
    extends: cc.Component,

    properties: {
        prefab: cc.Prefab,
        rate: 1,        //發(fā)射間隔
        speed: 1000,    //移動(dòng)速度
        offsetX: 0,
    },

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

    _emmitNode() {
        //實(shí)例化節(jié)點(diǎn),設(shè)置位置&父節(jié)
        let node = cc.instantiate(this.prefab);
        node.position = this.node.position;
        node.x += this.offsetX;
        node.parent = this.node.parent;
        //計(jì)算子彈需要飛行的距離等脂,飛行時(shí)間 = 距離 / 速度
        let distance = ((cc.winSize.height / 2) - this.node.y);
        let duration = distance / this.speed;
        //使用moveBy動(dòng)作俏蛮,完成后刪除子彈節(jié)點(diǎn)
        let moveBy = cc.moveBy(duration, cc.v2(0, distance));
        let removeSelf = cc.removeSelf();
        let sequence = cc.sequence(moveBy, removeSelf);
        node.runAction(sequence);    
    }
});

發(fā)射器代碼也很簡(jiǎn)單:

  1. 實(shí)例化子彈節(jié)點(diǎn)
  2. 讓子彈飛起來(lái)

我們這里子彈是垂直飛行的,直接使moveBy動(dòng)作就可以完成上遥,子彈從當(dāng)前飛機(jī)節(jié)點(diǎn)出發(fā)直到屏幕頂部結(jié)束搏屑,這是它飛行的距離根據(jù)公式:距離/速度=時(shí)間,計(jì)算每顆子彈的飛行時(shí)間粉楚,保證飛機(jī)在不同位置辣恋,所有子彈都是按同樣的速度飛行。

4. 小結(jié)

本次教程我們實(shí)現(xiàn)了一個(gè)最小飛機(jī)游戲的簡(jiǎn)單原型模软,我們的核心地圖滾動(dòng)與子彈發(fā)射代碼只有70多行伟骨,有沒(méi)有覺(jué)得使用Cocos Creator開(kāi)發(fā)游戲飛一般的簡(jiǎn)單呢...

不過(guò)還有很多欠缺的地方,比如:限制飛機(jī)不要跑出屏幕之外燃异、子彈應(yīng)該使用內(nèi)存池進(jìn)行優(yōu)化携狭,在功能上還缺少敵機(jī)生成、少子彈碰撞回俐、得分計(jì)算等等逛腿,這些內(nèi)容我們留到下次繼續(xù)。

想獲得源碼的同學(xué)可以在仅颇,公眾號(hào)回復(fù):“飛機(jī)”或“飛機(jī)大戰(zhàn)”单默,如果你對(duì)飛機(jī)游戲有不同的實(shí)現(xiàn)方案,歡迎一起討論忘瓦!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末搁廓,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子耕皮,更是在濱河造成了極大的恐慌境蜕,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件凌停,死亡現(xiàn)場(chǎng)離奇詭異粱年,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)苦锨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)逼泣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)趴泌,“玉大人,你說(shuō)我怎么就攤上這事拉庶∈茹荆” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵氏仗,是天一觀的道長(zhǎng)吉捶。 經(jīng)常有香客問(wèn)我,道長(zhǎng)皆尔,這世上最難降的妖魔是什么呐舔? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮慷蠕,結(jié)果婚禮上珊拼,老公的妹妹穿的比我還像新娘。我一直安慰自己流炕,他們只是感情好澎现,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著每辟,像睡著了一般剑辫。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上渠欺,一...
    開(kāi)封第一講書(shū)人閱讀 51,541評(píng)論 1 305
  • 那天妹蔽,我揣著相機(jī)與錄音,去河邊找鬼挠将。 笑死胳岂,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的捐名。 我是一名探鬼主播旦万,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼闹击,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼镶蹋!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起赏半,我...
    開(kāi)封第一講書(shū)人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤贺归,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后断箫,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體拂酣,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年仲义,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了婶熬。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片剑勾。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖赵颅,靈堂內(nèi)的尸體忽然破棺而出虽另,到底是詐尸還是另有隱情,我是刑警寧澤饺谬,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布捂刺,位于F島的核電站,受9級(jí)特大地震影響募寨,放射性物質(zhì)發(fā)生泄漏族展。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一拔鹰、第九天 我趴在偏房一處隱蔽的房頂上張望仪缸。 院中可真熱鬧,春花似錦列肢、人聲如沸腹殿。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)锣尉。三九已至,卻和暖如春决采,著一層夾襖步出監(jiān)牢的瞬間自沧,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工树瞭, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留拇厢,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓晒喷,卻偏偏與公主長(zhǎng)得像孝偎,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子凉敲,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容