Add randomized idle behaviors
This commit is contained in:
+75
-1
@@ -10,6 +10,7 @@
|
|||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
#include <QPixmap>
|
#include <QPixmap>
|
||||||
|
#include <QRandomGenerator>
|
||||||
#include <QScreen>
|
#include <QScreen>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
@@ -48,6 +49,16 @@ PetWindow::PetWindow(QWidget *parent)
|
|||||||
advanceStateFrame();
|
advanceStateFrame();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
m_idleBehaviorTimer.setSingleShot(true);
|
||||||
|
connect(&m_idleBehaviorTimer, &QTimer::timeout, this, [this]() {
|
||||||
|
playIdleBehavior();
|
||||||
|
});
|
||||||
|
|
||||||
|
m_behaviorReturnTimer.setSingleShot(true);
|
||||||
|
connect(&m_behaviorReturnTimer, &QTimer::timeout, this, [this]() {
|
||||||
|
returnToIdleFromBehavior();
|
||||||
|
});
|
||||||
|
|
||||||
loadInitialImage();
|
loadInitialImage();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,7 +169,7 @@ void PetWindow::addStateTestActions(QMenu *menu)
|
|||||||
stateMenu->setEnabled(!stateMenu->actions().isEmpty());
|
stateMenu->setEnabled(!stateMenu->actions().isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
void PetWindow::playState(const QString &stateName, bool centerWindow)
|
void PetWindow::playState(const QString &stateName, bool centerWindow, bool autoReturn)
|
||||||
{
|
{
|
||||||
if (m_currentStateName == stateName && !m_currentFrames.isEmpty())
|
if (m_currentStateName == stateName && !m_currentFrames.isEmpty())
|
||||||
{
|
{
|
||||||
@@ -171,6 +182,8 @@ void PetWindow::playState(const QString &stateName, bool centerWindow)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_idleBehaviorTimer.stop();
|
||||||
|
m_behaviorReturnTimer.stop();
|
||||||
m_animationTimer.stop();
|
m_animationTimer.stop();
|
||||||
m_currentStateName = stateName;
|
m_currentStateName = stateName;
|
||||||
m_currentFrames = state->framePaths;
|
m_currentFrames = state->framePaths;
|
||||||
@@ -180,6 +193,15 @@ void PetWindow::playState(const QString &stateName, bool centerWindow)
|
|||||||
|
|
||||||
const int intervalMs = qMax(1, 1000 / state->fps);
|
const int intervalMs = qMax(1, 1000 / state->fps);
|
||||||
m_animationTimer.start(intervalMs);
|
m_animationTimer.start(intervalMs);
|
||||||
|
|
||||||
|
if (stateName == QStringLiteral("idle"))
|
||||||
|
{
|
||||||
|
scheduleIdleBehavior();
|
||||||
|
}
|
||||||
|
else if (autoReturn && state->loop)
|
||||||
|
{
|
||||||
|
m_behaviorReturnTimer.start(4000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PetWindow::advanceStateFrame()
|
void PetWindow::advanceStateFrame()
|
||||||
@@ -222,6 +244,58 @@ void PetWindow::advanceStateFrame()
|
|||||||
setDisplayImage(m_currentFrames.at(m_currentFrameIndex), false);
|
setDisplayImage(m_currentFrames.at(m_currentFrameIndex), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PetWindow::scheduleIdleBehavior()
|
||||||
|
{
|
||||||
|
if (!m_characterPackage.hasState(QStringLiteral("idle")))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int idleDelayMs = QRandomGenerator::global()->bounded(8000, 16001);
|
||||||
|
m_idleBehaviorTimer.start(idleDelayMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PetWindow::playIdleBehavior()
|
||||||
|
{
|
||||||
|
if (m_dragging || m_currentStateName != QStringLiteral("idle"))
|
||||||
|
{
|
||||||
|
scheduleIdleBehavior();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList candidateStates;
|
||||||
|
const QStringList preferredStates = {
|
||||||
|
QStringLiteral("think"),
|
||||||
|
QStringLiteral("sleep"),
|
||||||
|
QStringLiteral("happy"),
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const QString &stateName : preferredStates)
|
||||||
|
{
|
||||||
|
if (m_characterPackage.hasState(stateName))
|
||||||
|
{
|
||||||
|
candidateStates.append(stateName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (candidateStates.isEmpty())
|
||||||
|
{
|
||||||
|
scheduleIdleBehavior();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int stateIndex = QRandomGenerator::global()->bounded(candidateStates.size());
|
||||||
|
playState(candidateStates.at(stateIndex), false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PetWindow::returnToIdleFromBehavior()
|
||||||
|
{
|
||||||
|
if (!m_dragging)
|
||||||
|
{
|
||||||
|
playState(QStringLiteral("idle"), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void PetWindow::setDisplayImage(const QString &imagePath, bool centerWindow)
|
void PetWindow::setDisplayImage(const QString &imagePath, bool centerWindow)
|
||||||
{
|
{
|
||||||
QPixmap pixmap(imagePath);
|
QPixmap pixmap(imagePath);
|
||||||
|
|||||||
+6
-1
@@ -24,13 +24,18 @@ protected:
|
|||||||
private:
|
private:
|
||||||
void loadInitialImage();
|
void loadInitialImage();
|
||||||
void addStateTestActions(QMenu *menu);
|
void addStateTestActions(QMenu *menu);
|
||||||
void playState(const QString &stateName, bool centerWindow);
|
void playState(const QString &stateName, bool centerWindow, bool autoReturn = false);
|
||||||
void advanceStateFrame();
|
void advanceStateFrame();
|
||||||
|
void scheduleIdleBehavior();
|
||||||
|
void playIdleBehavior();
|
||||||
|
void returnToIdleFromBehavior();
|
||||||
void setDisplayImage(const QString &imagePath, bool centerWindow);
|
void setDisplayImage(const QString &imagePath, bool centerWindow);
|
||||||
void setAlwaysOnTop(bool enabled);
|
void setAlwaysOnTop(bool enabled);
|
||||||
|
|
||||||
QLabel *m_imageLabel;
|
QLabel *m_imageLabel;
|
||||||
QTimer m_animationTimer;
|
QTimer m_animationTimer;
|
||||||
|
QTimer m_idleBehaviorTimer;
|
||||||
|
QTimer m_behaviorReturnTimer;
|
||||||
CharacterPackage m_characterPackage;
|
CharacterPackage m_characterPackage;
|
||||||
QString m_currentStateName;
|
QString m_currentStateName;
|
||||||
QStringList m_currentFrames;
|
QStringList m_currentFrames;
|
||||||
|
|||||||
Reference in New Issue
Block a user