Cocos Creator中實現(xiàn)相對地圖運動的粒子系統(tǒng)

最近在做一個H5的海戰(zhàn)類小游戲。

1.jpg

地圖很大,船在邊角位置的時候,相對世界坐標(biāo)有絕對運動,也就是說地圖不動船在動。但是在中間位置的時候,地圖和船同時運動,最后的顯示效果,相當(dāng)于船在屏幕中間只轉(zhuǎn)向不運動,而地圖在運動。

實現(xiàn)這樣的效果其實并不難。首先船在海上運動,船的x,y坐標(biāo)是相對地圖(海)的坐標(biāo)。然后根據(jù)船的位置調(diào)整海的坐標(biāo):

    _setPos: function (boatX,boatY) {
        let x = -boatX;
        let y = -boatY;

        if (x < -this.xLimit) {
            x = -this.xLimit;
        } else if (x > this.xLimit) {
            x = this.xLimit;
        }

        if (y < -this.yLimit) {
            y = -this.yLimit;
        } else if (y > this.yLimit) {
            y = this.yLimit;
        }

        this.node.x = x;
        this.node.y = y;
    }

其中,xLimit是用地圖的寬度減去設(shè)計分辨率寬度然后除2;yLimit是用地圖的高度減去設(shè)計分辨率高度然后除2。

我們要給船在運動的時候加上水花拖尾的效果,首先想到的就是用粒子系統(tǒng)來實現(xiàn)。然后發(fā)現(xiàn),當(dāng)船在邊角位置移動的時候,有完美的水花拖尾效果,但是船運動到中間以后,由于船相對世界坐標(biāo)沒有運動,拖尾就沒有了。

解決這個問題,在原來cocos的系統(tǒng)中,可以設(shè)置粒子系統(tǒng)里面的positionType,將默認(rèn)的PositionType::FREE設(shè)置為 PositionType::RELATIVE,然而在Creator中我們發(fā)現(xiàn)將positionType由0設(shè)置為1并沒有什么用。

查官方文檔,終于發(fā)現(xiàn)Creator里面并不支持:


positonType.png

怎么辦呢?

自己做一個粒子系統(tǒng)來實現(xiàn)吧。用js實現(xiàn)的效率可能略低,但是總比做不了的好,效率等做出來看了再說。

原理:

每幀在船所在位置下面的海面上貼一個粒子發(fā)射器,每個粒子發(fā)射器發(fā)射3-5個粒子,每個粒子的生命期從0-0.8秒左右隨機,當(dāng)粒子生命期結(jié)束后,主動將自己從發(fā)射器節(jié)點上刪除;當(dāng)發(fā)射器上所有的粒子都已經(jīng)結(jié)束生命期,發(fā)射器主動將自身從父節(jié)點刪除。粒子的位置有一個小范圍隨機,將用作粒子的圖片從0到一個固定的scale進行縮放。數(shù)值可以調(diào)整,生存期長,粒子拖尾會比較長,目標(biāo)scale大,拖尾的尺寸就比較大。具體還可以做一些顏色、透明度等變化。粒子發(fā)射器不跟隨船運動,這樣在船快速運動的時候,就會出現(xiàn)明顯的拖尾。

實戰(zhàn):

首先,自定義一個Prefab做成粒子發(fā)射器,取名為ParticleEmitter。實質(zhì)是一個空節(jié)點,上面掛一個腳本,用于控制粒子發(fā)射。然后在Scene的update里面,每一幀產(chǎn)生一個ParticleEmitter,放到當(dāng)前船所在的位置,貼到地圖上面,船的下面。

    update: function (dt) {
        let waveNode = cc.instantiate(this.mPrefabWave);
        waveNode.parent = this.mSeaNode;
        waveNode.x = this.x;
        waveNode.y = this.y;
        waveNode.setLocalZOrder(10);
    },

其中:this.mPrefabWave就是我們的發(fā)射器預(yù)制件ParticleEmitter。this.mSeaNode是海(地圖)所屬的節(jié)點。

ParticleEmitter所掛的腳本代碼如下:

cc.Class({
    extends: cc.Component,

    properties: {
        mPrefabWave: {
            default: null,
            type: cc.Prefab
        }
    },

    // use this for initialization
    onLoad: function () {
        this.varX = 10;    //粒子X位置可變范圍
        this.varY = 5;     //粒子Y位置可變范圍
        this.avgNum = 4;  //每個發(fā)射器發(fā)射的粒子平均數(shù)

        let cnt = this.avgNum + cc.MyLib.rand(2) - 1;   
         //cc.MyLib.rand(2): 在[0,2]區(qū)間產(chǎn)生一個隨機整數(shù)(0,1或者2);
        for (let i=0;i<cnt;++i) {
            this._createParticleNode();
        }
        this.particleNum = cnt;
    },


    _createParticleNode: function() {
        let Rand = cc.MyLib.rand;
        let particleNode = cc.instantiate(this.mPrefabWave);
        particleNode.parent = this.node;
        //在當(dāng)前位置附近小范圍內(nèi)隨機一個x,y作為粒子的位置。
        let x = Rand(this.varX * 10) / 10 - this.varX / 2;
        let y = Rand(this.varY * 10) / 10 - this.varY / 2;
        particleNode.setPosition(x,y);
        let sc = particleNode.getComponent("ParticleNode");
        let attr = {};
        attr.pSuper = this;
        attr.lifespan = 0.8 * Math.random();  //粒子的生命期
        attr.srcR = 64;
        attr.srcG = 64;
        attr.srcB = 64;
        attr.desR = 128;
        attr.desG = 128;
        attr.desB = 128;
        sc._init(attr);
},

    //當(dāng)每個粒子生命期結(jié)束的時候,將發(fā)射器的粒子計數(shù)減一。
    //當(dāng)計數(shù)減為0的時候,將粒子發(fā)射器自身節(jié)點移除。
    _reduceParticleNum: function() {
        if (--this.particleNum == 0) {
            this.node.removeFromParent();
        }
    }
});

每個粒子節(jié)點是一個叫做ParticleNode的Prefab, 里面就是一個Sprite,一個靜態(tài)水花的圖做spriteFrame,將Blend設(shè)置為Src:SRC_ALPHA以及Dst:ONE,然后掛上一個控制腳本。

particleNode.png

ParticleNode控制腳本的內(nèi)容:

cc.Class({
    extends: cc.Component,

    properties: {
    },

    // use this for initialization
    onLoad: function () {
        this.totalDt = 0;
        this.srcScale = 0;
        this.node.scale = this.srcScale;
        this.desScale = 0.8;
        this.srcOpacity = 255;
    },

    _init: function(attr) {
        this.pSuper = attr.pSuper;
        this.life = attr.lifespan;
        this.srcR = attr.srcR;
        this.srcG = attr.srcG;
        this.srcB = attr.srcG;
        this.desR = attr.desR;
        this.desG = attr.desG;
        this.desB = attr.desB;
        this.node.color = cc.color(this.srcR,this.srcG,this.srcB,this.srcOpacity);
    },

    // called every frame, uncomment this function to activate update callback
    update: function (dt) {
        this.totalDt += dt;
        if (this.totalDt <= this.life/2) {
            let ratio = 2 * this.totalDt / this.life;
            let scale = this.srcScale + (this.desScale-this.srcScale) * ratio;
            this.node.scale = scale;
            let r = this.srcR + (this.desR-this.srcR) * ratio;
            let g = this.srcG + (this.desG-this.srcG) * ratio;
            let b = this.srcB + (this.desB-this.srcB) * ratio;
            this.node.color = cc.color(r,g,b,this.srcOpacity);
        } else if (this.totalDt <= this.life) {
            let ratio = (1 - this.totalDt / this.life) * 2;
            let opacity = this.srcOpacity * ratio;
            this.node.setOpacity(opacity);
        } else {
            this.node.removeFromParent();
            this.pSuper._reduceParticleNum();
        } 
    },
});

update里面,一半生命期粒子的尺寸從0一直增大到目標(biāo)scale,因為圖片略大,這里的目標(biāo)scale定為0.8,同時顏色值從開始的RGB不斷變化到目標(biāo)RGB。另外一半生命期,將粒子的透明度從當(dāng)前透明度減少到0,實現(xiàn)淡出效果。生命期結(jié)束后,將粒子自身節(jié)點移除,并且在它所屬的發(fā)射器上將粒子計數(shù)減少1。

最后的效果還不錯,同時效率也還可以,看一下效果圖:

2.jpg
3.jpg
4.jpg

后話:

雖然自己實現(xiàn)了相對運動的粒子效果,但是如果有現(xiàn)成的粒子系統(tǒng)可以用的話,誰愿意重復(fù)造輪子???希望Creator能盡快完善吧。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 【研究】 一、TP粒子能做什么? 有很多類似群體運動,如魚群、人流、空中飄著葉子等等,群體中每個個體都保持自己獨立...
    DIGITALMAN閱讀 7,295評論 5 50
  • 想必以前QQ空間的點贊效果大家都知道吧,點贊之后按鈕周圍會有一圈爆裂的小圓點;還有微信的紅包雨表情動畫等,以及煙花...
    NotFunGuy閱讀 9,461評論 5 52
  • ――“非暴力溝通”之四 一· 關(guān)于強制力 溝通是要有耐心的,有充分的時間保證...
    簫音聲聲閱讀 210評論 0 1
  • 心理咨詢家表示,太在意別人的看法,是一種不自信的表現(xiàn)。 因為強烈的不自信,才會需要別人的評價來肯定自己。 ----...
    琉璀閱讀 2,522評論 7 8
  • 以前媽媽給我買了好多菱角,菱角就像蘑菇上面的東西,還像個小帽子有兩個小腳黑乎乎的,他是在水中的一個植物。...
    任曦說日記閱讀 673評論 0 0

友情鏈接更多精彩內(nèi)容