Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Toggle main menu visibility
Loading...
Searching...
No Matches
qquickparticleaffector.cpp
Go to the documentation of this file.
1
// Copyright (C) 2016 The Qt Company Ltd.
2
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4
#
include
<
QtCore
/
qtconfigmacros
.
h
>
5
#
undef
QT_NO_FOREACH
// this file contains unported legacy Q_FOREACH uses
6
7
#
include
"qquickparticleaffector_p.h"
8
#
include
<
QDebug
>
9
#
include
<
private
/
qqmlglobal_p
.
h
>
10
QT_BEGIN_NAMESPACE
11
12
/*!
13
\qmltype ParticleAffector
14
//! \nativetype QQuickParticleAffector
15
\inqmlmodule QtQuick.Particles
16
\brief Applies alterations to the attributes of logical particles at any
17
point in their lifetime.
18
\ingroup qtquick-particles
19
20
The base ParticleAffector does not alter any attributes, but can be used to emit a signal
21
when a particle meets certain conditions.
22
23
If an affector has a defined size, then it will only affect particles within its size and
24
position on screen.
25
26
Affectors have different performance characteristics to the other particle system elements. In
27
particular, they have some simplifications to try to maintain a simulation at real-time or faster.
28
When running a system with Affectors, irregular frame timings that grow too large ( > one second per
29
frame) will cause the Affectors to try and cut corners with a faster but less accurate simulation.
30
If the system has multiple affectors the order in which they are applied is not guaranteed, and when
31
simulating larger time shifts they will simulate the whole shift each, which can lead to different
32
results compared to smaller time shifts.
33
34
Accurate simulation for large numbers of particles (hundreds) with multiple affectors may be
35
possible on some hardware, but on less capable hardware you should expect small irregularties in the
36
simulation as simulates with worse granularity.
37
*/
38
/*!
39
\qmlproperty ParticleSystem QtQuick.Particles::ParticleAffector::system
40
This is the system which will be affected by the element.
41
If the ParticleAffector is a direct child of a ParticleSystem, it will automatically be associated with
42
it.
43
*/
44
/*!
45
\qmlproperty list<string> QtQuick.Particles::ParticleAffector::groups
46
Which logical particle groups will be affected.
47
48
If empty, it will affect all particles.
49
*/
50
/*!
51
\qmlproperty list<string> QtQuick.Particles::ParticleAffector::whenCollidingWith
52
If any logical particle groups are specified here, then the particle affector
53
will only be triggered if the particle being examined intersects with
54
a particle of one of these groups.
55
56
This is different from the groups property. The groups property selects which
57
particles might be examined, and if they meet other criteria (including being
58
within the bounds of the ParticleAffector, modified by shape) then they will be tested
59
again to see if they intersect with a particles from one of the particle groups
60
in whenCollidingWith.
61
62
By default, no groups are specified.
63
*/
64
/*!
65
\qmlproperty bool QtQuick.Particles::ParticleAffector::enabled
66
If enabled is set to false, this affector will not affect any particles.
67
68
Usually this is used to conditionally turn an affector on or off.
69
70
Default value is true.
71
*/
72
/*!
73
\qmlproperty bool QtQuick.Particles::ParticleAffector::once
74
If once is set to true, this affector will only affect each particle
75
once in their lifetimes. If the affector normally simulates a continuous
76
effect over time, then it will simulate the effect of one second of time
77
the one instant it affects the particle.
78
79
Default value is false.
80
*/
81
/*!
82
\qmlproperty Shape QtQuick.Particles::ParticleAffector::shape
83
If a size has been defined, the shape property can be used to affect a
84
non-rectangular area.
85
*/
86
/*!
87
\qmlsignal QtQuick.Particles::ParticleAffector::affected(real x, real y)
88
89
This signal is emitted when a particle is selected to be affected. It will not be emitted
90
if a particle is considered by the ParticleAffector but not actually altered in any way.
91
92
In the special case where an ParticleAffector has no possible effect (e.g. ParticleAffector {}), this signal
93
will be emitted for all particles being considered if you connect to it. This allows you to
94
execute arbitrary code in response to particles (use the ParticleAffector::onAffectParticles
95
signal handler if you want to execute code which affects the particles
96
themselves). As this executes JavaScript code per particle, it is not recommended to use this
97
signal with a high-volume particle system.
98
99
(\a {x}, \a {y}) is the particle's current position.
100
*/
101
QQuickParticleAffector::QQuickParticleAffector(QQuickItem *parent) :
102
QQuickItem(parent), m_needsReset(
false
), m_ignoresTime(
false
), m_onceOff(
false
), m_enabled(
true
)
103
, m_system(
nullptr
), m_updateIntSet(
false
), m_shape(
new
QQuickParticleExtruder(
this
))
104
{
105
}
106
107
bool
QQuickParticleAffector::isAffectedConnected()
108
{
109
IS_SIGNAL_CONNECTED(
this
, QQuickParticleAffector, affected, (qreal,qreal));
110
}
111
112
113
void
QQuickParticleAffector::componentComplete()
114
{
115
if
(!m_system && qobject_cast<QQuickParticleSystem*>(parentItem()))
116
setSystem(qobject_cast<QQuickParticleSystem*>(parentItem()));
117
QQuickItem::componentComplete();
118
}
119
120
bool
QQuickParticleAffector::activeGroup(
int
g) {
121
if
(!m_system)
122
return
false
;
123
124
if
(m_updateIntSet){
//This can occur before group ids are properly assigned, but that resets the flag
125
m_groupIds.clear();
126
foreach (
const
QString &p, m_groups)
127
m_groupIds << m_system->groupIds[p];
128
m_updateIntSet =
false
;
129
}
130
return
m_groupIds.isEmpty() || m_groupIds.contains(g);
131
}
132
133
bool
QQuickParticleAffector::shouldAffect(QQuickParticleData* d)
134
{
135
if
(!d)
136
return
false
;
137
if
(!m_system)
138
return
false
;
139
140
if
(activeGroup(d->groupId)){
141
if
((m_onceOff && m_onceOffed.contains(std::make_pair(d->groupId, d->index)))
142
|| !d->stillAlive(m_system))
143
return
false
;
144
//Need to have previous location for affected anyways
145
if
(width() == 0 || height() == 0
146
|| m_shape->contains(QRectF(m_offset.x(), m_offset.y(), width(), height()), QPointF(d->curX(m_system), d->curY(m_system)))){
147
if
(m_whenCollidingWith.isEmpty() || isColliding(d)){
148
return
true
;
149
}
150
}
151
}
152
return
false
;
153
154
}
155
156
void
QQuickParticleAffector::postAffect(QQuickParticleData* d)
157
{
158
if
(!m_system)
159
return
;
160
161
m_system->needsReset << d;
162
if
(m_onceOff)
163
m_onceOffed << std::make_pair(d->groupId, d->index);
164
if
(isAffectedConnected())
165
emit affected(d->curX(m_system), d->curY(m_system));
166
}
167
168
const
qreal QQuickParticleAffector::simulationDelta = 0.020;
169
const
qreal QQuickParticleAffector::simulationCutoff = 1.000;
//If this goes above 1.0, then m_once behaviour needs special codepath
170
171
void
QQuickParticleAffector::affectSystem(qreal dt)
172
{
173
if
(!m_enabled)
174
return
;
175
if
(!m_system)
176
return
;
177
178
//If not reimplemented, calls affectParticle per particle
179
//But only on particles in targeted system/area
180
updateOffsets();
//### Needed if an ancestor is transformed.
181
if
(m_onceOff)
182
dt = 1.0;
183
for
(QQuickParticleGroupData* gd : std::as_const(m_system->groupData)) {
184
if
(activeGroup(gd->index)) {
185
for
(QQuickParticleData* d : std::as_const(gd->data)) {
186
if
(shouldAffect(d)) {
187
bool
affected =
false
;
188
qreal myDt = dt;
189
if
(!m_ignoresTime && myDt < simulationCutoff) {
190
int
realTime = m_system->timeInt;
191
m_system->timeInt -= myDt * 1000.0;
192
while
(myDt > simulationDelta) {
193
m_system->timeInt += simulationDelta * 1000.0;
194
if
(d->alive(m_system))
//Only affect during the parts it was alive for
195
affected = affectParticle(d, simulationDelta) || affected;
196
myDt -= simulationDelta;
197
}
198
m_system->timeInt = realTime;
199
}
200
if
(myDt > 0.0)
201
affected = affectParticle(d, myDt) || affected;
202
if
(affected)
203
postAffect(d);
204
}
205
}
206
}
207
}
208
}
209
210
bool
QQuickParticleAffector::affectParticle(QQuickParticleData *, qreal )
211
{
212
return
true
;
213
}
214
215
void
QQuickParticleAffector::reset(QQuickParticleData* pd)
216
{
//TODO: This, among other ones, should be restructured so they don't all need to remember to call the superclass
217
if
(m_onceOff)
218
if
(activeGroup(pd->groupId))
219
m_onceOffed.remove(std::make_pair(pd->groupId, pd->index));
220
}
221
222
void
QQuickParticleAffector::updateOffsets()
223
{
224
if
(m_system)
225
m_offset = m_system->mapFromItem(
this
, QPointF(0, 0));
226
}
227
228
bool
QQuickParticleAffector::isColliding(QQuickParticleData *d)
const
229
{
230
if
(!m_system)
231
return
false
;
232
233
qreal myCurX = d->curX(m_system);
234
qreal myCurY = d->curY(m_system);
235
qreal myCurSize = d->curSize(m_system) / 2;
236
foreach (
const
QString &group, m_whenCollidingWith){
237
foreach (QQuickParticleData* other, m_system->groupData[m_system->groupIds[group]]->data){
238
if
(!other->stillAlive(m_system))
239
continue
;
240
qreal otherCurX = other->curX(m_system);
241
qreal otherCurY = other->curY(m_system);
242
qreal otherCurSize = other->curSize(m_system) / 2;
243
if
((myCurX + myCurSize > otherCurX - otherCurSize
244
&& myCurX - myCurSize < otherCurX + otherCurSize)
245
&& (myCurY + myCurSize > otherCurY - otherCurSize
246
&& myCurY - myCurSize < otherCurY + otherCurSize))
247
return
true
;
248
}
249
}
250
return
false
;
251
}
252
253
QT_END_NAMESPACE
254
255
#
include
"moc_qquickparticleaffector_p.cpp"
QT_BEGIN_NAMESPACE
Combined button and popup list for selecting options.
Definition
qsequentialanimationgroup.cpp:47
qtdeclarative
src
particles
qquickparticleaffector.cpp
Generated on
for Qt by
1.18.0