---
# System prepended metadata

title: Particle System Egret v.s Cocos Creator
tags: [cocos creator, Egret, particle system, plist]

---

# Particle System Egret v.s Cocos Creator

## 重點先說
Creator 3D 目前只有 unity-like 的獨特粒子特效, 和 2d 泛用的粒子特效規格完全不同.
以下以未來 cc3d & 2d 合併的前提下, 研究 egret 與 cc2d 的粒子特效規格轉換的可行性.

## cocos 官方推薦編輯器之一
- [Particle2dx For EffectHub](http://www.effecthub.com/particle2dx)
    - design particle for Cocos2dx CoronaSDK
    - plist 內可含 Base64 的圖片資訊
    - Particle2dx 無法表演旋轉的屬性

## 差異
- 副檔名: egret `.json`, cc `.plist`.
- 坐標系: egret `左手`, cc `右手`. 因此在2D世界中, Y軸要反轉.  
    影響屬性為:
    - gravityy
- 顏色: egret `0-255`, cc `0.0-1.0`.  
    - 影響屬性為:
        - finishColorBlue
        - finishColorVarianceBlue
        - finishColorGreen
        - finishColorRed
        - finishColorVarianceRed
        - finishColorVarianceGreen
        - startColorBlue
        - startColorVarianceBlue
        - startColorGreen
        - startColorVarianceGreen
        - startColorRed
        - startColorVarianceRed
    - 但 alpha 兩邊都是 `0.0-1.0`.
- 時長: egret `毫秒(ms)`, cc `秒(s)`.  
    - 影響屬性為:
        - duration
        - particleLifespan
        - particleLifespanVariance
- 混和類型: egret `係數類型字串`, cc `係數(0.0-1.0)`
    - `Egret Feather` 可吃該格式, 但無法從編輯介面調整.
    - 影響屬性為:
        - blendFuncDestination
        - blendFuncSource
    - egret 預設值為 `src: one, dst: oneMinusSourceAlpha`  
        對應 cc 數值為 `src: 1, dst: 771`
    - particle2dx 會直接使用 cc2d 的功能設定數值, [Cocos2d-html5-v2.2.3.min.js](https://github.com/mash76/particle2dx/blob/master/Cocos2d-html5-v2.2.3.min.js) 相關的參數:
        ```javascript=
        cc.BLEND_SRC = cc.OPTIMIZE_BLEND_FUNC_FOR_PREMULTIPLIED_ALPHA ? 1 : 770;
        cc.BLEND_DST = 771;

        gl.ONE = 1;
        gl.ZERO = 0;
        gl.SRC_ALPHA = 770;
        gl.ONE_MINUS_SRC_ALPHA = 771;
        gl.ONE_MINUS_DST_COLOR = 775;
        ```
- 大多屬性都是一對一的, 除了:
    - `sourcePositionx` & `sourcePositiony` 來自 `emitter {x,y}`
    - `sourcePositionVariancex` & `sourcePositionVariancey` 來自 `emitterVariance {x,y}`
    - `gravityx` & `gravityy` 來自 `gravity {x,y}`
    - `minRadiusVariance` 理論上 cc 也吃, 但[編輯器模板](https://github.com/mash76/particle2dx/blob/master/particle/template.plist)沒有此屬性.
    - `plist` 可以將圖片直接以 Base64 的形式儲存在 `textureImageData`, egret 沒有相應的欄位.

## 轉換器本體

### e2c v2.0
- 仿造 particle2dx 替換 template 特殊字串的做法. (原本為逐一添加)
- 以 cc 所需參數為主導的方式 mapping.(前一版以 egret 屬性為主)
- 搭配 `eval` & json data 簡化複雜度

```javascript=
// 直接複製到 chome console 即可執行
// v2.0 主要參考 mash76/particle2dx 採用模板替換關鍵字的作法

// template base on https://github.com/mash76/particle2dx/blob/master/particle/template.plist, 增加 minRadiusVariance & rotationEndVariance.
// <?xml version="1.0" encoding="UTF-8"?>
// <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
// <plist version="1.0">
// <dict>
// 	<key>angle</key>
// 	<real>__angle__</real>
// 	<key>angleVariance</key>
// 	<real>__angleVar__</real>
// 	<key>blendFuncDestination</key>
// 	<integer>__blendFuncDestination__</integer>
// 	<key>blendFuncSource</key>
// 	<integer>__blendFuncSource__</integer>
// 	<key>duration</key>
// 	<real>__duration__</real>
// 	<key>emitterType</key>
// 	<real>__emitterMode__</real>
// 	<key>finishColorAlpha</key>
// 	<real>__end_a__</real>
// 	<key>finishColorBlue</key>
// 	<real>__end_b__</real>
// 	<key>finishColorGreen</key>
// 	<real>__end_g__</real>
// 	<key>finishColorRed</key>
// 	<real>__end_r__</real>
// 	<key>finishColorVarianceAlpha</key>
// 	<real>__end_a_var__</real>
// 	<key>finishColorVarianceBlue</key>
// 	<real>__end_b_var__</real>
// 	<key>finishColorVarianceGreen</key>
// 	<real>__end_g_var__</real>
// 	<key>finishColorVarianceRed</key>
// 	<real>__end_r_var__</real>
// 	<key>finishParticleSize</key>
// 	<real>__endSize__</real>
// 	<key>finishParticleSizeVariance</key>
// 	<real>__endSizeVar__</real>
// 	<key>gravityx</key>
// 	<real>__grav_x__</real>
// 	<key>gravityy</key>
// 	<real>__grav_y__</real>
// 	<key>maxParticles</key>
// 	<real>__maxParticles__</real>
// 	<key>maxRadius</key>
// 	<real>__maxRadius__</real>
// 	<key>maxRadiusVariance</key>
// 	<real>__maxRadiusVar__</real>
// 	<key>minRadius</key>
// 	<real>__minRadius__</real>
// 	<key>minRadiusVariance</key>
// 	<real>__minRadiusVar__</real>
// 	<key>particleLifespan</key>
// 	<real>__life__</real>
// 	<key>particleLifespanVariance</key>
// 	<real>__lifeVar__</real>
// 	<key>radialAccelVariance</key>
// 	<real>__rad_accel_var__</real>
// 	<key>radialAcceleration</key>
// 	<real>__rad_accel__</real>
// 	<key>rotatePerSecond</key>
// 	<real>__rotatePerSecond__</real>
// 	<key>rotatePerSecondVariance</key>
// 	<real>__rotatePerSecondVar__</real>
// 	<key>rotationEnd</key>
// 	<real>__endSpin__</real>
// 	<key>rotationEndVariance</key>
// 	<real>__endSpinVar__</real>
// 	<key>rotationStart</key>
// 	<real>__startSpin__</real>
// 	<key>rotationStartVariance</key>
// 	<real>__startSpinVar__</real>
// 	<key>sourcePositionVariancex</key>
// 	<real>__posx_var__</real>
// 	<key>sourcePositionVariancey</key>
// 	<real>__posy_var__</real>
// 	<key>sourcePositionx</key>
// 	<real>__posx__</real>
// 	<key>sourcePositiony</key>
// 	<real>__posy__</real>
// 	<key>speed</key>
// 	<real>__speed__</real>
// 	<key>speedVariance</key>
// 	<real>__speedVar__</real>
// 	<key>startColorAlpha</key>
// 	<real>__start_a__</real>
// 	<key>startColorBlue</key>
// 	<real>__start_b__</real>
// 	<key>startColorGreen</key>
// 	<real>__start_g__</real>
// 	<key>startColorRed</key>
// 	<real>__start_r__</real>
// 	<key>startColorVarianceAlpha</key>
// 	<real>__start_a_var__</real>
// 	<key>startColorVarianceBlue</key>
// 	<real>__start_b_var__</real>
// 	<key>startColorVarianceGreen</key>
// 	<real>__start_g_var__</real>
// 	<key>startColorVarianceRed</key>
// 	<real>__start_r_var__</real>
// 	<key>startParticleSize</key>
// 	<real>__startSize__</real>
// 	<key>startParticleSizeVariance</key>
// 	<real>__startSizeVar__</real>
// 	<key>tangentialAccelVariance</key>
// 	<real>__tan_accel_var__</real>
// 	<key>tangentialAcceleration</key>
// 	<real>__tan_accel__</real>
// 	<key>textureFileName</key>
// 	<string>__textureFileName__.png</string>
// 	<key>textureImageData</key>
// 	<string>__png_base64__</string>
// </dict>
// </plist>

var e2c = {
    mappingData: {
        "angle": {
            "path": "emitAngle",
            "replacement": "__angle__"
        },
        "angleVariance": {
            "path": "emitAngleVariance",
            "replacement": "__angleVar__"
        },
        "blendFuncDestination": {
            "path": "blendFactorDestination",
            "replacement": "__blendFuncDestination__"
        },
        "blendFuncSource": {
            "path": "blendFactorSource",
            "replacement": "__blendFuncSource__"
        },
        "duration": {
            "path": "duration",
            "replacement": "__duration__"
        },
        "emitterType": {
            "path": "emitterType",
            "replacement": "__emitterMode__"
        },
        "finishColorAlpha": {
            "path": "endAlpha",
            "replacement": "__end_a__"
        },
        "finishColorBlue": {
            "path": "endBlue",
            "replacement": "__end_b__"
        },
        "finishColorGreen": {
            "path": "endGreen",
            "replacement": "__end_g__"
        },
        "finishColorRed": {
            "path": "endRed",
            "replacement": "__end_r__"
        },
        "finishColorVarianceAlpha": {
            "path": "endAlphaVariance",
            "replacement": "__end_a_var__"
        },
        "finishColorVarianceBlue": {
            "path": "endBlueVariance",
            "replacement": "__end_b_var__"
        },
        "finishColorVarianceGreen": {
            "path": "engGreenVariance",
            "replacement": "__end_g_var__"
        },
        "finishColorVarianceRed": {
            "path": "endRedVariance",
            "replacement": "__end_r_var__"
        },
        "finishParticleSize": {
            "path": "endSize",
            "replacement": "__endSize__"
        },
        "finishParticleSizeVariance": {
            "path": "endSizeVariance",
            "replacement": "__endSizeVar__"
        },
        "gravityx": {
            "path": "gravity.x",
            "replacement": "__grav_x__"
        },
        "gravityy": {
            "path": "gravity.y",
            "replacement": "__grav_y__"
        },
        "maxParticles": {
            "path": "maxParticles",
            "replacement": "__maxParticles__"
        },
        "maxRadius": {
            "path": "maxRadius",
            "replacement": "__maxRadius__"
        },
        "maxRadiusVariance": {
            "path": "maxRadiusVariance",
            "replacement": "__maxRadiusVar__"
        },
        "minRadius": {
            "path": "minRadius",
            "replacement": "__minRadius__"
        },
        "minRadiusVariance": {
            "path": "minRadiusVariance",
            "replacement": "__minRadiusVar__"
        },
        "particleLifespan": {
            "path": "lifespan",
            "replacement": "__life__"
        },
        "particleLifespanVariance": {
            "path": "lifespanVariance",
            "replacement": "__lifeVar__"
        },
        "radialAccelVariance": {
            "path": "radialAccelerationVariance",
            "replacement": "__rad_accel_var__"
        },
        "radialAcceleration": {
            "path": "radialAcceleration",
            "replacement": "__rad_accel__"
        },
        "rotatePerSecond": {
            "path": "rotatePerSecond",
            "replacement": "__rotatePerSecond__"
        },
        "rotatePerSecondVariance": {
            "path": "rotatePerSecondVariance",
            "replacement": "__rotatePerSecondVar__"
        },
        "rotationEnd": {
            "path": "endRotation",
            "replacement": "__endSpin__"
        },
        "rotationEndVariance": {
            "path": "endRotationVariance",
            "replacement": "__endSpinVar__"
        },
        "rotationStart": {
            "path": "startRotation",
            "replacement": "__startSpin__"
        },
        "rotationStartVariance": {
            "path": "startRotationVariance",
            "replacement": "__startSpinVar__"
        },
        "sourcePositionVariancex": {
            "path": "emitterVariance.x",
            "replacement": "__posx_var__"
        },
        "sourcePositionVariancey": {
            "path": "emitterVariance.y",
            "replacement": "__posy_var__"
        },
        "sourcePositionx": {
            "path": "emitter.x",
            "replacement": "__posx__"
        },
        "sourcePositiony": {
            "path": "emitter.y",
            "replacement": "__posy__"
        },
        "speed": {
            "path": "speed",
            "replacement": "__speed__"
        },
        "speedVariance": {
            "path": "speedVariance",
            "replacement": "__speedVar__"
        },
        "startColorAlpha": {
            "path": "startAlpha",
            "replacement": "__start_a__"
        },
        "startColorBlue": {
            "path": "startBlue",
            "replacement": "__start_b__"
        },
        "startColorGreen": {
            "path": "startGreen",
            "replacement": "__start_g__"
        },
        "startColorRed": {
            "path": "startRed",
            "replacement": "__start_r__"
        },
        "startColorVarianceAlpha": {
            "path": "startAlphaVariance",
            "replacement": "__start_a_var__"
        },
        "startColorVarianceBlue": {
            "path": "startBlueVariance",
            "replacement": "__start_b_var__"
        },
        "startColorVarianceGreen": {
            "path": "startGreenVariance",
            "replacement": "__start_g_var__"
        },
        "startColorVarianceRed": {
            "path": "startRedVariance",
            "replacement": "__start_r_var__"
        },
        "startParticleSize": {
            "path": "startSize",
            "replacement": "__startSize__"
        },
        "startParticleSizeVariance": {
            "path": "startSizeVariance",
            "replacement": "__startSizeVar__"
        },
        "tangentialAccelVariance": {
            "path": "tangentialAccelerationVariance",
            "replacement": "__tan_accel_var__"
        },
        "tangentialAcceleration": {
            "path": "tangentialAcceleration",
            "replacement": "__tan_accel__"
        },
        "textureFileName": {
            "path": "texture",
            "replacement": "__textureFileName__"
        }
    },
    getValue(mappedKey, value) {
        switch (mappedKey) {
            case "duration":
                if (value != -1) value /= 1000;
                break;
            case "particleLifespan":
            case "particleLifespanVariance":
                value /= 1000;
                break;
            case "finishColorBlue":
            case "finishColorVarianceBlue":
            case "finishColorGreen":
            case "finishColorRed":
            case "finishColorVarianceRed":
            case "finishColorVarianceGreen":
            case "startColorBlue":
            case "startColorVarianceBlue":
            case "startColorGreen":
            case "startColorVarianceGreen":
            case "startColorRed":
            case "startColorVarianceRed": // 之後要轉換可在這裡 switch
                value /= 255;
                break;
            case "blendFuncDestination": // 之後要轉換可在這裡 switch
                value = 711;
                break;
            case "blendFuncSource":
                value = 1;
                break;
        }

        return value;
    },
    phase(src) {
        let result =
            '<?xml version="1.0" encoding="UTF-8"?>\r\n<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\r\n<plist version="1.0">\r\n<dict>\r\n\t<key>angle</key>\r\n\t<real>__angle__</real>\r\n\t<key>angleVariance</key>\r\n\t<real>__angleVar__</real>\r\n\t<key>blendFuncDestination</key>\r\n\t<integer>__blendFuncDestination__</integer>\r\n\t<key>blendFuncSource</key>\r\n\t<integer>__blendFuncSource__</integer>\r\n\t<key>duration</key>\r\n\t<real>__duration__</real>\r\n\t<key>emitterType</key>\r\n\t<real>__emitterMode__</real>\r\n\t<key>finishColorAlpha</key>\r\n\t<real>__end_a__</real>\r\n\t<key>finishColorBlue</key>\r\n\t<real>__end_b__</real>\r\n\t<key>finishColorGreen</key>\r\n\t<real>__end_g__</real>\r\n\t<key>finishColorRed</key>\r\n\t<real>__end_r__</real>\r\n\t<key>finishColorVarianceAlpha</key>\r\n\t<real>__end_a_var__</real>\r\n\t<key>finishColorVarianceBlue</key>\r\n\t<real>__end_b_var__</real>\r\n\t<key>finishColorVarianceGreen</key>\r\n\t<real>__end_g_var__</real>\r\n\t<key>finishColorVarianceRed</key>\r\n\t<real>__end_r_var__</real>\r\n\t<key>finishParticleSize</key>\r\n\t<real>__endSize__</real>\r\n\t<key>finishParticleSizeVariance</key>\r\n\t<real>__endSizeVar__</real>\r\n\t<key>gravityx</key>\r\n\t<real>__grav_x__</real>\r\n\t<key>gravityy</key>\r\n\t<real>__grav_y__</real>\r\n\t<key>maxParticles</key>\r\n\t<real>__maxParticles__</real>\r\n\t<key>maxRadius</key>\r\n\t<real>__maxRadius__</real>\r\n\t<key>maxRadiusVariance</key>\r\n\t<real>__maxRadiusVar__</real>\r\n\t<key>minRadius</key>\r\n\t<real>__minRadius__</real>\r\n\t<key>minRadiusVariance</key>\r\n\t<real>__minRadiusVar__</real>\r\n\t<key>particleLifespan</key>\r\n\t<real>__life__</real>\r\n\t<key>particleLifespanVariance</key>\r\n\t<real>__lifeVar__</real>\r\n\t<key>radialAccelVariance</key>\r\n\t<real>__rad_accel_var__</real>\r\n\t<key>radialAcceleration</key>\r\n\t<real>__rad_accel__</real>\r\n\t<key>rotatePerSecond</key>\r\n\t<real>__rotatePerSecond__</real>\r\n\t<key>rotatePerSecondVariance</key>\r\n\t<real>__rotatePerSecondVar__</real>\r\n\t<key>rotationEnd</key>\r\n\t<real>__endSpin__</real>\r\n\t<key>rotationEndVariance</key>\r\n\t<real>__endSpinVar__</real>\r\n\t<key>rotationStart</key>\r\n\t<real>__startSpin__</real>\r\n\t<key>rotationStartVariance</key>\r\n\t<real>__startSpinVar__</real>\r\n\t<key>sourcePositionVariancex</key>\r\n\t<real>__posx_var__</real>\r\n\t<key>sourcePositionVariancey</key>\r\n\t<real>__posy_var__</real>\r\n\t<key>sourcePositionx</key>\r\n\t<real>__posx__</real>\r\n\t<key>sourcePositiony</key>\r\n\t<real>__posy__</real>\r\n\t<key>speed</key>\r\n\t<real>__speed__</real>\r\n\t<key>speedVariance</key>\r\n\t<real>__speedVar__</real>\r\n\t<key>startColorAlpha</key>\r\n\t<real>__start_a__</real>\r\n\t<key>startColorBlue</key>\r\n\t<real>__start_b__</real>\r\n\t<key>startColorGreen</key>\r\n\t<real>__start_g__</real>\r\n\t<key>startColorRed</key>\r\n\t<real>__start_r__</real>\r\n\t<key>startColorVarianceAlpha</key>\r\n\t<real>__start_a_var__</real>\r\n\t<key>startColorVarianceBlue</key>\r\n\t<real>__start_b_var__</real>\r\n\t<key>startColorVarianceGreen</key>\r\n\t<real>__start_g_var__</real>\r\n\t<key>startColorVarianceRed</key>\r\n\t<real>__start_r_var__</real>\r\n\t<key>startParticleSize</key>\r\n\t<real>__startSize__</real>\r\n\t<key>startParticleSizeVariance</key>\r\n\t<real>__startSizeVar__</real>\r\n\t<key>tangentialAccelVariance</key>\r\n\t<real>__tan_accel_var__</real>\r\n\t<key>tangentialAcceleration</key>\r\n\t<real>__tan_accel__</real>\r\n\t<key>textureFileName</key>\r\n\t<string>__textureFileName__.png</string>\r\n\t<key>textureImageData</key>\r\n\t<string>__png_base64__</string>\r\n</dict>\r\n</plist>';

        for (const key in this.mappingData) {
            const data = this.mappingData[key];
            const value = this.getValue(key, eval(`src.${data.path}`));

            if (value != null) {
                console.log(`${data.replacement}: ${value}`);
                result = result.replace(data.replacement, value);
            }
        }

        result = result.replace("__png_base64__", ""); // 如果想要 image in plist 可以塞進這欄位

        console.log(result);
    }
};

```

---

### 使用範例
```javascript=
e2c.phase(
    {
        "texture": "ttt.png",
        "gravity": { "x": 0, "y": 500 },
        "radialAcceleration": 38.85,
        "maxParticles": 30,
        "radialAccelerationVariance": 0,
        "emitterType": 0,
        "engGreenVariance": 0,
        "emitterVariance": { "x": 100, "y": 50 },
        "endAlpha": 1,
        "tangentialAccelerationVariance": 0,
        "startAlpha": 0.8901960784313725,
        "duration": -1,
        "startBlueVariance": 0,
        "maxRadiusVariance": 30,
        "lifespan": 2230,
        "blendFactorDestination": "oneMinusSourceAlpha",
        "minRadius": 20,
        "lifespanVariance": 700,
        "minRadiusVariance": 10,
        "startSize": 30,
        "blendFactorSource": "one",
        "rotatePerSecond": 30,
        "startSizeVariance": 10,
        "rotatePerSecondVariance": 10,
        "startBlue": 255,
        "startRedVariance": 0,
        "emitter": { "x": -12, "y": 13 },
        "endSizeVariance": 5,
        "tangentialAcceleration": 0,
        "emitAngle": 260,
        "endSize": 20,
        "emitAngleVariance": 360,
        "startAlphaVariance": 0,
        "startRotation": 0,
        "startGreenVariance": 0,
        "startRotationVariance": 45,
        "endRedVariance": 0,
        "endAlphaVariance": 0,
        "endRotation": 263.58,
        "speed": 150,
        "endRotationVariance": 292.07,
        "maxRadius": 100,
        "endRed": 255,
        "startRed": 255,
        "endBlue": 255,
        "speedVariance": 0,
        "endBlueVariance": 0,
        "startGreen": 255,
        "endGreen": 255,
    }
)
```



###### tags: `Egret` `cocos creator` `particle system` `plist`