# 粒子组

在本章的开头,表达过粒子是成组的,默认情况下是属于空字符组('')的。 使用 GroupGoal影响器可以改变粒子改变所在的组。 为了形象化提现这一点,创建一个小型烟花,火箭开始进入空中并在炸成壮观的烟花。

image

该示例分为2部分。 第一部分“发射时间”,是关于场景的设置和粒子组的介绍;第二部分是“放烟花”,重点介绍的是组的变化。

开始吧!

# 发射时间

首先,创建了一个典型的黑暗场景:

import QtQuick
import QtQuick.Particles

Rectangle {
    id: root
    width: 480; height: 240
    color: "#1F1F1F"
    property bool tracer: false
}

这个tracer属性将用于打开和关闭跟踪器场景。 接下来是声明粒子系统:

ParticleSystem {
    id: particleSystem
}

还有两个图像粒子(一个用于火箭,一个用于排放废气):
译者注释:废气是火箭升空时候尾部排放的废气,有时候由于展示的屏幕的分辨率不同,看到尾气很不明显,甚至有时候看不到;或者仅在火箭消失时候能短暂看到。

ImageParticle {
    id: smokePainter
    system: particleSystem
    groups: ['smoke']
    source: "assets/particle.png"
    alpha: 0.3
    entryEffect: ImageParticle.None
}

ImageParticle {
    id: rocketPainter
    system: particleSystem
    groups: ['rocket']
    source: "assets/rocket.png"
    entryEffect: ImageParticle.None
}

可以在上面看到,它们使用groups属性来声明粒子属于哪个组。 只需声明一个名称就足够了,Qt Quick将根据名称创建一个隐式的组。

现在是时候向空中发射一些火箭了。 为此,在场景底部创建了一个发射器,并将速度设置为向上方向。 为了模拟一些重力,设置类向下的加速度:

Emitter {
    id: rocketEmitter
    anchors.bottom: parent.bottom
    width: parent.width; height: 40
    system: particleSystem
    group: 'rocket'
    emitRate: 2
    maximumEmitted: 4
    lifeSpan: 4800
    lifeSpanVariation: 400
    size: 32
    velocity: AngleDirection { angle: 270; magnitude: 150; magnitudeVariation: 10 }
    acceleration: AngleDirection { angle: 90; magnitude: 50 }
    Tracer { color: 'red'; visible: root.tracer }
}

此发射器属于*'rocket'*组,与火箭粒子绘制器属于相同组。 通过组名,将它们绑定在一起。 发射器将粒子发射到'rocket'组中,火箭粒子绘制器将会绘制它们。

对于废气部分,使用尾迹发射器,它跟随火箭。 废气声明了一个名为'smoke'的组,并跟随来自'rocket'组的粒子:

TrailEmitter {
    id: smokeEmitter
    system: particleSystem
    emitHeight: 1
    emitWidth: 4
    group: 'smoke'
    follow: 'rocket'
    emitRatePerParticle: 96
    velocity: AngleDirection { angle: 90; magnitude: 100; angleVariation: 5 }
    lifeSpan: 200
    size: 16
    sizeVariation: 4
    endSize: 0
}

向下的烟雾用来模拟从火箭中喷出来的烟雾。 emitHeightemitWidth指定了火箭粒子的周围区域,此区域用于发射出烟雾粒子。 如果没有指定,那么烟雾粒子跟随火箭粒子发射出来,但是对于此示例,想要添加烟雾粒子是来自火箭末端附近的中心点的效果。

如果现在运行这个例子,会看到火箭飞起来,有些甚至飞出了场景。 由于这并不是真正想要的效果,需要在它们离开屏幕之前放慢它们的速度。 这里可以使用摩擦影响器将粒子减慢到最小阈值:

Friction {
    groups: ['rocket']
    anchors.top: parent.top
    width: parent.width; height: 80
    system: particleSystem
    threshold: 5
    factor: 0.9
}

在摩擦影响器中,还需要声明它将影响哪些粒子组。 摩擦会减慢所有火箭的速度,其作用区域是从屏幕顶部到向下80像素,降速因子为0.9,直到它们降到每秒5像素的速度;尝试向下高度为100像素,会看到火箭们几乎立即停止。 由于粒子仍有向下的加速度,火箭将在达到其寿命结束时开始向地面下沉。

由于在空中爬升是一项艰难的工作,且情况非常不稳定,因此想在火箭爬升时模拟一些湍流:

Turbulence {
    groups: ['rocket']
    anchors.bottom: parent.bottom
    width: parent.width; height: 160
    system: particleSystem
    strength: 25
    Tracer { color: 'green'; visible: root.tracer }
}

此外,湍流需要声明它将影响哪些组。 湍流影响区域是距离底部160像素的位置向上延伸,直到它到达摩擦的边界。 当然,它们也可以重叠。

当运行示例的时候,将看到火箭正在向上爬升,然后由于摩擦而减速,并由于仍旧施加的向下加速度而落回地面。 接下来就是要开始放烟花了。

image

提示

该图像显示了带有跟踪器的场景,示踪器可以展示场景中不同的区域。在红色区域发射火箭粒子,然后在蓝色区域受到湍流的影响,最后它们在绿色区域中受摩擦影响减慢并开始下降。下降是因为稳定地施加了向下的加速度。

# 放烟花

为了能将火箭变成美丽的烟花,需要添加一个ParticleGroup来封装这些变化:

ParticleGroup {
    name: 'explosion'
    system: particleSystem
}

使用GroupGoal影响器将受影响的粒子更改为粒子组。 此组目标影响器放置在屏幕垂直中心附近,它将影响'rocket'组。 使用goalState属性,将更改的目标组设置为'explosion',即之前定义的粒子组:

GroupGoal {
    id: rocketChanger
    anchors.top: parent.top
    width: parent.width; height: 80
    system: particleSystem
    groups: ['rocket']
    goalState: 'explosion'
    jump: true
    Tracer { color: 'blue'; visible: root.tracer }
}

jump属性说明组的变化应立即发生,而不是等待一段的特定时间后发生。

提示

在Qt 6版本中,可能无法使用组变化的duration(持续时间)。 有其他的主意吗?

当火箭粒子进入组目标区域时,'rocket'(火箭)组变化成'explosion'(爆炸)粒子组,因此需要在粒子组内添加烟花:

// inside particle group
// 在粒子组内
TrailEmitter {
    id: explosionEmitter
    anchors.fill: parent
    group: 'sparkle'
    follow: 'rocket'
    lifeSpan: 750
    emitRatePerParticle: 200
    size: 32
    velocity: AngleDirection { angle: -90; angleVariation: 180; magnitude: 50 }
}

爆炸将粒子发射到'sparkle'(火花)组中,将为这个组定义一个粒子绘制器。 使用的尾迹发射器跟随火箭粒子并为每个火箭发射200个粒子,粒子方向向上并设定方向变化误差为180°。

当粒子被发射到'sparkle'(火花)组中时,还需要为粒子定义一个粒子绘制器:

ImageParticle {
    id: sparklePainter
    system: particleSystem
    groups: ['sparkle']
    color: 'red'
    colorVariation: 0.6
    source: "assets/star.png"
    alpha: 0.3
}

烟花应是红色的小星星,颜色几乎是透明的,以产生一些闪光效果。

为了让烟花更加壮观,还在粒子组中添加了第二个尾迹发射器,它将向下发射一些粒子,这些粒子处于一个狭窄的锥形中:

// inside particle group
TrailEmitter {
    id: explosion2Emitter
    anchors.fill: parent
    group: 'sparkle'
    follow: 'rocket'
    lifeSpan: 250
    emitRatePerParticle: 100
    size: 32
    velocity: AngleDirection { angle: 90; angleVariation: 15; magnitude: 400 }
}

否则,设置类似于其他爆炸尾迹发射器。 就这样。

这就是最终效果。

image

下面是火箭烟花的完整源码:

import QtQuick
import QtQuick.Particles

Rectangle {
    id: root
    width: 480; height: 240
    color: "#1F1F1F"
    property bool tracer: false

    ParticleSystem {
        id: particleSystem
    }

    ImageParticle {
        id: smokePainter
        system: particleSystem
        groups: ['smoke']
        source: "assets/particle.png"
        alpha: 0.3
    }

    ImageParticle {
        id: rocketPainter
        system: particleSystem
        groups: ['rocket']
        source: "assets/rocket.png"
        entryEffect: ImageParticle.Fade
    }

    Emitter {
        id: rocketEmitter
        anchors.bottom: parent.bottom
        width: parent.width; height: 40
        system: particleSystem
        group: 'rocket'
        emitRate: 2
        maximumEmitted: 8
        lifeSpan: 4800
        lifeSpanVariation: 400
        size: 128
        velocity: AngleDirection { angle: 270; magnitude: 150; magnitudeVariation: 10 }
        acceleration: AngleDirection { angle: 90; magnitude: 50 }
        Tracer { color: 'red'; visible: root.tracer }
    }

    TrailEmitter {
        id: smokeEmitter
        system: particleSystem
        group: 'smoke'
        follow: 'rocket'
        size: 16
        sizeVariation: 8
        emitRatePerParticle: 16
        velocity: AngleDirection { angle: 90; magnitude: 100; angleVariation: 15 }
        lifeSpan: 200
        Tracer { color: 'blue'; visible: root.tracer }
    }

    Friction {
        groups: ['rocket']
        anchors.top: parent.top
        width: parent.width; height: 80
        system: particleSystem
        threshold: 5
        factor: 0.9

    }

    Turbulence {
        groups: ['rocket']
        anchors.bottom: parent.bottom
        width: parent.width; height: 160
        system: particleSystem
        strength:25
        Tracer { color: 'green'; visible: root.tracer }
    }


    ImageParticle {
        id: sparklePainter
        system: particleSystem
        groups: ['sparkle']
        color: 'red'
        colorVariation: 0.6
        source: "assets/star.png"
        alpha: 0.3
    }

    GroupGoal {
        id: rocketChanger
        anchors.top: parent.top
        width: parent.width; height: 80
        system: particleSystem
        groups: ['rocket']
        goalState: 'explosion'
        jump: true
        Tracer { color: 'blue'; visible: root.tracer }
    }

    ParticleGroup {
        name: 'explosion'
        system: particleSystem

        TrailEmitter {
            id: explosionEmitter
            anchors.fill: parent
            group: 'sparkle'
            follow: 'rocket'
            lifeSpan: 750
            emitRatePerParticle: 200
            size: 32
            velocity: AngleDirection { angle: -90; angleVariation: 180; magnitude: 50 }
        }

        TrailEmitter {
            id: explosion2Emitter
            anchors.fill: parent
            group: 'sparkle'
            follow: 'rocket'
            lifeSpan: 250
            emitRatePerParticle: 100
            size: 32
            velocity: AngleDirection { angle: 90; angleVariation: 15; magnitude: 400 }
        }
    }
}
最后更新: 1/1/2022, 10:21:51 AM