From 30fb79c7d061473fc2839ccdd54380943847e605 Mon Sep 17 00:00:00 2001 From: Ysm-04 Date: Thu, 28 May 2026 11:37:18 +0800 Subject: [PATCH] Add randomized idle behaviors --- src/ui/PetWindow.cpp | 76 +++++++++++++++++++++++++++++++++++++++++++- src/ui/PetWindow.h | 7 +++- 2 files changed, 81 insertions(+), 2 deletions(-) diff --git a/src/ui/PetWindow.cpp b/src/ui/PetWindow.cpp index 2f872a3..1921c34 100644 --- a/src/ui/PetWindow.cpp +++ b/src/ui/PetWindow.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -48,6 +49,16 @@ PetWindow::PetWindow(QWidget *parent) 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(); } @@ -158,7 +169,7 @@ void PetWindow::addStateTestActions(QMenu *menu) 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()) { @@ -171,6 +182,8 @@ void PetWindow::playState(const QString &stateName, bool centerWindow) return; } + m_idleBehaviorTimer.stop(); + m_behaviorReturnTimer.stop(); m_animationTimer.stop(); m_currentStateName = stateName; m_currentFrames = state->framePaths; @@ -180,6 +193,15 @@ void PetWindow::playState(const QString &stateName, bool centerWindow) const int intervalMs = qMax(1, 1000 / state->fps); m_animationTimer.start(intervalMs); + + if (stateName == QStringLiteral("idle")) + { + scheduleIdleBehavior(); + } + else if (autoReturn && state->loop) + { + m_behaviorReturnTimer.start(4000); + } } void PetWindow::advanceStateFrame() @@ -222,6 +244,58 @@ void PetWindow::advanceStateFrame() 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) { QPixmap pixmap(imagePath); diff --git a/src/ui/PetWindow.h b/src/ui/PetWindow.h index d5f6c3b..9557301 100644 --- a/src/ui/PetWindow.h +++ b/src/ui/PetWindow.h @@ -24,13 +24,18 @@ protected: private: void loadInitialImage(); void addStateTestActions(QMenu *menu); - void playState(const QString &stateName, bool centerWindow); + void playState(const QString &stateName, bool centerWindow, bool autoReturn = false); void advanceStateFrame(); + void scheduleIdleBehavior(); + void playIdleBehavior(); + void returnToIdleFromBehavior(); void setDisplayImage(const QString &imagePath, bool centerWindow); void setAlwaysOnTop(bool enabled); QLabel *m_imageLabel; QTimer m_animationTimer; + QTimer m_idleBehaviorTimer; + QTimer m_behaviorReturnTimer; CharacterPackage m_characterPackage; QString m_currentStateName; QStringList m_currentFrames;