‎Cocos2d-x 學習筆記(24) ParticleSystem ParticleSystemQuad


1. ParticleSystem

ParticleData是存儲粒子數據的類,ParticleSystem會關聯一個ParticleData對象。

ParticleSystem直接繼承了Node、TextureProtocol(紋理)、PlayableProtocol(start stop方法)。

ParticleSystem定義了粒子的相關屬性。

粒子從ParticleSystem的位置發射。

屬性

- float _elapsed

運行時間。

粒子相關屬性

- float _startSize, _startSizeVar, _endSize, _endSizeVar

粒子大小及浮動值。

- Color4F _startColor, _startColorVar, _endColor, _endColorVar

粒子顏色值及浮動值。

- float _startSpin, _startSpinVar, _endSpin, _endSpinVar

粒子自身旋轉的角度值及浮動值。

- PositionType _positionType

粒子位置模式,有3種:FREE(粒子在世界坐標系移動)、RELATIVE(粒子相對父節點坐標系移動)、GROUPED(粒子跟隨發射點移動)。

- float _life, _lifeVar

粒子生存時間及浮動值。

發射相關屬性

- float _angle, _angleVar

粒子發射的角度及浮動值。

- Mode _emitterMode

發射器模式。發射有2種模式,用枚舉Mode表示:

Gravity:重力模式,Mode A,屬性:重力加速度(向量表示)、速度和浮動值(粒子的初速度)、徑向加速度和浮動值(與速度方向平行)、切向加速度和浮動值(與速度方向垂直)。

Radius:徑向模式,Mode B,屬性:起始半徑和浮動值(粒子出生時和圓心距離)、結束半徑和浮動值(粒子死亡時和圓心距離)、每秒旋轉的角度和浮動值。

- float _emissionRate

發射器每秒發射的粒子數。

- int _totalParticles

生存的粒子最大數量。

- int _particleCount

當前生存的粒子數。

- float _duration

發射器工作時長,-1為永遠發射。

- Vec2 _sourcePosition, _posVar

發射位置及發射位置的浮動值。

_sourcePosition與bool _sourcePositionCompatible有關,布爾值默認為true表明兼容,位置將被設置到node的位置變量;為false位置將被設置到_sourcePosition變量。

兩個靜態屬性

- static Vector<ParticleSystem*> __allInstances

存儲粒子系統的容器。

 

- static float __totalParticleCountFactor

該屬性默認為1。在update方法中,最大粒子數_totalParticles乘該系數,得到最大粒子數。

1. 創建

粒子對象的創建可以分為這3種方法:

- 通過代碼創建ParticleSystemQuad,並設置屬性

- 通過plist文件創建

- 直接通過代碼使用現成的粒子子類實現特效

plist文件會被轉成ValueMap,從而對plist的各項數據進行解析,相關屬性值賦給ParticleSystem屬性。

2. onEnter() onExit()方法

在執行addChild方法將粒子節點加到父節點時,會調用節點的onEnter方法。

ParticleSystem的onEnter方法中有這兩行:

    this->scheduleUpdateWithPriority(1);
    __allInstances.pushBack(this);

先設置update方法將在每幀執行。再將當前粒子類加入靜態容器__allInstances中。

ParticleSystem的onExit方法會執行unscheduleUpdate,停止每幀執行update(dt),並從靜態容器__allInstances中刪除粒子類。

3. update(dt)方法

該方法被調度器Scheduler每幀觸發,粒子的更新離不開這個重要的方法。

4. 粒子添加與粒子到期后刪除

ParticleSystem成員_particleCount表示當前存在屏幕上的粒子數(當前已生成沒銷毀的粒子數)。

在update(dt)中,每幀會調用粒子添加的方法addParticles(int count)。

添加數量為count的粒子,實際上是把粒子的數據被添加到ParticleSystem成員中_particleData。

新增的各個粒子各項數據是被修改到從對應的_particleData數組成員的“最末尾”的下標位置開始,要添加多少個粒子,就修改多少個指針。“最末尾”的下標指的是根據_particleCount得出。

粒子到期后刪除時,也是在update(dt)方法中刪除,但是沒有真正執行“刪除”操作,而是將_particleData最末尾(數組成員最末尾)的數據復制到當前粒子的位置上,並對_particleCount減1。

我們知道,在update方法中是把_particleData每個數組成員前_particleCount項作為當前存在的粒子的數據並進行更新。所以,“被復制”的數據項位置實際上在之后的update中被“忽略”了,所以該項的數據只會被新增的粒子覆蓋,而前面被刪除的粒子的數據位置被這個“被復制”的數據項覆蓋,保證了數組成員前_particleCount項始終代表着當前存在的粒子的數據。

總結ParticleSystem

ParticleSystem關聯一個ParticleData。

每個粒子當前的屬性值狀態信息等,被保存在ParticleData中。而ParticleSystem中的粒子信息是我們直接設置的,例如浮動值只存儲在ParticleSystem成員變量中。

每一次update時,新建的粒子和當前粒子狀態各項信息通過計算后,都被保存在ParticleData中。

盡管ParticleData是一個類,我們可以把它理解成是一個“容器”。粒子系統ParticleSystem主要是提供對粒子當前信息ParticleData“容器”的管理,例如對“容器”修改、更新、添加等。所以說,粒子系統ParticleSystem是所有粒子的基類,只負責粒子最基礎的創建和存儲功能。

2. ParticleSystemQuad

ParticleSystemQuad直接繼承了ParticleSystem。所有粒子特效類都是ParticleSystemQuad的子類。

該類在父類的基礎上增加了對粒子的繪制功能。

1. 頂點緩存與索引緩存

ParticleSystemQuad有兩個重要變量:頂點緩存和索引緩存。

- V3F_C4B_T2F_Quad *_quads

頂點緩存:包含多個頂點數據的一塊內存,一個四邊形的4個頂點信息作為一個單位進行存儲。每一個V3F_C4B_T2F_Quad結構體存儲了4個頂點的信息(4個V3F_C4B_T2F結構體對象),每個頂點的信息包括三維頂點坐標、顏色和透明度、紋理UV坐標。

- GLushort *_indices

索引緩存:每6個索引對應一個四邊形,OpenGL是通過三角形來繪制四邊形的,所以一個四邊形需要兩個三角形的頂點數據,也就是6個索引對應1個V3F_C4B_T2F_Quad了。

在所有粒子效果類的create方法中,都會調用ParticleSystemQuad的initWithTotalParticles方法進行初始化,該方法會調用allocMemory分配粒子效果類需要的頂點緩存和索引緩存的內存區域。

內存的個數為我們設置的最大粒子數。

對於頂點緩存,每塊內存的大小為V3F_C4B_T2F_Quad結構體的大小。對於索引緩存,每塊內存為索引的6倍,也就是說把一個四邊形需要的所有6個索引作為一個內存區域存儲。大致邏輯是:

    memset(_quads, 0, _totalParticles * sizeof(V3F_C4B_T2F_Quad));
    memset(_indices, 0, _totalParticles * 6 * sizeof(GLushort));

索引緩存是對頂點緩存的映射,這樣可以對於重復的頂點使用一個內存進行存儲。

在剛才說的initWithTotalParticles方法進行兩個緩存內存的分配之后,對索引緩存設置索引值,設置索引指向的頂點位置。具體步驟如下:

    for(int i = 0; i < _totalParticles; ++i)
    {
        const unsigned int i6 = i*6;
        const unsigned int i4 = i*4;
        _indices[i6+0] = (GLushort) i4+0;
        _indices[i6+1] = (GLushort) i4+1;
        _indices[i6+2] = (GLushort) i4+2;

        _indices[i6+5] = (GLushort) i4+1;
        _indices[i6+4] = (GLushort) i4+2;
        _indices[i6+3] = (GLushort) i4+3;
    }

另外,在setTotalParticles(int tp)方法中,根據參數最大粒子數,對頂點緩存_quads和索引緩存_indices大小更新並初始化,使用的也是類似上面的思路。

2. initTexCoordsWithRect(rect)

initTexCoordsWithRect(rect)方法,通過紋理更新每個粒子在的UV坐標。

該方法2個使用位置:

設置粒子的紋理時,使用setTexture方法,需要重新設置新紋理的UV坐標。

重新設置粒子最大數時,使用setTotalParticles方法,因為粒子總數發生改變,需要重新初始化頂點緩存和索引緩存,需要重新設置頂點緩存內的UV坐標。

該方法要求傳入的參數rect是根據紋理坐標系(Texture coordinates,OpenGL坐標系)表示的,而不能是像素坐標系(Pixel coordinates)。

紋理坐標系(OpenGL坐標系)左下角為原點(0,0);像素坐標系是圖片數據原始的坐標系,左上角為原點(0,0)。

接下來通過計算,得出矩形四個頂點的UV坐標。此時的UV坐標需要存入頂點緩存中,而頂點緩存是直接面向GPU的,所以不采用紋理OpenGL坐標系,而是像素坐標系。使用像素坐標系的結果是頂部的坐標值為0,與底部的坐標值交換了。

該方法最終向頂點緩存中存入一個矩形的4個頂點像素坐標系下的UV坐標:

    for(unsigned int i=start; i<end; i++) 
    {
        // bottom-left vertex:
        quads[i].bl.texCoords.u = left;
        quads[i].bl.texCoords.v = bottom;
        // bottom-right vertex:
        quads[i].br.texCoords.u = right;
        quads[i].br.texCoords.v = bottom;
        // top-left vertex:
        quads[i].tl.texCoords.u = left;
        quads[i].tl.texCoords.v = top;
        // top-right vertex:
        quads[i].tr.texCoords.u = right;
        quads[i].tr.texCoords.v = top;
    }

3. updateParticleQuads()

該方法在ParticleSystem的每幀update最后執行。

在ParticleSystem的中,該方法為空,調用的是ParticleSystemQuad的該方法。

update方法在updateParticleQuads之前是把本幀的粒子數據修改到ParticleData中,之后執行該方法,用來把ParticleData中生存的粒子數據寫到頂點緩存中,是對位置和顏色分別在頂點緩存進行更新。

把頂點坐標寫入頂點緩存前,根據3種粒子位置類型計算當前粒子位置,之后執行updatePosWithParticle方法寫入頂點緩存。該方法通過位置坐標、旋轉角度、矩形大小,計算出矩形4個頂點坐標,存入頂點緩存中。

存入頂點緩存的坐標是像素坐標系的坐標,所以updatePosWithParticle方法會將旋轉角度取反。

4. 其它

ParticleSystemQuad重寫了Node的draw方法,使用了頂點緩存和索引緩存。

initWithTotalParticles方法調用setupVBO或setupVBOandVAO方法加載VBO VAO。


本文原創地址:https://www.cnblogs.com/deepcho/ ,如果您在非本網址看到此文章,說明網站是爬蟲采集抄襲而成。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM