粒子组(Particle Group)

在本章开始时,我们已经介绍过粒子组了,默认下,粒子都属于空组(””)。使用GroupGoal控制器可以改变粒子组。为了实现可视化,我们创建了一个烟花示例,火箭进入,在空中爆炸形成壮观的烟火。

粒子组(Particle Group) - 图1

这个例子分为两部分。第一部分叫做“发射时间(Launch Time)”连接场景,加入粒子组,第二部分叫做“爆炸烟花(Let there be firework)”,专注于粒子组的变化。

让我们看看这两部分。

发射时间(Launch Time)

首先我们创建一个典型的黑色场景:

  1. import QtQuick 2.0
  2. import QtQuick.Particles 2.0
  3. Rectangle {
  4. id: root
  5. width: 480; height: 240
  6. color: "#1F1F1F"
  7. property bool tracer: false
  8. }

tracer使用被用作场景追踪的开关,然后定义我们的粒子系统:

  1. ParticleSystem {
  2. id: particleSystem
  3. }

我们添加两种粒子图片画笔(一个用于火箭,一个用于火箭喷射烟雾):

  1. ImageParticle {
  2. id: smokePainter
  3. system: particleSystem
  4. groups: ['smoke']
  5. source: "assets/particle.png"
  6. alpha: 0.3
  7. entryEffect: ImageParticle.None
  8. }
  9. ImageParticle {
  10. id: rocketPainter
  11. system: particleSystem
  12. groups: ['rocket']
  13. source: "assets/rocket.png"
  14. entryEffect: ImageParticle.None
  15. }

你可以看到在这些画笔定义中,它们使用groups属性来定义粒子的归属。只需要定义一个名字,Qt Quick将会隐式的创建这个分组。

现在我们需要将这些火箭发射到空中。我们在场景底部创建一个粒子发射器,将速度设置为朝上的方向。为了模拟重力,我们设置一个向下的加速度:

  1. Emitter {
  2. id: rocketEmitter
  3. anchors.bottom: parent.bottom
  4. width: parent.width; height: 40
  5. system: particleSystem
  6. group: 'rocket'
  7. emitRate: 2
  8. maximumEmitted: 4
  9. lifeSpan: 4800
  10. lifeSpanVariation: 400
  11. size: 32
  12. velocity: AngleDirection { angle: 270; magnitude: 150; magnitudeVariation: 10 }
  13. acceleration: AngleDirection { angle: 90; magnitude: 50 }
  14. Tracer { color: 'red'; visible: root.tracer }
  15. }

发射器属于’rocket’粒子组,与我们的火箭粒子画笔相同。通过粒子组将它们联系在一起。发射器将粒子发射到’rocket’粒子组中,火箭画笔将会绘制它们。

对于烟雾,我们使用一个追踪发射器,它将会跟在火箭的后面。我们定义’smoke’组,并且它会跟在’rocket’粒子组后面:

  1. TrailEmitter {
  2. id: smokeEmitter
  3. system: particleSystem
  4. emitHeight: 1
  5. emitWidth: 4
  6. group: 'smoke'
  7. follow: 'rocket'
  8. emitRatePerParticle: 96
  9. velocity: AngleDirection { angle: 90; magnitude: 100; angleVariation: 5 }
  10. lifeSpan: 200
  11. size: 16
  12. sizeVariation: 4
  13. endSize: 0
  14. }

向下模拟从火箭里面喷射出的烟。emitHeight与emitWidth指定了围绕跟随在烟雾粒子发射后的粒子。如果不指定这个值,跟随的粒子将会被拿掉,但是对于这个例子,我们想要提升显示效果,粒子流从一个接近于火箭尾部的中间点发射出。

如果你运行这个例子,你会发现一些火箭正常飞起,一些火箭却飞出场景。这不是我们想要的,我们需要在它们离开场景前让他们慢下来,这里可以使用摩擦控制器来设置一个最小阈值:

  1. Friction {
  2. groups: ['rocket']
  3. anchors.top: parent.top
  4. width: parent.width; height: 80
  5. system: particleSystem
  6. threshold: 5
  7. factor: 0.9
  8. }

在摩擦控制器中,你也需要定义哪个粒子组受控制器影响。当火箭经过从顶部向下80像素的区域时,所有的火箭将会以0.9的factor减慢(你可以试试100,你会发现它们立即停止了),直到它们的速度达到每秒5个像素。随着火箭粒子向下的加速度继续生效,火箭开始向地面下沉,直到它们的生命周期结束。

由于在空气中向上运动是非常困难的,并且非常不稳定,我们在火箭上升时模拟一些紊流:

  1. Turbulence {
  2. groups: ['rocket']
  3. anchors.bottom: parent.bottom
  4. width: parent.width; height: 160
  5. system: particleSystem
  6. strength: 25
  7. Tracer { color: 'green'; visible: root.tracer }
  8. }

当然,紊流控制器也需要定义它会影响哪些粒子组。紊流控制器的区域从底部向上160像素(直到摩擦控制器边界上),它们也可以相互覆盖。

当你运行程序时,你可以看到火箭开始上升,然后在摩擦控制器区域开始减速,向下的加速度仍然生效,火箭开始后退。下一步我们开始制作爆炸烟花。

粒子组(Particle Group) - 图2

注意

使用tracers跟踪区域可以显示场景中的不同区域。火箭粒子发射的红色区域,蓝色区域是紊流控制器区域,最后在绿色的摩擦控制器区域减速,并且再次下降是由于向下的加速度仍然生效。

爆炸烟花(Let there be fireworks)

让火箭变成美丽的烟花,我们需要添加一个粒子组来封装这个变化:

  1. ParticleGroup {
  2. name: 'explosion'
  3. system: particleSystem
  4. }

我们使用GroupGoal控制器来改变粒子组。这个组控制器被放置在屏幕中间垂直线附近,它将会影响’rocket’粒子组。使用groupGoal属性,我们设置目标组改变为我们之前定义的’explosion’组:

  1. GroupGoal {
  2. id: rocketChanger
  3. anchors.top: parent.top
  4. width: parent.width; height: 80
  5. system: particleSystem
  6. groups: ['rocket']
  7. goalState: 'explosion'
  8. jump: true
  9. Tracer { color: 'blue'; visible: root.tracer }
  10. }

jump属性定义了粒子组的变化是立即变化而不是在某个时间段后变化。

注意

在Qt5的alpha发布版中,粒子组的持续改变无法工作,有好的建议吗?

由于火箭粒子变为我们的爆炸粒子,当火箭粒子进入GroupGoal控制器区域时,我们需要在粒子组中添加一个烟花:

  1. // inside particle group
  2. TrailEmitter {
  3. id: explosionEmitter
  4. anchors.fill: parent
  5. group: 'sparkle'
  6. follow: 'rocket'
  7. lifeSpan: 750
  8. emitRatePerParticle: 200
  9. size: 32
  10. velocity: AngleDirection { angle: -90; angleVariation: 180; magnitude: 50 }
  11. }

爆炸释放粒子到’sparkle’粒子组。我们稍后会定义这个组的粒子画笔。轨迹发射器跟随火箭粒子每秒发射200个火箭爆炸粒子。粒子的方向向上,并改变180度。

由于向’sparkle’粒子组发射粒子,我们需要定义一个粒子画笔用于绘制这个组的粒子:

  1. ImageParticle {
  2. id: sparklePainter
  3. system: particleSystem
  4. groups: ['sparkle']
  5. color: 'red'
  6. colorVariation: 0.6
  7. source: "assets/star.png"
  8. alpha: 0.3
  9. }

闪烁的烟花是红色的星星,使用接近透明的颜色来渲染出发光的效果。

为了使烟花更加壮观,我们也需要添加给我们的粒子组添加第二个轨迹发射器,它向下发射锥形粒子:

  1. // inside particle group
  2. TrailEmitter {
  3. id: explosion2Emitter
  4. anchors.fill: parent
  5. group: 'sparkle'
  6. follow: 'rocket'
  7. lifeSpan: 250
  8. emitRatePerParticle: 100
  9. size: 32
  10. velocity: AngleDirection { angle: 90; angleVariation: 15; magnitude: 400 }
  11. }

其它的爆炸轨迹发射器与这个设置类似,就这样。

下面是最终结果。

粒子组(Particle Group) - 图3

下面是火箭烟花的所有代码。

  1. import QtQuick 2.0
  2. import QtQuick.Particles 2.0
  3. Rectangle {
  4. id: root
  5. width: 480; height: 240
  6. color: "#1F1F1F"
  7. property bool tracer: false
  8. ParticleSystem {
  9. id: particleSystem
  10. }
  11. ImageParticle {
  12. id: smokePainter
  13. system: particleSystem
  14. groups: ['smoke']
  15. source: "assets/particle.png"
  16. alpha: 0.3
  17. }
  18. ImageParticle {
  19. id: rocketPainter
  20. system: particleSystem
  21. groups: ['rocket']
  22. source: "assets/rocket.png"
  23. entryEffect: ImageParticle.Fade
  24. }
  25. Emitter {
  26. id: rocketEmitter
  27. anchors.bottom: parent.bottom
  28. width: parent.width; height: 40
  29. system: particleSystem
  30. group: 'rocket'
  31. emitRate: 2
  32. maximumEmitted: 8
  33. lifeSpan: 4800
  34. lifeSpanVariation: 400
  35. size: 32
  36. velocity: AngleDirection { angle: 270; magnitude: 150; magnitudeVariation: 10 }
  37. acceleration: AngleDirection { angle: 90; magnitude: 50 }
  38. Tracer { color: 'red'; visible: root.tracer }
  39. }
  40. TrailEmitter {
  41. id: smokeEmitter
  42. system: particleSystem
  43. group: 'smoke'
  44. follow: 'rocket'
  45. size: 16
  46. sizeVariation: 8
  47. emitRatePerParticle: 16
  48. velocity: AngleDirection { angle: 90; magnitude: 100; angleVariation: 15 }
  49. lifeSpan: 200
  50. Tracer { color: 'blue'; visible: root.tracer }
  51. }
  52. Friction {
  53. groups: ['rocket']
  54. anchors.top: parent.top
  55. width: parent.width; height: 80
  56. system: particleSystem
  57. threshold: 5
  58. factor: 0.9
  59. }
  60. Turbulence {
  61. groups: ['rocket']
  62. anchors.bottom: parent.bottom
  63. width: parent.width; height: 160
  64. system: particleSystem
  65. strength:25
  66. Tracer { color: 'green'; visible: root.tracer }
  67. }
  68. ImageParticle {
  69. id: sparklePainter
  70. system: particleSystem
  71. groups: ['sparkle']
  72. color: 'red'
  73. colorVariation: 0.6
  74. source: "assets/star.png"
  75. alpha: 0.3
  76. }
  77. GroupGoal {
  78. id: rocketChanger
  79. anchors.top: parent.top
  80. width: parent.width; height: 80
  81. system: particleSystem
  82. groups: ['rocket']
  83. goalState: 'explosion'
  84. jump: true
  85. Tracer { color: 'blue'; visible: root.tracer }
  86. }
  87. ParticleGroup {
  88. name: 'explosion'
  89. system: particleSystem
  90. TrailEmitter {
  91. id: explosionEmitter
  92. anchors.fill: parent
  93. group: 'sparkle'
  94. follow: 'rocket'
  95. lifeSpan: 750
  96. emitRatePerParticle: 200
  97. size: 32
  98. velocity: AngleDirection { angle: -90; angleVariation: 180; magnitude: 50 }
  99. }
  100. TrailEmitter {
  101. id: explosion2Emitter
  102. anchors.fill: parent
  103. group: 'sparkle'
  104. follow: 'rocket'
  105. lifeSpan: 250
  106. emitRatePerParticle: 100
  107. size: 32
  108. velocity: AngleDirection { angle: 90; angleVariation: 15; magnitude: 400 }
  109. }
  110. }
  111. }