上一章我们介绍了粒子的旋转。粒子的旋转作用于每一个粒子,除此之外,我们还可以设置粒子轨迹的方向。轨迹取决于一个指定的向量空间,该向量空间定义了粒子的速度和加速度,以及一个随机的方向。QML 提供了三个不同的向量空间,用于定义粒子的速度和加速度:

    • PointDirection:使用 x 和 y 值定义的方向
    • AngleDirection:使用角度定义的方向
    • TargetDirection:使用一个目标点坐标定义的方向

    粒子轨迹方向

    下面我们详细介绍这几种向量空间。

    首先,我们讨论AngleDirection。要使用AngleDirection,我们需要将其赋值给Emittervelocity属性:

    1. velocity: AngleDirection { }

    粒子发射角度使用angle属性定义。angle属性的取值范围是[0, 360),0 为水平向右。在我们例子中,我们希望粒子向右发射,因此angle设置为 0;粒子发射范围则是 +/-5 度:

    1. velocity: AngleDirection {
    2. angle: 0
    3. angleVariation: 15
    4. }

    现在我们设置好了方向,下面继续设置粒子速度。粒子的速度由magnitude属性决定。magnitude单位是像素/秒。如果我们的场景宽度是 640px,那么将magnitude设置为 100 或许还不错。这意味着,粒子平均需要耗费 6.4 秒时间从场景一端移动到另一端。为了让粒子速度更有趣,我们还要设置magnitudeVariation属性。这会为该速度设置一个可变的范围区间:

    1. velocity: AngleDirection {
    2. ...
    3. magnitude: 100
    4. magnitudeVariation: 50
    5. }

    下面是Emitter的完整代码。

    1. Emitter {
    2. id: emitter
    3. anchors.left: parent.left
    4. anchors.verticalCenter: parent.verticalCenter
    5. width: 1; height: 1
    6. system: particleSystem
    7. lifeSpan: 6400
    8. lifeSpanVariation: 400
    9. size: 32
    10. velocity: AngleDirection {
    11. angle: 0
    12. angleVariation: 15
    13. magnitude: 100
    14. magnitudeVariation: 50
    15. }
    16. }

    要运行上面的代码,只需要将上一章的示例程序中Emitter替换下即可。根据前面的描述,由于我们将magnitude设置为 100,因此粒子的平均生命周期为 6.4 秒。另外,我们将发射器的宽度和高度都设置为 1px,意味着所有粒子都会从相同位置发射,也就具有相同的轨迹起点。

    接下来我们来看加速度。加速度为每一个粒子增加一个加速度向量,该向量会随时间的流逝而改变速度。例如,我们创建一个类似星轨的轨迹,为了达到这一目的,我们将速度方向修改为 -45 度,并且移除速度变量区间:

    1. velocity: AngleDirection {
    2. angle: -45
    3. magnitude: 100
    4. }

    加速度方向为 90 度向下,数值为 25:

    1. acceleration: AngleDirection {
    2. angle: 90
    3. magnitude: 25
    4. }

    那么,这段代码的执行结果如下所示:

    带有加速度的粒子轨迹

    至于为什么这个加速度能够形成这样的轨迹,已经超出了本文的范围,这里不再赘述。

    下面介绍另外一种方向的定义。PointDirection使用 x 和 y 值导出向量空间。例如,你想要让粒子轨迹沿着 45 度角的方向,那么就需要将 x 和 y 设置成相同的值。在我们的例子中,我们希望粒子轨迹从左向右,成为一个 15 度的角。为了设置粒子轨迹,首先我们需要将PointDirection赋值给Emittervelocity属性:

    1. velocity: PointDirection { }

    为了指定粒子速度为 100px 每秒,我们将x的值设置为 100。15 度是 90 度的六分之一,因此我们将 y 的变化范围(yVariation)指定为 100/6:

    1. Emitter {
    2. id: emitter
    3. anchors.left: parent.left
    4. anchors.verticalCenter: parent.verticalCenter
    5. width: 1; height: 1
    6. system: particles
    7. lifeSpan: 6400
    8. lifeSpanVariation: 400
    9. size: 16
    10. velocity: PointDirection {
    11. x: 100
    12. y: 0
    13. xVariation: 0
    14. yVariation: 100/6
    15. }
    16. }

    代码运行结果如下:PointDirection

    最后是TargetDirectionTargetDirection使用相对于发射器或某个项目的 x 和 y 坐标指定一个目标点。如果指定的是一个项目,那么这个项目的中心会成为目标点。使用TargetDirection可以达到一些特殊的效果。例如下面的代码:

    1. velocity: TargetDirection {
    2. targetX: 100
    3. targetY: 0
    4. targetVariation: 100/6
    5. magnitude: 100
    6. }

    我们使用TargetDirection,将目标点的 x 坐标设置为 100,y 坐标为 0,因此这是一个水平轴上的点。targetVariation值为 100/6,这会形成一个大约 15 度的范围。代码运行结果如下:

    粒子系统:TargetDirection

    上一章提到,粒子由发射器发射。一旦粒子发射出来,发射器的任务就已经完成,不会再对粒子有任何影响。如果我们需要影响已经发射出的粒子,需要使用影响器(affector)。影响器有很多种类:

    • Age:改变粒子的生命周期,一般用于提前结束粒子的生命周期
    • Attractor:将粒子吸引到一个指定的点
    • Friction:按比例降低粒子的当前速度
    • Gravity:添加一个有一定角度的加速度
    • Turbulence:为粒子增加一个图像噪音
    • Wander:随机改变粒子轨迹
    • GroupGoal:改变粒子组的状态
    • SpriteGoal:改变精灵粒子的状态 Age可以改变粒子的生命周期,lifeLeft属性指定粒子还能存活还有多少时间。例如:
    1. import QtQuick 2.0
    2. import QtQuick.Particles 2.0
    3.  
    4. Rectangle {
    5. id: root;
    6. width: 480; height: 160
    7. color: "#1f1f1f"
    8.  
    9. ParticleSystem {
    10. id: particles
    11. }
    12.  
    13. Emitter {
    14. id: emitter
    15. anchors.left: parent.left
    16. anchors.verticalCenter: parent.verticalCenter
    17. width: 1; height: 1
    18. system: particles
    19. lifeSpan: 6400
    20. lifeSpanVariation: 400
    21. size: 16
    22. velocity: TargetDirection {
    23. targetX: 100
    24. targetY: 0
    25. targetVariation: 100/6
    26. magnitude: 100
    27. }
    28. }
    29.  
    30. Age {
    31. anchors.horizontalCenter: parent.horizontalCenter
    32. width: 140; height: 120
    33. system: particles
    34. advancePosition: true
    35. lifeLeft: 3200
    36. once: true
    37. Rectangle {
    38. anchors.fill: parent
    39. color: 'transparent'
    40. border.color: 'green'
    41. border.width: 2
    42. opacity: 0.8
    43. }
    44. }
    45.  
    46. ItemParticle {
    47. system: particles
    48. delegate: Rectangle {
    49. id: rect
    50. width: 10
    51. height: 10
    52. color: "red"
    53. radius: 10
    54. }
    55. }
    56. }

    Affector Age

    在这个例子中,我们利用影响器Age,将粒子的生命周期缩短到 3200 毫秒(lifeLeft指定)。当粒子进入影响器的范围时,其生命周期只剩下 3200 毫秒。将advancePosition设置为true,我们会看到一旦粒子的生命周期只剩下 3200 毫秒,粒子又会在其预期的位置重新出现。

    影响器Attractor将粒子吸引到使用pointXpointY定位的指定点,该点的坐标相对于Attractorstrength属性指定Attractor吸引的强度。

    1. Attractor {
    2. anchors.horizontalCenter: parent.horizontalCenter
    3. width: 160; height: 70
    4. system: particles
    5. pointX: 0
    6. pointY: 0
    7. strength: 1.0
    8. Rectangle {
    9. anchors.fill: parent
    10. color: 'transparent'
    11. border.color: 'green'
    12. border.width: 2
    13. opacity: 0.8
    14. }
    15. }

    在我们的例子中,粒子从左向右发射,Attractor在界面上半部分。只有进入到影响器范围内的粒子才会受到影响,这种轨迹的分离使我们能够清楚地看到影响器的作用。

    Affector Attractor

    影响器Friction会按照一定比例降低粒子的速度。例如:

    1. Friction {
    2. anchors.horizontalCenter: parent.horizontalCenter
    3. width: 240; height: 120
    4. system: particles
    5. factor : 0.8
    6. threshold: 25
    7. Rectangle {
    8. anchors.fill: parent
    9. color: 'transparent'
    10. border.color: 'green'
    11. border.width: 2
    12. opacity: 0.8
    13. }
    14. }

    上面的代码中,粒子会按照factor为 0.8 的比例降低粒子的速度,直到降低到 25 像素/秒(由threshold属性指定)。其运行结果如下:

    Affector Friction

    影响器Gravity为粒子添加一个加速度。例如:

    1. Gravity {
    2. width: 240; height: 90
    3. system: particles
    4. magnitude: 50
    5. angle: 90
    6. Rectangle {
    7. anchors.fill: parent
    8. color: 'transparent'
    9. border.color: 'green'
    10. border.width: 2
    11. opacity: 0.8
    12. }
    13. }

    在这个例子中,所有进入到影响器范围内的粒子都会添加一个加速度,角度是 90 度(向下),取值 50。代码运行结果是:

    Affector Gravity

    影响器Turbulence为每个粒子添加一个力向量。每个粒子所获得的随机力向量都是随机的,这由一个噪音图像决定,使用noiseSource属性可以自定义这个噪音图像。strength属性定义了作用到粒子上面的向量有多强。例如:

    1. Turbulence {
    2. anchors.horizontalCenter: parent.horizontalCenter
    3. width: 240; height: 120
    4. system: particles
    5. strength: 100
    6. Rectangle {
    7. anchors.fill: parent
    8. color: 'transparent'
    9. border.color: 'green'
    10. border.width: 2
    11. opacity: 0.8
    12. }
    13. }

    运行这段代码,观察粒子轨迹就会发现,一旦进入到影响器的范围内,粒子就像发疯一样到处乱穿,而不是原本按照从左向右的方向保持一个大致的轨迹。

    Affector Turbulence

    影响器Wander控制轨迹。affectedParameter属性指定Wander可以控制哪一个属性(速度、位置或者加速度等);pace属性指定每秒该属性变化的最大值;yVarianceyVariance指定粒子轨迹 x 和 y 坐标的浮动区间。例如:

    1. Wander {
    2. anchors.horizontalCenter: parent.horizontalCenter
    3. width: 240; height: 120
    4. system: particles
    5. affectedParameter: Wander.Position
    6. pace: 200
    7. yVariance: 240
    8. Rectangle {
    9. anchors.fill: parent
    10. color: 'transparent'
    11. border.color: 'green'
    12. border.width: 2
    13. opacity: 0.8
    14. }
    15. }

    在这个例子中,影响器作用于粒子轨迹的位置属性,轨迹位置会以每秒 200 次的频率,在 y 方向上随机震动。

    Affector Wander

    粒子是用于模拟很多自然现象,比如云、烟、火花等的强有力的工具。Qt 5 内置的粒子系统让我们可以轻松完成这些工作。同时,适当的粒子往往会成为用户界面上最吸引人的部分,尤其对于一些游戏应用,粒子特效更是不可或缺。应该说,游戏才是粒子的最佳应用环境。