Add randomized idle behaviors

This commit is contained in:
2026-05-28 11:37:18 +08:00
parent c5c29bd6cd
commit 30fb79c7d0
2 changed files with 81 additions and 2 deletions
+75 -1
View File
@@ -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
View File
@@ -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;