Implement randomStart for sprites
authorAlan Alpert <alan.alpert@nokia.com>
Wed, 18 Jan 2012 01:48:30 +0000 (11:48 +1000)
committerQt by Nokia <qt-info@nokia.com>
Fri, 27 Jan 2012 05:17:54 +0000 (06:17 +0100)
Most useful in the particle system, so that sprites aren't temporally
aligned at the start (ruining the random look).

Change-Id: I1cbf6c2187e412fcb8b31cab0d87bcde275c9281
Reviewed-by: Alan Alpert <alan.alpert@nokia.com>

examples/declarative/particles/affectors/spritegoal.qml
src/quick/items/qquicksprite.cpp
src/quick/items/qquickspriteengine.cpp
src/quick/items/qquickspriteengine_p.h

index 1e14e0b..ac4f3c7 100644 (file)
@@ -38,9 +38,8 @@
 **
 ****************************************************************************/
 
-import QtQuick.Particles 2.0
-import QtQuick.Particles 2.0 as Qlp
 import QtQuick 2.0
+import QtQuick.Particles 2.0
 
 Item {
     id: root
@@ -108,14 +107,13 @@ Item {
                 source: "../images/meteor.png"
                 frames: 35
                 duration: 40
-                speedModifiesDuration: -0.1
+                randomStart: true
                 to: {"explode":0, "spinning":1}
             },Sprite {
                 name: "explode"
                 source: "../images/_explo.png"
                 frames: 22
                 duration: 40
-                speedModifiesDuration: -0.1
                 to: {"nullFrame":1}
             },Sprite {//Not sure if this is needed, but seemed easiest
                 name: "nullFrame"
index fc7f089..ac5fe5d 100644 (file)
@@ -174,6 +174,18 @@ QT_BEGIN_NAMESPACE
 */
 
 /*!
+    \qmlproperty bool QtQuick2::Sprite::randomStart
+
+    If true, then the animation will start its first animation with a random amount of its duration skipped.
+    This allows them to not look like they all just started when the animation begins.
+
+    This only affects the very first animation played. Transitioning to another animation, or the same
+    animation again, will not trigger this.
+
+    Default is false.
+*/
+
+/*!
     \qmlproperty bool QtQuick2::Sprite::frameSync
 
     If true, then the animation will have no duration. Instead, the animation will advance
index 42904b2..6e2e876 100644 (file)
@@ -75,6 +75,7 @@ QT_BEGIN_NAMESPACE
     state normally does.
 */
 
+static const int NINF = -1000000;//magic number for random start time - should be more negative than a single realistic animation duration
 /* TODO:
    make sharable?
    solve the state data initialization/transfer issue so as to not need to make friends
@@ -380,6 +381,10 @@ void QQuickStochasticEngine::start(int index, int state)
         return;
     m_things[index] = state;
     m_duration[index] = m_states[state]->variedDuration();
+    if (m_states[state]->randomStart())
+        m_startTimes[index] = NINF;
+    else
+        m_startTimes[index] = 0;
     m_goals[index] = -1;
     restart(index);
 }
@@ -388,16 +393,19 @@ void QQuickStochasticEngine::stop(int index)
 {
     if (index >= m_things.count())
         return;
-    //Will never change until start is called again with a new state - this is not a 'pause'
+    //Will never change until start is called again with a new state (or manually advanced) - this is not a 'pause'
     for (int i=0; i<m_stateUpdates.count(); i++)
         m_stateUpdates[i].second.removeAll(index);
 }
 
 void QQuickStochasticEngine::restart(int index)
 {
+    bool randomStart = (m_startTimes[index] == NINF);
     m_startTimes[index] = m_timeOffset;
     if (m_addAdvance)
         m_startTimes[index] += m_advanceTime.elapsed();
+    if (randomStart)
+        m_startTimes[index] -= qrand() % m_duration[index];
     int time = m_duration[index] + m_startTimes[index];
     for (int i=0; i<m_stateUpdates.count(); i++)
         m_stateUpdates[i].second.removeAll(index);
@@ -407,13 +415,24 @@ void QQuickStochasticEngine::restart(int index)
 
 void QQuickSpriteEngine::restart(int index) //Reimplemented to recognize and handle pseudostates
 {
+    bool randomStart = (m_startTimes[index] == NINF);
     if (m_sprites[m_things[index]]->frameSync()) {//Manually advanced
         m_startTimes[index] = 0;
+        if (randomStart && m_sprites[m_things[index]]->m_generatedCount)
+            m_startTimes[index] += qrand() % m_sprites[m_things[index]]->m_generatedCount;
     } else {
         m_startTimes[index] = m_timeOffset;
         if (m_addAdvance)
             m_startTimes[index] += m_advanceTime.elapsed();
+        if (randomStart)
+            m_startTimes[index] -= qrand() % m_duration[index];
         int time = spriteDuration(index) + m_startTimes[index];
+        if (randomStart) {
+            int curTime = m_timeOffset + (m_addAdvance ? m_advanceTime.elapsed() : 0);
+            while (time < curTime) //Fast forward through psuedostates as needed
+                time += spriteDuration(index);
+        }
+
         for (int i=0; i<m_stateUpdates.count(); i++)
             m_stateUpdates[i].second.removeAll(index);
         addToUpdateList(time, index);
index 7a147a2..6adab97 100644 (file)
@@ -61,6 +61,8 @@ class Q_AUTOTEST_EXPORT QQuickStochasticState : public QObject //Currently for i
     Q_OBJECT
     Q_PROPERTY(int duration READ duration WRITE setDuration NOTIFY durationChanged)
     Q_PROPERTY(int durationVariation READ durationVariation WRITE setDurationVariation NOTIFY durationVariationChanged)
+    //Note than manually advanced sprites need to query this variable and implement own behaviour for it
+    Q_PROPERTY(bool randomStart READ randomStart WRITE setRandomStart NOTIFY randomStartChanged)
     Q_PROPERTY(QVariantMap to READ to WRITE setTo NOTIFY toChanged)
     Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
 
@@ -68,6 +70,8 @@ public:
     QQuickStochasticState(QObject* parent = 0)
         : QObject(parent)
         , m_duration(1000)
+        , m_durationVariation(0)
+        , m_randomStart(false)
     {
     }
 
@@ -99,6 +103,11 @@ public:
                 - m_durationVariation);
     }
 
+    bool randomStart() const
+    {
+        return m_randomStart;
+    }
+
 signals:
     void durationChanged(int arg);
 
@@ -110,6 +119,8 @@ signals:
 
     void entered();//### Just playing around - don't expect full state API
 
+    void randomStartChanged(bool arg);
+
 public slots:
     void setDuration(int arg)
     {
@@ -143,6 +154,14 @@ public slots:
         }
     }
 
+    void setRandomStart(bool arg)
+    {
+        if (m_randomStart != arg) {
+            m_randomStart = arg;
+            emit randomStartChanged(arg);
+        }
+    }
+
 private:
     QString m_name;
     QVariantMap m_to;
@@ -150,6 +169,7 @@ private:
     int m_durationVariation;
 
     friend class QQuickStochasticEngine;
+    bool m_randomStart;
 };
 
 class Q_AUTOTEST_EXPORT QQuickStochasticEngine : public QObject