drag.axis: Drag.XandYAxis
drag.target: ship
}
- Emitter {
- group: "engine"
- system: particles
- emitRate: 200
- lifeSpan: 1000
- size: 10
- endSize: 4
- sizeVariation: 4
- speed: PointDirection { x: -128; xVariation: 32 }
- height: parent.height
- width: 20
- }
- Emitter {
- group: "shot"
- system: particles
- emitRate: 32
- lifeSpan: 2000
- enabled: spacePressed
- size: 40
- speed: PointDirection { x: 256; }
- x: parent.width
- y: parent.height/2
- }
+ }
+ Emitter {
+ group: "engine"
+ system: particles
+ emitRate: 200
+ lifeSpan: 1000
+ size: 10
+ endSize: 4
+ sizeVariation: 4
+ speed: PointDirection { x: -128; xVariation: 32 }
+ height: ship.height
+ y: ship.y
+ x: ship.x
+ width: 20
+ }
+ Emitter {
+ group: "shot"
+ system: particles
+ emitRate: 32
+ lifeSpan: 2000
+ enabled: spacePressed
+ size: 40
+ speed: PointDirection { x: 256; }
+ x: ship.x + ship.width
+ y: ship.y + ship.height/2
}
Text {
$$PWD/qsgtargetdirection_p.h \
$$PWD/qsgturbulence_p.h \
$$PWD/qsgwander_p.h \
- $$PWD/qsgtargetaffector_p.h \
$$PWD/qsgcumulativedirection_p.h \
$$PWD/qsgv8particledata_p.h \
$$PWD/qsgrectangleextruder_p.h \
$$PWD/qsgtargetdirection.cpp \
$$PWD/qsgturbulence.cpp \
$$PWD/qsgwander.cpp \
- $$PWD/qsgtargetaffector.cpp \
$$PWD/qsgcumulativedirection.cpp \
$$PWD/qsgv8particledata.cpp \
$$PWD/qsgrectangleextruder.cpp \
if (shouldAffect(d))
toAffect << d;
+ if (toAffect.isEmpty())
+ return;
+
v8::HandleScope handle_scope;
v8::Context::Scope scope(QDeclarativeEnginePrivate::getV8Engine(qmlEngine(this))->context());
v8::Handle<v8::Array> array = v8::Array::New(toAffect.size());
for (int i=0; i<toAffect.size(); i++)
array->Set(i, toAffect[i]->v8Value().toHandle());
- emit affectParticles(QDeclarativeV8Handle::fromHandle(array), dt);
+ if (dt >= simulationCutoff || dt <= simulationDelta) {
+ emit affectParticles(QDeclarativeV8Handle::fromHandle(array), dt);
+ } else {
+ int realTime = m_system->timeInt;
+ m_system->timeInt -= dt * 1000.0;
+ while (dt > simulationDelta) {
+ m_system->timeInt += simulationDelta * 1000.0;
+ dt -= simulationDelta;
+ emit affectParticles(QDeclarativeV8Handle::fromHandle(array), simulationDelta);
+ }
+ m_system->timeInt = realTime;
+ if (dt > 0.0) {
+ emit affectParticles(QDeclarativeV8Handle::fromHandle(array), dt);
+ }
+ }
foreach (QSGParticleData* d, toAffect)
if (d->update == 1.0)
QSGGroupGoalAffector::QSGGroupGoalAffector(QQuickItem *parent) :
QSGParticleAffector(parent), m_jump(false)
{
+ m_ignoresTime = true;
}
void QSGGroupGoalAffector::setGoalState(QString arg)
when a particle meets certain conditions.
If an affector has a defined size, then it will only affect particles within its size and position on screen.
+
+ Affectors have different performance characteristics to the other particle system elements. In particular,
+ they have some simplifications to try to maintain a simulation at real-time or faster. When running a system
+ with Affectors, irregular frame timings that grow too large ( > one second per frame) will cause the Affectors
+ to try and cut corners with a faster but less accurate simulation. If the system has multiple affectors the order
+ in which they are applied is not guaranteed, and when simulating larger time shifts they will simulate the whole
+ shift each, which can lead to different results compared to smaller time shifts.
+
+ Accurate simulation for large numbers of particles (hundreds) with multiple affectors may be possible on some hardware,
+ but on less capable hardware you should expect small irregularties in the simulation as simulates with worse granularity.
*/
/*!
\qmlproperty ParticleSystem QtQuick.Particles2::Affector::system
x,y is the particles current position.
*/
QSGParticleAffector::QSGParticleAffector(QQuickItem *parent) :
- QQuickItem(parent), m_needsReset(false), m_system(0), m_enabled(true)
+ QQuickItem(parent), m_needsReset(false), m_ignoresTime(false), m_system(0), m_enabled(true)
, m_updateIntSet(false), m_shape(new QSGParticleExtruder(this))
{
}
emit affected(d->curX(), d->curY());
}
+const qreal QSGParticleAffector::simulationDelta = 0.020;
+const qreal QSGParticleAffector::simulationCutoff = 1.000;
+
void QSGParticleAffector::affectSystem(qreal dt)
{
if (!m_enabled)
return;
- //If not reimplemented, calls affect particle per particle
+ //If not reimplemented, calls affectParticle per particle
//But only on particles in targeted system/area
updateOffsets();//### Needed if an ancestor is transformed.
- foreach (QSGParticleGroupData* gd, m_system->groupData)
- if (activeGroup(m_system->groupData.key(gd)))
- foreach (QSGParticleData* d, gd->data)
- if (shouldAffect(d))
- if (affectParticle(d, dt))
+ foreach (QSGParticleGroupData* gd, m_system->groupData) {
+ if (activeGroup(m_system->groupData.key(gd))) {
+ foreach (QSGParticleData* d, gd->data) {
+ if (shouldAffect(d)) {
+ bool affected = false;
+ qreal myDt = dt;
+ if (!m_ignoresTime && myDt < simulationCutoff) {
+ int realTime = m_system->timeInt;
+ m_system->timeInt -= myDt * 1000.0;
+ while (myDt > simulationDelta) {
+ m_system->timeInt += simulationDelta * 1000.0;
+ affected = affectParticle(d, simulationDelta) || affected;
+ myDt -= simulationDelta;
+ }
+ m_system->timeInt = realTime;
+ }
+ if (myDt > 0.0)
+ affected = affectParticle(d, myDt) || affected;
+ if (affected)
postAffect(d);
+ }
+ }
+ }
+ }
}
bool QSGParticleAffector::affectParticle(QSGParticleData *, qreal )
friend class QSGParticleSystem;
virtual bool affectParticle(QSGParticleData *d, qreal dt);
bool m_needsReset;//### What is this really saving?
+ bool m_ignoresTime;
QSGParticleSystem* m_system;
QStringList m_groups;
bool activeGroup(int g);
virtual void componentComplete();
QPointF m_offset;
bool isAffectedConnected();
+ static const qreal simulationDelta;
+ static const qreal simulationCutoff;
private:
QSet<int> m_groupIds;
QSet<QPair<int, int> > m_onceOffed;
#include "qsgtargetdirection_p.h"
#include "qsgturbulence_p.h"
#include "qsgwander_p.h"
-#include "qsgtargetaffector_p.h"
#include "qsgcumulativedirection_p.h"
#include "qsgcustomaffector_p.h"
#include "qsgrectangleextruder_p.h"
qmlRegisterType<QSGSpriteGoalAffector>(uri, 2, 0, "SpriteGoal");
qmlRegisterType<QSGGroupGoalAffector>(uri, 2, 0, "GroupGoal");
qmlRegisterType<QSGTurbulenceAffector>(uri, 2, 0 , "Turbulence");
- qmlRegisterType<QSGTargetAffector>(uri, 2, 0 , "Target");
qmlRegisterType<QSGMoveAffector>(uri, 2, 0, "Move");
//Exposed just for completeness
m_systemStates(false),
m_notUsingEngine(false)
{
+ m_ignoresTime = true;
}
void QSGSpriteGoalAffector::updateStateIndex(QQuickStochasticEngine* e)
+++ /dev/null
-/****************************************************************************
-**
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the Declarative module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** GNU Lesser General Public License Usage
-** This file may be used under the terms of the GNU Lesser General Public
-** License version 2.1 as published by the Free Software Foundation and
-** appearing in the file LICENSE.LGPL included in the packaging of this
-** file. Please review the following information to ensure the GNU Lesser
-** General Public License version 2.1 requirements will be met:
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU General
-** Public License version 3.0 as published by the Free Software Foundation
-** and appearing in the file LICENSE.GPL included in the packaging of this
-** file. Please review the following information to ensure the GNU General
-** Public License version 3.0 requirements will be met:
-** http://www.gnu.org/copyleft/gpl.html.
-**
-** Other Usage
-** Alternatively, this file may be used in accordance with the terms and
-** conditions contained in a signed written agreement between you and Nokia.
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qsgtargetaffector_p.h"
-#include <QDebug>
-
-QSGTargetAffector::QSGTargetAffector(QQuickItem *parent) :
- QSGParticleAffector(parent), m_targetX(0), m_targetY(0),
- m_targetWidth(0), m_targetHeight(0), m_defaultShape(new QSGParticleExtruder(this)),
- m_targetShape(m_defaultShape), m_targetTime(-1)
-{
- m_needsReset = true;
-}
-
-void QSGTargetAffector::reset(QSGParticleData* d)
-{
- QSGParticleAffector::reset(d);
- m_targets[qMakePair<int,int>(d->group, d->index)] = m_targetShape->extrude(QRectF(m_targetX, m_targetY, m_targetWidth, m_targetHeight));
-}
-
-bool QSGTargetAffector::affectParticle(QSGParticleData *d, qreal dt)
-{
- Q_UNUSED(dt);
- QPointF target = m_targets[qMakePair<int,int>(d->group, d->index)];
- if (target.isNull())
- return false;
- qreal tt = m_targetTime==-1?d->lifeSpan:(m_targetTime / 1000.0);
- qreal t = tt - (d->lifeSpan - d->lifeLeft());
- if (t <= 0)
- return false;
- qreal tx = d->x + d->vx * tt + 0.5 * d->ax * tt * tt;
- qreal ty = d->y + d->vy * tt + 0.5 * d->ay * tt * tt;
-
- if (QPointF(tx,ty) == target)
- return false;
-
- qreal vX = (target.x() - d->x) / tt;
- qreal vY = (target.y() - d->y) / tt;
-
- qreal w = 1 - (t / tt) + 0.05;
- w = qMin<qreal>(w, 1.0);
- qreal wvX = vX * w + d->vx * (1 - w);
- qreal wvY = vY * w + d->vy * (1 - w);
- //Screws with the acceleration so that the given start pos with the chosen weighted velocity will still end at the target coordinates
- qreal ax = (2*(target.x() - d->x - wvX*tt)) / (tt*tt);
- qreal ay = (2*(target.y() - d->y - wvY*tt)) / (tt*tt);
-
- d->vx = wvX;
- d->vy = wvY;
- d->ax = ax;
- d->ay = ay;
-
- return true;
-}
+++ /dev/null
-/****************************************************************************
-**
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the Declarative module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** GNU Lesser General Public License Usage
-** This file may be used under the terms of the GNU Lesser General Public
-** License version 2.1 as published by the Free Software Foundation and
-** appearing in the file LICENSE.LGPL included in the packaging of this
-** file. Please review the following information to ensure the GNU Lesser
-** General Public License version 2.1 requirements will be met:
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU General
-** Public License version 3.0 as published by the Free Software Foundation
-** and appearing in the file LICENSE.GPL included in the packaging of this
-** file. Please review the following information to ensure the GNU General
-** Public License version 3.0 requirements will be met:
-** http://www.gnu.org/copyleft/gpl.html.
-**
-** Other Usage
-** Alternatively, this file may be used in accordance with the terms and
-** conditions contained in a signed written agreement between you and Nokia.
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QSGTARGETAFFECTOR_H
-#define QSGTARGETAFFECTOR_H
-
-#include "qsgparticleaffector_p.h"
-
-class QSGTargetAffector : public QSGParticleAffector
-{
- Q_OBJECT
- Q_PROPERTY(int targetX READ targetX WRITE setTargetX NOTIFY targetXChanged)
- Q_PROPERTY(int targetY READ targetY WRITE setTargetY NOTIFY targetYChanged)
- Q_PROPERTY(int targetWidth READ targetWidth WRITE setTargetWidth NOTIFY targetWidthChanged)
- Q_PROPERTY(int targetHeight READ targetHeight WRITE setTargetHeight NOTIFY targetHeightChanged)
- Q_PROPERTY(QSGParticleExtruder* targetShape READ targetShape WRITE setTargetShape NOTIFY targetShapeChanged)
- Q_PROPERTY(int targetTime READ targetTime WRITE setTargetTime NOTIFY targetTimeChanged)
-
-public:
- explicit QSGTargetAffector(QQuickItem *parent = 0);
-
- int targetX() const
- {
- return m_targetX;
- }
-
- int targetY() const
- {
- return m_targetY;
- }
-
- int targetWidth() const
- {
- return m_targetWidth;
- }
-
- int targetHeight() const
- {
- return m_targetHeight;
- }
-
- QSGParticleExtruder* targetShape() const
- {
- return m_targetShape;
- }
-
- int targetTime() const
- {
- return m_targetTime;
- }
-
-signals:
-
- void targetXChanged(int arg);
-
- void targetYChanged(int arg);
-
- void targetWidthChanged(int arg);
-
- void targetHeightChanged(int arg);
-
- void targetShapeChanged(QSGParticleExtruder* arg);
-
- void targetTimeChanged(int arg);
-
-public slots:
- void setTargetX(int arg)
- {
- if (m_targetX != arg) {
- m_targetX = arg;
- emit targetXChanged(arg);
- }
- }
-
- void setTargetY(int arg)
- {
- if (m_targetY != arg) {
- m_targetY = arg;
- emit targetYChanged(arg);
- }
- }
-
- void setTargetWidth(int arg)
- {
- if (m_targetWidth != arg) {
- m_targetWidth = arg;
- emit targetWidthChanged(arg);
- }
- }
-
- void setTargetHeight(int arg)
- {
- if (m_targetHeight != arg) {
- m_targetHeight = arg;
- emit targetHeightChanged(arg);
- }
- }
-
- void setTargetShape(QSGParticleExtruder* arg)
- {
- if (m_targetShape != arg) {
- m_targetShape = arg;
- emit targetShapeChanged(arg);
- }
- }
-
- void setTargetTime(int arg)
- {
- if (m_targetTime != arg) {
- m_targetTime = arg;
- emit targetTimeChanged(arg);
- }
- }
-
-protected:
- virtual void reset(QSGParticleData*);
- virtual bool affectParticle(QSGParticleData *d, qreal dt);
-private:
- int m_targetX;
- int m_targetY;
- int m_targetWidth;
- int m_targetHeight;
- QSGParticleExtruder* m_defaultShape;
- QSGParticleExtruder* m_targetShape;
- int m_targetTime;
-
- QHash<QPair<int, int>, QPointF> m_targets;
-};
-
-#endif // QSGTARGETAFFECTOR_H