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 <QMouseEvent>
#include <QPixmap>
#include <QRandomGenerator>
#include <QScreen>
#include <QVBoxLayout>
@@ -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);