# 粒子组
在本章的开头,表达过粒子是成组的,默认情况下是属于空字符组('')的。 使用 GroupGoal
影响器可以改变粒子改变所在的组。 为了形象化提现这一点,创建一个小型烟花,火箭开始进入空中并在炸成壮观的烟花。
该示例分为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
}
向下的烟雾用来模拟从火箭中喷出来的烟雾。 emitHeight和emitWidth指定了火箭粒子的周围区域,此区域用于发射出烟雾粒子。 如果没有指定,那么烟雾粒子跟随火箭粒子发射出来,但是对于此示例,想要添加烟雾粒子是来自火箭末端附近的中心点的效果。
如果现在运行这个例子,会看到火箭飞起来,有些甚至飞出了场景。 由于这并不是真正想要的效果,需要在它们离开屏幕之前放慢它们的速度。 这里可以使用摩擦影响器将粒子减慢到最小阈值:
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像素的位置向上延伸,直到它到达摩擦的边界。 当然,它们也可以重叠。
当运行示例的时候,将看到火箭正在向上爬升,然后由于摩擦而减速,并由于仍旧施加的向下加速度而落回地面。 接下来就是要开始放烟花了。
提示
该图像显示了带有跟踪器的场景,示踪器可以展示场景中不同的区域。在红色区域发射火箭粒子,然后在蓝色区域受到湍流的影响,最后它们在绿色区域中受摩擦影响减慢并开始下降。下降是因为稳定地施加了向下的加速度。
# 放烟花
为了能将火箭变成美丽的烟花,需要添加一个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 }
}
否则,设置类似于其他爆炸尾迹发射器。 就这样。
这就是最终效果。
下面是火箭烟花的完整源码:
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 }
}
}
}