zoukankan      html  css  js  c++  java
  • Qt5官方demo分析集11——Qt Quick Particles Examples

    在这个系列中的所有文章都可以在这里查看http://blog.csdn.net/cloud_castle/article/category/2123873

    接上文Qt5官方demo解析集10——Qt Quick Particles Examples - Emitters


    Affectors是Qt官方粒子系统demo中的第二个例程,它是在Emitters上的进一步扩展。我们将看到。通过使用Affectors,我们可以创造更加灵活的粒子显示以及交互行为。

    首先还是看下介绍:This is a collection of small QML examples relating to using Affectors in the particle system. Each example is a small QML file emphasizing a particular type or feature.

    非常简短,告诉我们这个demo依旧是由多个使用Affectors的小样例构成。执行后是相同的选择框:


    一共同拥有10个样例,我们还是从第一个開始:


    (1)Age

    来看看<“杀掉”进入Affector的粒子>是个什么效果:进入图中矩形框的雪花都变小并逐渐消失了。



    来看看这个小样例是怎么写的吧~ age.qml:

    import QtQuick 2.0
    import QtQuick.Particles 2.0
    
    Rectangle {
        id: root
         360
        height: 600
        color: "white"
    
        ParticleSystem { id: particles }
    
        ImageParticle {            // 这里向我们展示第二种图像粒子的设置
            system: particles
            sprites: Sprite {      // sprites属性用来定义一组帧图片来作为粒子。这样粒子能够像GIF一样拥有自己的动画
                name: "snow"
                source: "../../images/snowflake.png"  // 这是一张具有51帧的雪花图形
                frameCount: 51
                frameDuration: 40                     // 帧动画的基本设置
                frameDurationVariation: 8
            }
        }
    
        Emitter {
            system: particles
            emitRate: 20
            lifeSpan: 8000
            velocity: PointDirection { y:80; yVariation: 40; }  // 加速度下落
            acceleration: PointDirection { y: 4 }
            size: 36
            endSize: 12
            sizeVariation: 8
             parent.width
            height: 100
        }
    
        MouseArea {
            id: ma
            anchors.fill: parent
            hoverEnabled: true
        }
    
        Rectangle {                   // 这里使用Rectangle作为Age的父类,当然Age能够定义自己的坐标以及区域。可是增加Rectangle可视化效果更好
            color: "#803333AA"                        // 半透明的湛蓝色
            border.color: "black"
            x: ma.mouseX - 36                         // 这里用到属性绑定使得该矩形能够尾随鼠标的移动,并以鼠标为中心点
            y: ma.mouseY - 36
             72
            height: 72
            //! [0]
            Age {                         // Age继承自Affector,事实上在上一篇Emitters中我们就接触了一个Affector:Turbulence。它能够提供一个气流的效果,而这里的Age则同意我们改变粒子的生命周期。
                anchors.fill: parent    
                system: particles
                once: true                // 每一个粒子仅仅影响一次
                lifeLeft: 1200            // 粒子剩下的时间
                advancePosition: false    // 退化是否影响位置、速度、和加速度
            }
            //! [0]
        }
    }

    雪花图太长。截一部分好了:



    (2)Attractor

    这个小样例使用Affector中的Attractor(吸引者)向我们展示了怎样使用粒子系统模拟一个黑洞。



    能够看到图中心有一个“黑洞”,靠近黑洞的粒子会被改变执行轨迹,太近的粒子会被吸进去。假设须要我们自己来写这样的速度改变的代码可能会相当繁琐。好在QtQuick给我们提供了Attractor这个Affector,来看看它怎么使用的~attractor.qml

    import QtQuick 2.0
    import QtQuick.Particles 2.0
    Rectangle {
        id: root
         360
        height: 540
        color: "black"
        Image {
            source: "qrc:/images/finalfrontier.png"
            anchors.centerIn:parent
        }
        ParticleSystem {
            id: particles
            anchors.fill: parent
            Emitter {                    // 星星发射器
                group: "stars"
                emitRate: 40
                lifeSpan: 4000
                enabled: true
                size: 30
                sizeVariation: 10
                velocity: PointDirection { x: 220; xVariation: 40 }
                height: parent.height  // height定义了发射发射区域的高度,否则粒子从(0,0)发出
            }
            Emitter {                    // 陨石发射器
                group: "roids"
                emitRate: 10
                lifeSpan: 4000
                enabled: true
                size: 30
                sizeVariation: 10
                velocity: PointDirection { x: 220; xVariation: 40 }
                height: parent.height
            }
            ImageParticle {              // 星星
                id: stars
                groups: ["stars"]
                source: "qrc:///particleresources/star.png"
                color: "white"
                colorVariation: 0.5
                alpha: 0
            }
            ImageParticle {              // 陨石
                id: roids
                groups: ["roids"]
                sprites: Sprite {      // 这里再次使用了帧动画,由于未定义frameDurationVariation。全部陨石的旋转速度都是同样的
                    id: spinState
                    name: "spinning"
                    source: "qrc:/images/meteor.png"
                    frameCount: 35
                    frameDuration: 60
                }
            }
            ImageParticle {             // 飞船子弹
                id: shot
                groups: ["shot"]
                source: "qrc:///particleresources/star.png"
                color: "#0FF06600"
                colorVariation: 0.3
            }
            ImageParticle {             // 尾气
                id: engine
                groups: ["engine"]
                source: "qrc:///particleresources/fuzzydot.png"
                color: "orange"
                SequentialAnimation on color {        // 属性动画
                    loops: Animation.Infinite
                    ColorAnimation {
                        from: "red"
                        to: "cyan"
                        duration: 1000
                    }
                    ColorAnimation {
                        from: "cyan"
                        to: "red"
                        duration: 1000
                    }
                }
                colorVariation: 0.2
            }
            //! [0]
            Attractor {                   // Affector家族中的一员,能够形成吸引其它粒子的效果
                id: gs; pointX: root.width/2; pointY: root.height/2; strength: 4000000;   // pointX,pointY是其作为目标点,同其它Affector一样。设置其x,y,height,weidth改变的是其影响区域
                affectedParameter: Attractor.Acceleration           // 设置为影响加速度
                proportionalToDistance: Attractor.InverseQuadratic       // 影响效果与距离的比例关系
            }
            //! [0]
            Age {                        // 在Attractor周围再安装一个Age。由于这里没有设置lifeLeft。粒子进入该区域变消失了
                x: gs.pointX - 8;        // Age的影响区域
                y: gs.pointY - 8;
                 16
                height: 16
            }
            Rectangle {                  // 用矩形画圆的方法
                color: "black"
                 8
                height: 8
                radius: 4
                x: gs.pointX - 4
                y: gs.pointY - 4
            }
            Image {                        // 飞行器
                source:"qrc:/images/rocket2.png"
                id: ship
                 45
                height: 22
                //Automatic movement
                SequentialAnimation on x {             // 属性动画,这里使用了弹线轨迹
                    loops: -1
                    NumberAnimation{to: root.width-45; easing.type: Easing.InOutQuad; duration: 2000} 
                    NumberAnimation{to: 0; easing.type: Easing.OutInQuad; duration: 6000}
                }
                SequentialAnimation on y {
                    loops: -1
                    NumberAnimation{to: root.height-22; easing.type: Easing.OutInQuad; duration: 6000}
                    NumberAnimation{to: 0; easing.type: Easing.InOutQuad; duration: 2000}
                }
            }
            Emitter {                           // 尾气粒子
                group: "engine"
                emitRate: 200
                lifeSpan: 1000
                size: 10
                endSize: 4
                sizeVariation: 4
                velocity: PointDirection { x: -128; xVariation: 32 }
                height: ship.height
                y: ship.y
                x: ship.x
                 20
            }
            Emitter {                         // 子弹粒子
                group: "shot"
                emitRate: 32
                lifeSpan: 1000
                enabled: true
                size: 40
                velocity: PointDirection { x: 256; }
                x: ship.x + ship.width
                y: ship.y + ship.height/2
            }
        }
    }


    
    

    (3)Custom Affector

    在这个样例中我们将了解到怎样实现一个自己定义的Affector,以及通过这个Affector实现落叶飘落的效果。

    当Affector的子类都不能满足我们的需求的时候,这样的方式就显得尤为重要了。

    直接上代码。因为我会调试这些代码因此其图片的路径被我改成了资源路径,希望没有影响到大家。customaffector.qml:

    import QtQuick 2.0
    import QtQuick.Particles 2.0
    Item {                         // 假设这个文件作为一个组件,Image作为根项目将使使用这个组件的人能够对其随意改动
         360
        height: 600
        Image {                           // 因此不推荐将Image作为根文件夹,而是以Item作为替代,而嵌套Image
            source: "qrc:/images/backgroundLeaves.jpg"
            anchors.fill: parent
        }
        ParticleSystem {
            anchors.fill: parent
            Emitter {
                 parent.width       // 粒子出现的点为(0,0)到(360,0)
                emitRate: 4
                lifeSpan: 14000
                size: 80
                velocity: PointDirection { y: 60 } // 初始速度
            }
            Wander {                      // 一个系统自带的Affector:Wander(漫步者),它能够用来提供随机的粒子轨迹,这样形成了左右晃动的叶子
                anchors.fill: parent
                anchors.bottomMargin: 100  // 与设置Affector的height相似,确定Wander的影响区域
                xVariance: 60              // x方向上的变化率
                pace: 60                   // 最大步长
            }
            //! [0]
            Affector {                     // 主要的Affector类不会改变粒子不论什么属性,但我们能够在合适的时候发出信号来做出对应的处理
                property real coefficient: 0.1   // 自己定义属性“同步系数”和“速度”
                property real velocity: 1.5
                 parent.width
                height: parent.height - 100      // 底部100像素不再产生影响
                onAffectParticles: {      // 仅仅要有粒子被该Affector影响,这个handler就被触发。

    通过它我们能够定义自己的Affector行为。相似onEmitterParticles,因为使用了javaScript数组以及计算。我们相同不推荐在包括大量粒子的系统中使用它。 //Linear movement // 这一段是在源代码中被凝视的,它提供了线性摇动的计算 // if (particle.r == 0) { // particle.r = Math.random() > 0.5 ? -1 : 1; // } else if (particle.r == 1) { // particle.rotation += velocity * dt; // 不知道这个dt是什么,仅仅知道是一个比較小的小数... // if (particle.rotation >= maxAngle) // particle.r = -1; // } else if (particle.r == -1) { // particle.rotation -= velocity * dt; // if (particle.rotation <= -1 * maxAngle) // particle.r = 1; // } //Wobbly movement for (var i=0; i<particles.length; i++) { // 这是一个摇摆算法,相对上面的代码而言更加精妙 var particle = particles[i]; if (particle.r == 0.0) { // 在QML中我们能够将參数定义与赋值放在一起 particle.r = Math.random() + 0.01; // 将 0.01 定义为particle.r的最小值 } particle.rotation += velocity * particle.r * dt; // 随机的particle.r保证每片叶子的旋转角度都是随机的 particle.r -= particle.rotation * coefficient; // 然后这里通过“同步系数”适当改变particle.r。系数越大。叶片晃动越剧烈。

    依据QML属性绑定的原则,当particle.r被改变,particle.rotation随之改变。

    正向的旋转角度使particle.r变小。导致particle.rotation变小。叶片方向旋转,反之亦然,得到晃动效果 if (particle.r == 0.0) // 假设为0给其一个改变量 particle.r -= particle.rotation * 0.000001; particle.update = 1; } } } //! [0] //! [1] Affector { // 定义“地面”的摩擦减速效果 x: -60 parent.width + 120 height: 100 anchors.bottom: parent.bottom onAffectParticles: { for (var i=0; i<particles.length; i++) { var particle = particles[i]; var pseudoRand = (Math.floor(particle.t*1327) % 10) + 1; // Math.floor取到一个整数,并对10取余。

    叶子生命周期越长,这个数会越大。也就更easy被“减速” var yslow = dt * pseudoRand * 0.5 + 1; var xslow = dt * pseudoRand * 0.05 + 1; if (particle.vy < 1) // 速度低于 1 则停止 particle.vy = 0; else particle.vy = (particle.vy / yslow); // 否则除以摩擦系数 if (particle.vx < 1) particle.vx = 0; else particle.vx = (particle.vx / xslow); particle.update = true; } } } //! [1] ImageParticle { anchors.fill: parent id: particles sprites: [Sprite { // 将多个png赋予图像粒子的方法 source: "qrc:/images/realLeaf1.png" frameCount: 1 frameDuration: 1 // 相似“导入者”。其生命周期非常短,1ms后它将变成后面的图像 to: {"a":1, "b":1, "c":1, "d":1} // 有1/4的概率变成"a",1/4的概率变成"b"...后面相似 }, Sprite { // 当该图像没有可转变的内容。它将反复播放自己 name: "a" source: "qrc:/images/realLeaf1.png" frameCount: 1 // 我们的单帧静态图也就是仅有一帧的连续图 frameDuration: 10000 }, Sprite { name: "b" source: "qrc:/images/realLeaf2.png" frameCount: 1 frameDuration: 10000 }, Sprite { name: "c" source: "qrc:/images/realLeaf3.png" frameCount: 1 frameDuration: 10000 }, Sprite { name: "d" source: "qrc:/images/realLeaf4.png" frameCount: 1 frameDuration: 10000 } ] z:4 // 在图像中的层次 } } }



    (4)Friction

    在上面的样例中我们看到了怎样使用代码来模拟一个摩擦效果,可是Qt Quick已经为我们提供了一个模拟摩擦效果的Affector。它就是Friction。

    这个样例与上面的样例类似:


    代码十分简练。

    friction.qml:

    import QtQuick 2.0
    import QtQuick.Particles 2.0
    
    Item {
         360
        height: 600
    
        Image {
            source: "qrc:/images/backgroundLeaves.jpg"
            anchors.fill: parent
        }
        ParticleSystem {
            anchors.fill: parent
            Emitter {
                 parent.width
                emitRate: 4
                lifeSpan: 14000
                size: 80
                velocity: PointDirection { y: 160; yVariation: 80; xVariation: 20 }  // xVariation给了叶子水平方向上移动的能力。可是达不到wander的“摆动”效果
            }
    
            ImageParticle {               // 图像粒子同上
                anchors.fill: parent
                id: particles
                sprites: [Sprite {
                        source: "qrc:/images/realLeaf1.png"
                        frameCount: 1
                        frameDuration: 1
                        to: {"a":1, "b":1, "c":1, "d":1}
                    }, Sprite {
                        name: "a"
                        source: "qrc:/images/realLeaf1.png"
                        frameCount: 1
                        frameDuration: 10000
                    },
                    Sprite {
                        name: "b"
                        source: "qrc:/images/realLeaf2.png"
                        frameCount: 1
                        frameDuration: 10000
                    },
                    Sprite {
                        name: "c"
                        source: "qrc:/images/realLeaf3.png"
                        frameCount: 1
                        frameDuration: 10000
                    },
                    Sprite {
                        name: "d"
                        source: "qrc:/images/realLeaf4.png"
                        frameCount: 1
                        frameDuration: 10000
                    }
                ]
    
                 100
                height: 100
                x: 20
                y: 20
                z:4
            }
    
            //! [0]
            Friction {                  // Friction为粒子带来摩擦效果,我们能够设置一个阈值。使Friction仅仅影响速度大于该阈值的粒子。

    该阈值默觉得0 anchors.fill: parent anchors.margins: -40 factor: 0.4 // 摩擦系数,值越大摩擦力越大 } //! [0] } }



    (5)Gravity

    类似的,除了摩擦力,我们另一个Affector用来模拟万有引力。

    它展示了叶片向地面加速飘落的效果。


    图中的绿色是"地面",能够拖动它360度旋转。叶片始终向“地面”的中心加速下落。gravity.aml:

    import QtQuick 2.0
    import QtQuick.Particles 2.0
    
    Item {
        id: window
         320; height: 480
        Rectangle {
            id: sky
            anchors.fill: parent          // 蓝色的背景覆盖了整个矩形范围
            gradient: Gradient {
                GradientStop {
                    position: 0.0
                    color: "DeepSkyBlue"
                }
                GradientStop {
                    position: 1.0
                    color: "SkyBlue"
                }
            }
        }
    
        Rectangle {                       // 由于在后面要实现“地面”的旋转。所以设置了较大的尺寸
            id: ground
             parent.height * 2
            height: parent.height
            y: parent.height/2
            x: parent.width/2 - parent.height
            transformOrigin: Item.Top          // 用来设置旋转和缩放的中心点
            rotation: 0
            gradient: Gradient {
                GradientStop { position: 0.0; color: "ForestGreen"; }
                GradientStop { position: 1.0; color: "white"; }
            }
        }
    
        MouseArea {
            anchors.fill: parent
            onPositionChanged: {         // 该信号在鼠标按下并移动位置时放出,假设不须要按下鼠标,可设置hoverEnabled为true
                var rot = Math.atan2(mouseY - window.height/2,mouseX - window.width/2) * 180/Math.PI; // 返回当前鼠标方向矢量与X 轴正方向的夹角
                ground.rotation = rot;           // 以该角度旋转
            }
        }
    
        ParticleSystem { id: sys }
        //! [0]
        Gravity {                  // 当使用Gravity时。要注意它对整个场景的吸引力都是同样的。假设角度和加速度恒定,最好直接在Emitter中设置
            system: sys            // 但在此例中假设直接设置Emitter,角度的计算会比較复杂
            magnitude: 32          // 强度
            angle: ground.rotation + 90  // 运动方向
        }
        //! [0]
        Emitter {
            system: sys
            anchors.centerIn: parent
            emitRate: 1
            lifeSpan: 10000
            size: 64
        }
        ImageParticle {
            anchors.fill: parent
            system: sys
            source: "qrc:/images/realLeaf1.png"
        }
    
    }


    (6)GroupGoal

    在前面我们学习到我们能够设置ImageParticle的groups属性,从而让不同的Emitter发送不同的粒子。

    更进一步。使用ParticleGroup和GroupGoal能够实现粒子在特定状态下的跳变。


    能够看到,这些红色的小光点在经过蓝色火焰后被点燃成火苗。同一时候被鼠标滑过的也将被点燃。界面的右上角还有个数字用来记录被点燃的火苗数。

    代码例如以下,groupgoal.qml:

    import QtQuick 2.0
    import QtQuick.Particles 2.0
    
    Rectangle {
        id: root
         360
        height: 600
        color: "black"
    
        property int score: 0               // 设置一个属性用来记录分数
        Text {
            color: "white"
            anchors.right: parent.right
            text: score
        }
    
        ParticleSystem {
            id: particles
            anchors.fill: parent
            // ![unlit]
            ParticleGroup {         // 这个元素有点相似状态机的概念,它将一种状态下的粒子群以打包的形式放在一起,然后通过name跳转
              name: "unlit"
                duration: 1000      // 1s后进入下一个状态
                to: {"lighting":1, "unlit":99}   // 设置百分之中的一个的光球能够自燃
                ImageParticle {
                    source: "qrc:/images/particleA.png"  // 资源文件里的一个光点,有点相似经常使用的glowdot,可是更大一些
                    colorVariation: 0.1
                    color: "#2060160f"            // 光点的颜色为红褐色
                }
                GroupGoal {                     // 继承自Affector,提供特定条件满足下的状态跳转
                    whenCollidingWith: ["lit"]  // 当碰撞到正在燃烧的火苗时
                    goalState: "lighting"       // 跳转为"lighting"状态
                    jump: true                  // 设置为立马跳转
                }
            }
            // ![unlit]
            // ![lighting]
            ParticleGroup {       // 一个过渡状态,正在被点亮的状态
                name: "lighting"
                duration: 100     // 0.1秒后跳转到"lit"
                to: {"lit":1}
            }
            // ![lighting]
            // ![lit]
            ParticleGroup {           // 被点亮状态
                name: "lit"
                duration: 10000       // 终态粒子的生命周期
                onEntered: score++;   // 分数加一
                TrailEmitter {          // 使用TrailEmitter构建尾部火焰
                    id: fireballFlame
                    group: "flame"      // 粒子"flame"是基于下方定义的ImageParticle
    
                    emitRatePerParticle: 48   // 每一个lit后尾随48玫"火焰"
                    lifeSpan: 200             // 生命周期与焰尾长度成正比
                    emitWidth: 8
                    emitHeight: 8
    
                    size: 24
                    sizeVariation: 8
                    endSize: 4                // 尾部体积更小
                }
    
                TrailEmitter {               // 还有一个TrailEmitter用来构建烟雾
                    id: fireballSmoke
                    group: "smoke"            // smoke在下方定义
            // ![lit]
    
                    emitRatePerParticle: 120
                    lifeSpan: 2000            // 较长的生命周期用来进行自己的动画
                    emitWidth: 16
                    emitHeight: 16
    
                    velocity: PointDirection {yVariation: 16; xVariation: 16}
                    acceleration: PointDirection {y: -16}              // 烟雾首先向下运动,随之向上升腾
    
                    size: 24
                    sizeVariation: 8
                    endSize: 8
                }
            }
    
            ImageParticle {               // 灰色烟雾粒子
                id: smoke
                anchors.fill: parent
                groups: ["smoke"]
                source: "qrc:///particleresources/glowdot.png"
                colorVariation: 0
                color: "#00111111"
            }
            ImageParticle {               // 蓝色闫焰苗粒子
                id: pilot
                anchors.fill: parent
                groups: ["pilot"]
                source: "qrc:///particleresources/glowdot.png"
                redVariation: 0.01
                blueVariation: 0.4        // 设置RGB中蓝色的变化率
                color: "#0010004f"
            }
            ImageParticle {               // 红色火焰粒子
                id: flame
                anchors.fill: parent
                groups: ["flame", "lit", "lighting"]
                source: "qrc:/images/particleA.png"
                colorVariation: 0.1
                color: "#00ff400f"
            }
    
            Emitter {                       // 用来发射易燃小球
                height: parent.height/2
                emitRate: 4
                lifeSpan: 4000//TODO: Infinite & kill zone  // demo中的凝视,TODO表示还要做的事。FIXME表示代码待改动,XXX表示有待商榷
                size: 24
                sizeVariation: 4
                velocity: PointDirection {x:120; xVariation: 80; yVariation: 50}
                acceleration: PointDirection {y:120}
                group: "unlit"
            }
    
            Emitter {                       // 用来构建焰苗
                id: flamer
                x: 100
                y: 300
                group: "pilot"
                emitRate: 80
                lifeSpan: 600
                size: 24
                sizeVariation: 2
                endSize: 0
                velocity: PointDirection { y:-100; yVariation: 4; xVariation: 4 }  // 粒子向上移动形成焰苗的升腾感
                // ![groupgoal-pilot]
                GroupGoal {
                    groups: ["unlit"]        // 设置被影响的粒子群
                    goalState: "lit"
                    jump: true               // 直接跳转,否则默觉得过渡时间结束后再跳转
                    system: particles
                    x: -15
                    y: -55
                    height: 75
                     30
                    shape: MaskShape {source: "qrc:/images/matchmask.png"}  // 这张图片是一个焰苗的图形。使用它能够使Affector影响一个非矩形区域
                }
                // ![groupgoal-pilot]
            }
            // ![groupgoal-ma]
            //Click to enflame
            GroupGoal {
                groups: ["unlit"]             // 设置其能够影响的粒子群
                goalState: "lighting"         // 目标状态
                jump: true
                enabled: ma.pressed           // 按下事件使能
                 18                     // 作用区域
                height: 18
                x: ma.mouseX - width/2
                y: ma.mouseY - height/2
            }
            // ![groupgoal-ma]
            MouseArea {
                id: ma
                anchors.fill: parent
            }
        }
    }


    (7)Move

    这个样例展示了直接使用Affector影响粒子运动(位置、速度、加速度)的方法。


    代码非常easy,我们大致看一下好了,move.qml:

    import QtQuick 2.0
    import QtQuick.Particles 2.0
    
    Rectangle {
         360
        height: 540
        color: "black"
        ParticleSystem {                                  // 第一束红色粒子
            anchors.fill: parent
            ImageParticle {
                groups: ["A"]
                anchors.fill: parent
                source: "qrc:///particleresources/star.png"
                color:"#FF1010"
                redVariation: 0.8                          // 形成"明红"到"暗红"的颜色差异
            }
    
            Emitter {
                group: "A"
                emitRate: 100
                lifeSpan: 2800
                size: 32
                sizeVariation: 8
                velocity: PointDirection{ x: 66; xVariation: 20 }
                 80                                      // 产生粒子的区域是(0,0)到(80,80)的矩形范围
                height: 80
            }
    
            //! [A]
            Affector {
                groups: ["A"]                                  // Affector作用于A
                x: 120                                         // 影响区域
                 80
                height: 80
                once: true
                position: PointDirection { x: 120; }            // x 添加120
            }
            //! [A]
    
            ImageParticle {                                     // 第二束绿色粒子
                groups: ["B"]
                anchors.fill: parent
                source: "qrc:///particleresources/star.png"
                color:"#10FF10"
                greenVariation: 0.8
            }
    
            Emitter {
                group: "B"
                emitRate: 100
                lifeSpan: 2800
                size: 32
                sizeVariation: 8
                velocity: PointDirection{ x: 240; xVariation: 60 }
                y: 260
                 10
                height: 10
            }
    
            //! [B]
            Affector {
                groups: ["B"]
                x: 120
                y: 240
                 80
                height: 80
                once: true
                velocity: AngleDirection { angleVariation:360; magnitude: 72 } // 角度变化范围和强度
            }
            //! [B]
    
            ImageParticle {                                      // 第三束蓝色粒子
                groups: ["C"]
                anchors.fill: parent
                source: "qrc:///particleresources/star.png"
                color:"#1010FF"
                blueVariation: 0.8
            }
    
            Emitter {
                group: "C"
                y: 400
                emitRate: 100
                lifeSpan: 2800
                size: 32
                sizeVariation: 8
                velocity: PointDirection{ x: 80; xVariation: 10 }
                acceleration: PointDirection { y: 10; x: 20; }
                 80
                height: 80
            }
    
            //! [C]
            Affector {
                groups: ["C"]
                x: 120
                y: 400
                 80
                height: 120
                once: true
                relative: false
                acceleration: PointDirection { y: -80; }         // 在y方向的加速度下降80
            }
            //! [C]
    
        }
    }


    (8)SpriteGoal

    这个样例向我们展示了怎样对使用sprites的ImageParticle做特殊的处理。使其在我们想要它改变时进行状态的跳转。

    如图是“星际迷航”中的飞船。它将撞毁其接触到的陨石。


    spritegoal.qml:

    import QtQuick 2.0
    import QtQuick.Particles 2.0
    
    Item {
        id: root
         360
        height: 540
        MouseArea {
            id: ma
            anchors.fill: parent
        }
    
        ParticleSystem { id: sys }
        Image {
            source: "qrc:/images/finalfrontier.png"  // 星际迷航
            transformOrigin: Item.Center             // 以中心点旋转,一共同拥有9个点可选,四个边角,四个边线中心,以及中心点
            anchors.centerIn: parent
            NumberAnimation on rotation {            // 背景缓慢旋转
                from: 0
                to: 360
                duration: 200000
                loops: Animation.Infinite
            }
    
        }
        ImageParticle {                              // 星星粒子
            system: sys
            groups: ["starfield"]
            source: "qrc:///particleresources/star.png"
            colorVariation: 0.3
            color: "white"
        }
        Emitter {
            id: starField
            system: sys
            group: "starfield"
    
            emitRate: 80
            lifeSpan: 2500
    
            anchors.centerIn: parent
    
            //acceleration: AngleDirection {angleVariation: 360; magnitude: 200}//Is this a better effect, more consistent velocity?

    acceleration: PointDirection { xVariation: 200; yVariation: 200; } // 上面是源代码中的凝视,作者留给我们一个问题。这个从中心点向外散射的粒子。是使用AngleDirection还是PointDirection?笔者想了下。以第一行代码发射的话。所有粒子的速度都将是同样的。而第二行代码则具有更大的随机性。

    以星星的散射而言。第二行代码更合理。 size: 0 endSize: 80 sizeVariation: 10 } Emitter { // 陨石的发射器 system: sys group: "meteor" emitRate: 12 lifeSpan: 5000 acceleration: PointDirection { xVariation: 80; yVariation: 80; } // 与星星的发射相似 size: 15 endSize: 300 // 增大的endSize形成由远及进感 anchors.centerIn: parent } ImageParticle { // 陨石粒子。由sprites的多帧图像构成 system: sys groups: ["meteor"] sprites:[Sprite { id: spinState // 自旋陨石 name: "spinning" source: "qrc:/images/meteor.png" frameCount: 35 frameDuration: 40 randomStart: true // 从任意的一帧開始 to: {"explode":0, "spinning":1} // 因为"explode"为0,因此spinning实际上是无限循环。"explode": 0能够不写。

    但为了逻辑清楚,加上更好 },Sprite { // 碎裂陨石 name: "explode" source: "qrc:/images/_explo.png" frameCount: 22 frameDuration: 40 to: {"nullFrame":1} // 去到一个空白图像 },Sprite {//Not sure if this is needed, but seemed easiest // 作者称不确定这个空白图像是否须要。可是带上它似乎更好 name: "nullFrame" source: "qrc:/images/nullRock.png" frameCount: 1 frameDuration: 1000 } ] } //! [0] SpriteGoal { // 这就是Affector中的SpriteGoal了 groups: ["meteor"] // 与groupGoal不同。GroupGoal影响的ParticleGroup,而SpriteGoal影响的是这里使用Sprites的粒子 system: sys goalState: "explode" // 目标状态 jump: true // 立马跳转 anchors.fill: rocketShip // 作用范围尾随飞船 60 height: 60 } //! [0] Image { // 企业号飞船,因为要使飞船绕一个固定的中心点旋转。坐标与旋转的计算所有放在Image中比較麻烦,我们能够使用两个Item来进行逻辑上的圆周计算 id: rocketShip source: "qrc:/images/rocket.png" anchors.centerIn: holder rotation: (circle.percent+0.25) * 360 // 随着所在圆周位置的不同对自身进行旋转。因为原图飞船是向上的,因此将其初始旋转90度 z: 2 } Item { // 通过以下的圆心和连续变化的百分比,这个Item用来得到实际的坐标 id: holder x: circle.x - Math.sin(circle.percent * 6.28316530714)*200 // 百分比乘以2π,200为半径 y: circle.y + Math.cos(circle.percent * 6.28316530714)*200 z: 1 } Item { id: circle x: root.width / 1.2 // 圆心的位置 y: root.height / 1.7 property real percent: 0 // 定义一个百分比属性 SequentialAnimation on percent { // 4秒的1到0循环 id: circleAnim1 loops: Animation.Infinite running: true NumberAnimation { duration: 4000 from: 1 to: 0 } } } ImageParticle { // 飞船的尾气粒子 z:0 // 其z值比飞船小。这样这些粒子不会覆盖在飞船上面 system: sys groups: ["exhaust"] source: "qrc:///particleresources/fuzzydot.png" color: "orange" SequentialAnimation on color { loops: Animation.Infinite ColorAnimation { from: "red" to: "cyan" duration: 1000 } ColorAnimation { from: "cyan" to: "red" duration: 1000 } } colorVariation: 0.2 } Emitter { // 喷气粒子发射器 id: trailsNormal2 system: sys group: "exhaust" emitRate: 300 lifeSpan: 500 y: holder.y x: holder.x velocity: PointDirection { xVariation: 40; yVariation: 40; } velocityFromMovement: 16 acceleration: PointDirection { xVariation: 10; yVariation: 10; } size: 4 sizeVariation: 4 } }



    (9)Turbulence

    在上篇博文的最后一个小样例——飞翔的火焰 中我们事实上已经接触到了Turbulence,它用来为粒子提供一个气流的效果。

    在这个样例中我们能够更清晰地看到它的使用方法。

    能够看到Turbulence为火苗和烟雾带来的效果:


    Turbulence.qml:

    import QtQuick 2.0
    import QtQuick.Particles 2.0
    
    Rectangle {
         320
        height: 480
        color: "#222222"
        id: root
        Image {
            source: "qrc:/images/candle.png"                 // 一根空白的蜡烛 
            anchors.bottom: parent.bottom
            anchors.horizontalCenter: parent.horizontalCenter   
            anchors.bottomMargin: -60                        // 这张图以下有一段空白
            anchors.horizontalCenterOffset: 2                // 水平中心向右平移2个像素
        }
        ParticleSystem {
            anchors.fill: parent
            MouseArea {                                     // 点击后关闭/打开Turbulence效果
                anchors.fill: parent
                onClicked: turb.enabled = !turb.enabled
            }
    
            //! [0]
            Turbulence {
                id: turb
                enabled: true
                height: (parent.height / 2) - 4
                 parent.width
                x: parent. width / 4
                anchors.fill: parent
                strength: 32                       // 能够为strength加入一个NumberAnimation,然后通过设置Easing,能够达到更逼近现实的气流效果
                NumberAnimation on strength{from: 16; to: 64; easing.type: Easing.InOutBounce; duration: 1800; loops: -1}
            }
            //! [0]
    
            ImageParticle {                         // 烟雾
                groups: ["smoke"]
                source: "qrc:///particleresources/glowdot.png"
                color: "#11111111"
                colorVariation: 0
            }
            ImageParticle {                         // 火苗
                groups: ["flame"]
                source: "qrc:///particleresources/glowdot.png"
                color: "#11ff400f"
                colorVariation: 0.1
            }
            Emitter {                               // 火苗粒子由窗体中心发出
                anchors.centerIn: parent
                group: "flame"
    
                emitRate: 120
                lifeSpan: 1200
                size: 20
                endSize: 10
                sizeVariation: 10
                acceleration: PointDirection { y: -40 }
                velocity: AngleDirection { angle: 270; magnitude: 20; angleVariation: 22; magnitudeVariation: 5 }
            }
            TrailEmitter {
                id: smoke1
                 root.width
                height: root.height/2
                group: "smoke"
                follow: "flame"
    
                emitRatePerParticle: 1
                lifeSpan: 2400
                lifeSpanVariation: 400
                size: 16
                endSize: 8
                sizeVariation: 8
                acceleration: PointDirection { y: -40 }
                velocity: AngleDirection { angle: 270; magnitude: 40; angleVariation: 22; magnitudeVariation: 5 }
            }
            TrailEmitter {                                   // 第二个TrailEmitter用来在更高一点的地方释放出更浓郁的烟雾
                id: smoke2
                 root.width
                height: root.height/2 - 20
                group: "smoke"
                follow: "flame"
    
                emitRatePerParticle: 4
                lifeSpan: 2400
                size: 36
                endSize: 24
                sizeVariation: 12
                acceleration: PointDirection { y: -40 }
                velocity: AngleDirection { angle: 270; magnitude: 40; angleVariation: 22; magnitudeVariation: 5 }
            }
        }
    }


    (10)Wander

    相同我们在本文第三个小样例中已经接触过wander了。在那我们使用wander为落叶加入了摇摆的飘落效果。

    在这个样例中我们将了解到,除了速度。wander还能够进一步作用于位置和加速度。


    能够看到在飘落的雪花背景中,有三个button分别用来选择位置,速度,以及加速度。通过点击这些button,能够改变这些雪花在x方向上的不同运动效果。这些button是在还有一个Qml文件里定义的。代码比較简单,贴在以下,就不一句句介绍了。

    GreyButton.qml:

    import QtQuick 2.0
    
    Item {
        id: container
    
        property string text: "Button"
        property string subText: ""
        signal clicked
    
         buttonLabel.width + 20; height: col.height + 12
    
        MouseArea {
            id: mouseArea;
            anchors.fill: parent;
            onClicked: container.clicked();
            onPressed: background.color = Qt.darker("lightgrey");
            onReleased: background.color="lightgrey";
        }
    
        Rectangle {
            id: background
            anchors.fill: parent
            color: "lightgrey"
            radius: 4
            border. 1
            border.color: Qt.darker(color)
        }
    
        Column {
            spacing: 2
            id: col
            x: 10
            y: 6
            Text {
                id: buttonLabel; text: container.text; color: "black"; font.pixelSize: 24
            }
            Text {
                id: buttonLabel2; text: container.subText; color: "black"; font.pixelSize: 12
            }
        }
    }

    wander.qml:

    import QtQuick 2.0
    import QtQuick.Particles 2.0
    
    Rectangle {
         360
        height: 540
        ParticleSystem { id: particles }
        ImageParticle {                                     // 雪花粒子
            system: particles
            sprites: Sprite {
                name: "snow"
                source: "../../images/snowflake.png"
                frameCount: 51
                frameDuration: 40
                frameDurationVariation: 8
            }
        }
    
        //! [0]
        Wander {                                            // wander
            id: wanderer
            system: particles
            anchors.fill: parent
            xVariance: 360/(wanderer.affectedParameter+1); // xVariance与pace必须都定义。因为未定义yVariance因此不会影响y方向的运动
            pace: 100*(wanderer.affectedParameter+1);     // 这里wanderer.affectedParameter实际等于0,不太懂这里的意思
        }
        //! [0]
    
        Emitter {
            system: particles
            emitRate: 20
            lifeSpan: 7000
            velocity: PointDirection { y:80; yVariation: 40; }
            acceleration: PointDirection { y: 4 }
            size: 20
            sizeVariation: 10
             parent.width
            height: 100
        }
        Row {                                             // 这里使用了一个布局器
            anchors.bottom: parent.bottom
            anchors.horizontalCenter: parent.horizontalCenter
            spacing: 4
            GreyButton {
                text:"dx/dt"
                onClicked: wanderer.affectedParameter = Wander.Position; // 点击改变Wander的影响属性
            }
            GreyButton {
                text:"dv/dt"
                onClicked: wanderer.affectedParameter = Wander.Velocity;
            }
            GreyButton {
                text:"da/dt"
                onClicked: wanderer.affectedParameter = Wander.Acceleration;
            }
        }
    }





    版权声明:本文博主原创文章,博客,未经同意不得转载。

  • 相关阅读:
    markdown基本语法
    每天一个Linux命令:pwd(3)
    每天一个Linux命令:cd(2)
    每天一个Linux命令:ls(1)
    每天一个Linux命令:man(0)
    maven命令行创建项目问题
    Regular Expression
    JS事件流
    canvas与svg区别
    js调试
  • 原文地址:https://www.cnblogs.com/hrhguanli/p/4801535.html
Copyright © 2011-2022 走看看