本系列全部文章能够在这里查看http://blog.csdn.net/cloud_castle/article/category/2123873
接上文 Qt5官方demo解析集12——Qt Quick Particles Examples - CustomParticles
先唠下嗑,在上文CustomParticles中我们接触了强大的ShaderEffect,笔者对其产生了极大的兴趣,于是去找了找有没有很多其它相关的例程,于是就发现了一个QML Video Shader Effects Example。确实效果华丽,以下放个图,回头再看看这个demo~
这个demo能够处理图片、视频以及摄像头数据,算是很强大的功能了。
只是在手机上执行时布局似乎有些问题。
好了,不扯远了,这次的demo又回归了ImageParticle。相信大家都不陌生了。这个demo应该比上一个要轻松,我们来看看吧:
依然是熟悉的选择框:
(1)All at once
这个样例演示了一群旋转的小熊。以下有一行话,“QML这么叼你敢信吗...”
确实是五彩缤纷哈,怎么来形成多彩的效果呢?可能你立即会想到ImageParticle中的colorVariation这个属性,将这个值设高不就能形成多彩的效果吗?确实不错,可是假设我们要求这个小熊仅仅在几种颜色之间变化呢?比如橘红,红色。青色,绿色,和黄色?或者再多一点,连随机数取值也不好做?那么ImageParticle为我们提供了一个属性colorTable。这个属性使得我们能够在一个一维纹理中取出颜色值赋予图像。我们通过自己定义一个合适的一维图像就能够决定小熊的颜色了。
这里我将colorVariation设置为1,能够看下对照效果:
能够看到颜色确实更加丰富。但因为本身的一维图像是带有透明度的,想要模仿原例的效果,我们还须要设置透明度:
这里将alpha设置为0.5:
好了。代码非常easy,说了这么多,就不讲了哈。allatonce.qml:
import QtQuick 2.0 import QtQuick.Particles 2.0 Rectangle { color: "white" 640 height: 480 ParticleSystem { id: sys } ImageParticle { // ![0] sprites: [ Sprite { name: "bear" source: "qrc:/images/bear_tiles.png" frameCount: 13 frameDuration: 120 } ] colorVariation: 0.5 rotationVelocityVariation: 360 colorTable: "qrc:/images/colortable.png" // ![0] system: sys } Friction { factor: 0.1 system: sys } Emitter { system: sys anchors.centerIn: parent id: particles emitRate: 200 lifeSpan: 6000 velocity: AngleDirection {angleVariation: 360; magnitude: 80; magnitudeVariation: 40} size: 60 endSize: 120 } Text { x: 16 y: 16 text: "QML..." style: Text.Outline; styleColor: "#AAAAAA" font.pixelSize: 32 } Text { anchors.bottom: parent.bottom anchors.right: parent.right anchors.margins: 16 text: "... can you be trusted with the power?" style: Text.Outline; styleColor: "#AAAAAA" font.pixelSize: width > 400 ? 32 : 16 } }
我将colortable的图贴在以下:
“” < - 就在这里。它纵向仅仅有一个像素。非常窄。
(2)Colored
这个样例展示了两种星星的效果。
colored.qml:
import QtQuick 2.0 import QtQuick.Particles 2.0 Rectangle { 360 height: 540 color: "black" ParticleSystem { anchors.fill: parent ImageParticle { // 背景星星 groups: ["stars"] anchors.fill: parent source: "qrc:///particleresources/star.png" } Emitter { group: "stars" emitRate: 800 lifeSpan: 2400 size: 24 sizeVariation: 8 anchors.fill: parent // 布满父对象的背景星星 } // ![0] ImageParticle { // 未定义的group默觉得"" anchors.fill: parent source: "qrc:///particleresources/star.png" alpha: 0 alphaVariation: 0.2 // 多彩与透明效果 colorVariation: 1.0 } // ![0] Emitter { // 默认发射group名为""的粒子 anchors.centerIn: parent emitRate: 400 lifeSpan: 2400 size: 48 sizeVariation: 8 velocity: AngleDirection {angleVariation: 180; magnitude: 60} // 180的变化度,即是(-180,180) } Turbulence { // 最后加入一些气流效果 anchors.fill: parent strength: 2 } } }
(3)Color Table
从名字能够知道这里样例着重介绍了colorTable这个属性。
能够看到3个光束以类似∞的轨迹执行,colortable.qml:
Rectangle { id: root 360 height: 540 color: "black" ParticleSystem { id: particles } ImageParticle { system: particles colorVariation: 0.5 alpha: 0 //! [0] source: "qrc:///particleresources/glowdot.png" colorTable: "qrc:/images/colortable.png" // 这个与样例一同样 sizeTable: "qrc:/images/colortable.png" // 有意思的是,我们能够使用这个一维图像的透明度来决定粒子的尺寸,依据Manual所说,这个属性将在之后被移除。取而代之的是使用自己定义的缓和曲线 //! [0] } Emitter { system: particles emitRate: 500 lifeSpan: 2000 y: root.height / 2 + Math.sin(t * 2) * root.height * 0.3 // 定义了一个相似∞的轨迹,删掉t中的2。它将变成一个椭圆 x: root.width / 2 + Math.cos(t) * root.width * 0.3 property real t; NumberAnimation on t { from: 0; to: Math.PI * 2; duration: 10000; loops: Animation.Infinite } velocityFromMovement: 20 velocity: PointDirection { xVariation: 5; yVariation: 5;} // 有一定的四周消散能力 acceleration: PointDirection { xVariation: 5; yVariation: 5;} size: 16 //endSize: 8 //sizeVariation: 8 } }关于为什么会形成3个光束:这里的粒子实际上是按轨迹不断生成的,新的粒子产生,旧的粒子还未消散。形成了一条光束。而这些粒子随着生命周期的变化,其颜色、透明度以及尺寸都是与这个colortable一维图像相关的,这个图像我在上面贴出来了,当中间几段有非常明显的透明区域,当粒子达到与之相相应的生命周期,我们也就看不到了,随着生命周期的推进,它们又以其它的颜色展现出来。
(4)Deformation
这一节主要介绍了ImageParticle的变形。主要是旋转以及伸缩。上面两排海星星在旋转,以下的海星星被压缩。
deformation.qml:
import QtQuick 2.0 import QtQuick.Particles 2.0 Rectangle { color: "goldenrod" 400 height: 400 ParticleSystem {id:sys} //! [spin] ImageParticle { system: sys groups: ["goingLeft", "goingRight"] source: "qrc:/images/starfish_4.png" rotation: 90 // (顺时针)旋转90度 rotationVelocity: 90 // 旋转速度 autoRotation: true // 定义该属性使粒子能依据运动轨迹自己主动旋转,这里是平移所以看不到效果 } //! [spin] //! [deform] ImageParticle { system: sys groups: ["goingDown"] source: "qrc:/images/starfish_0.png" // 换了一张图,这个星星不开心些 rotation: 180 // 旋转180度,倒过来了 yVector: PointDirection { y: 0.5; yVariation: 0.25; xVariation: 0.25; } // yVector參数是一个矢量,也就是说我们不仅能够压缩这个图像,还能使它随意拉伸(想象我们拉住一个四边形的两个角随意拉扯的效果)。 } //! [deform] Timer { running: true // 几个定时器用来发射粒子 repeat: false interval: 100 onTriggered: emitA.enabled = true; } Timer { running: true repeat: false interval: 4200 onTriggered: emitB.enabled = true; } Timer { running: true repeat: false interval: 8400 onTriggered: emitC.enabled = true; } Emitter { // 发射器。假设不清楚能够參考前面的博文 id: emitA x: 0 y: 120 system: sys enabled: false group: "goingRight" velocity: PointDirection { x: 100 } lifeSpan: 4000 emitRate: 1 size: 128 } Emitter { id: emitB x: 400 y: 240 system: sys enabled: false group: "goingLeft" velocity: PointDirection { x: -100 } lifeSpan: 4000 emitRate: 1 size: 128 } Emitter { id: emitC x: 0 y: 360 system: sys enabled: false group: "goingDown" velocity: PointDirection { x: 100 } lifeSpan: 4000 emitRate: 1 size: 128 } }
(5)Rotation
我们在上一节中就接触到了rotation,在那个里面rotation用来实现了图片的旋转动画。而这个样例则主要介绍了它的autoRotation - 自己主动转向。
先看看效果:
首先是一串从中下向四周发散的海星星,假设屏幕被点击。这些海星星将按其执行轨迹翻转,保证对每一个轨迹而言都是正的。
rotation.qml:
import QtQuick 2.0 import QtQuick.Particles 2.0 Rectangle { color: "goldenrod" 1000 height: 1000 ParticleSystem {id: sys} ImageParticle { id: up system: sys source: "qrc:/images/starfish_2.png" autoRotation: true // 这个属性我们前面有谈,再形象一点的话,假设海星星做圆周运动,它的脚会始终指向圆心 rotation: -90 // 粒子在自己主动旋转后会再加上这个旋转量,那么就得到了图中海星星对每一个运动方向都为正的效果 } Emitter { anchors.centerIn: parent system: sys emitRate: 10 size: 200 lifeSpan: 10000 velocity: AngleDirection {angleVariation: 360; magnitudeVariation: 100;} } MouseArea { anchors.fill: parent // 实现鼠标点击功能 onClicked: { up.autoRotation = !up.autoRotation up.rotation = up.autoRotation ? -90 : 0 } } }
(6)Sharing
由名字我们就行猜出一些端倪,这个样例向我们展示了怎样在同一个或是同一类粒子中展示不同的ImageParticle的效果。
同一时候。一个粒子中还可以包括多个ImageParticle中定义的属性。
因为原例中的文字是白色的。截图看不太清楚,我把它改成了蓝色。只是这并不影响。我们关注的是它的“小花”(粒子)。
能够看到小花在整个屏幕中都是偏白色,而在我们选中项的高亮中它显示为黑红色。而且它是随着进入的部分而部分变换。这在实际使用中相当经常使用。
另外还有些listView的操作与动画,但这就不是我们这一节重点啦~
sharing.qml:
// This example shows how to create your own highlight delegate for a ListView // that uses a SpringAnimation to provide custom movement when the // highlight bar is moved between items. import QtQuick 2.0 import QtQuick.Particles 2.0 Rectangle { property real delegateHeight: 65 200; height: 300 gradient: Gradient { GradientStop { position: 0.0; color: "#EEEEFF" } GradientStop { position: 1.0; color: "lightblue" } } // Define a delegate component. A component will be // instantiated for each visible item in the list. Component { // 我们须要为listView的每一个可视项目创建一个组件,定义一个组件就相似定义了一个qml文件。这个文件名称就是petDelegate.qml,Item是它的根文件夹。组件中定义的可视化对象不会被直接渲染,除非它被其它类型所载入。 id: petDelegate // 在Item外我们仅仅能定义这个id名 Item { // Item作为这个可视化组件的根文件夹 id: wrapper 200; height: delegateHeight z: 10 Column { Text {color: "blue"; text: name; font.pixelSize: 18 } // 按列排放的文字 Text {color: "blue"; text: 'Type: ' + type; font.pixelSize: 14 } Text {color: "blue"; text: 'Age: ' + age; font.pixelSize: 14 } } MouseArea { anchors.fill: parent; onClicked: listView.currentIndex = index; } // 被点击则作为当前对象 // indent the item if it is the current item states: State { name: "Current" // 设置一个当前状态 when: wrapper.ListView.isCurrentItem PropertyChanges { target: wrapper; x: 20 } // x缩进20 } transitions: Transition { NumberAnimation { properties: "x"; duration: 200 } // 为这个缩进加入一个动画 } } } // Define a highlight with customized movement between items. Component { // 将高亮显示框也定义为一个组件 id: highlightBar Rectangle { // Rectangle作为根文件夹 z: 0 200; height: delegateHeight gradient: Gradient { GradientStop { position: 0.0; color: "#99FF99" } GradientStop { position: 1.0; color: "#88FF88" } } y: listView.currentItem.y; // y坐标与当前项目坐标一致 Behavior on y { SpringAnimation { spring: 2; damping: 0.2 } } // 为 y 的改变加入一个弹簧动画 //! [1] ImageParticle { // 高亮框内的ImageParticle anchors.fill: parent system: particles source: "qrc:/images/flower.png" color: "red" clip: true alpha: 1.0 } //! [1] } } ListView { id: listView 200; height: parent.height model: petsModel // 指定模型 delegate: petDelegate // 指定托付对象 focus: true // Set the highlight delegate. Note we must also set highlightFollowsCurrentItem // to false so the highlight delegate can control how the highlight is moved. highlight: highlightBar // 指定highlight托付对象 highlightFollowsCurrentItem: false // 因为我们要实现自己定义的highlight动画,因此将该属性设置为false ParticleSystem { id: particles } // ParticleSystem Emitter { // Emitter system: particles anchors.fill: parent emitRate: 0 lifeSpan: 10000 size: 24 sizeVariation: 8 velocity: AngleDirection { angleVariation: 360; magnitude: 3 } maximumEmitted: 10 startTime: 5000 // 这个属性我们之前接触过了,它使Emitter被载入使直接显示5秒后的效果 Timer { running: true; interval: 10; onTriggered: parent.emitRate = 1; } } //! [0] ImageParticle { // 通用粒子,它覆盖了整个ListView,因此Emitter发射的粒子大部分通过它渲染 anchors.fill: parent // 可是当Emitter发射的粒子在高亮区域中时,它将转而使用highlight中的ImageParticle system: particles // 因此粒子颜色与透明度都被改变了 source: "qrc:/images/flower.png" // 但因为highlight中的ImageParticle中的rotation未被设置 alpha: 0.1 // 因此粒子将继续採用此处的rotationVariation: 180 color: "white" // 这也就是ImageParticle中的属性共享 rotationVariation: 180 z: -1 } //! [0] } ListModel { // 为ListView提供数据 id: petsModel ListElement { name: "Polly" type: "Parrot" age: 12 size: "Small" } ListElement { name: "Penny" type: "Turtle" age: 4 size: "Small" } ListElement { name: "Warren" type: "Rabbit" age: 2 size: "Small" } ListElement { name: "Spot" type: "Dog" age: 9 size: "Medium" } ListElement { name: "Schrödinger" type: "Cat" age: 2 size: "Medium" } ListElement { name: "Joey" type: "Kangaroo" age: 1 size: "Medium" } ListElement { name: "Kimba" type: "Bunny" age: 65 size: "Large" } ListElement { name: "Rover" type: "Dog" age: 5 size: "Large" } ListElement { name: "Tiny" type: "Elephant" age: 15 size: "Large" } } }
(7)Sprites
sprites大家都不陌生了。我们在前面的程序中大量接触到了这个东西。使用它要比使用GIF节省多得多的性能,而且与粒子系统一同工作,可以创造动态性能相当高的应用程序。
能够看到以下有仅仅会动的小熊,上方掉落的海星星也在不断变化着表情。
当下落到小熊附近时,它们将变成萌萌哒的"惊喜"表情。
sprites.qml:
import QtQuick 2.0 import QtQuick.Particles 2.0 Rectangle { color: "lightsteelblue" 800 height: 800 id: root SpriteSequence { // 该类型提供了一个机遇sprite的动画 sprites: Sprite { name: "bear" source: "qrc:/images/bear_tiles.png" // 图片贴在下方 frameCount: 13 frameDuration: 120 } 250 // 定义小熊的位置与层次 height: 250 x: 20 anchors.bottom: parent.bottom anchors.bottomMargin: 20 z:4 } ParticleSystem { id: sys } ImageParticle { anchors.fill: parent id: particles system: sys sprites: [Sprite { // 定义各种状态的海星星。并等概率相互转换 name: "happy" source: "qrc:/images/starfish_1.png" frameCount: 1 frameDuration: 260 to: {"happy": 1, "silly": 1, "angry": 1} }, Sprite { name: "angry" source: "qrc:/images/starfish_0.png" frameCount: 1 frameDuration: 260 to: {"happy": 1, "silly": 1, "angry": 1} }, Sprite { name: "silly" source: "qrc:/images/starfish_2.png" frameCount: 1 frameDuration: 260 to: {"happy": 1, "silly": 1, "noticedbear": 0} }, Sprite { // 在通常情况下,"noticedbear"状态无法达到 name: "noticedbear" source: "qrc:/images/starfish_3.png" frameCount: 1 frameDuration: 2600 }] } Emitter { // 海星星的发射器 system: sys emitRate: 2 lifeSpan: 10000 velocity: AngleDirection {angle: 90; magnitude: 60; angleVariation: 5} acceleration: PointDirection { y: 10 } size: 160 sizeVariation: 40 parent.width height: 100 } SpriteGoal { // 最后定义一个SpriteGoal使海星星在运动到矩形的左下部分时跳转到"noticedbear"状态 system: sys root.width; height: root.height/2; y: root.height/2; goalState:"noticedbear" } }