Animate idle character frames

This commit is contained in:
2026-05-28 10:48:54 +08:00
parent 4cfeb5022c
commit 69c3d34ae8
2 changed files with 48 additions and 7 deletions
+38 -6
View File
@@ -29,6 +29,7 @@ QString previewImagePath()
PetWindow::PetWindow(QWidget *parent) PetWindow::PetWindow(QWidget *parent)
: QWidget(parent) : QWidget(parent)
, m_imageLabel(new QLabel(this)) , m_imageLabel(new QLabel(this))
, m_currentFrameIndex(0)
, m_dragging(false) , m_dragging(false)
, m_alwaysOnTop(true) , m_alwaysOnTop(true)
{ {
@@ -43,6 +44,10 @@ PetWindow::PetWindow(QWidget *parent)
layout->setContentsMargins(0, 0, 0, 0); layout->setContentsMargins(0, 0, 0, 0);
layout->addWidget(m_imageLabel); layout->addWidget(m_imageLabel);
connect(&m_animationTimer, &QTimer::timeout, this, [this]() {
advanceIdleFrame();
});
loadInitialImage(); loadInitialImage();
} }
@@ -112,14 +117,38 @@ void PetWindow::loadInitialImage()
const CharacterState *idleState = package.state(QStringLiteral("idle")); const CharacterState *idleState = package.state(QStringLiteral("idle"));
if (idleState != nullptr && !idleState->framePaths.isEmpty()) if (idleState != nullptr && !idleState->framePaths.isEmpty())
{ {
setDisplayImage(idleState->framePaths.first()); startIdleAnimation(*idleState);
return; return;
} }
setDisplayImage(previewImagePath()); setDisplayImage(previewImagePath(), true);
} }
void PetWindow::setDisplayImage(const QString &imagePath) void PetWindow::startIdleAnimation(const CharacterState &idleState)
{
m_animationTimer.stop();
m_idleFrames = idleState.framePaths;
m_currentFrameIndex = 0;
setDisplayImage(m_idleFrames.at(m_currentFrameIndex), true);
const int intervalMs = qMax(1, 1000 / idleState.fps);
m_animationTimer.start(intervalMs);
}
void PetWindow::advanceIdleFrame()
{
if (m_idleFrames.isEmpty())
{
m_animationTimer.stop();
return;
}
m_currentFrameIndex = (m_currentFrameIndex + 1) % m_idleFrames.size();
setDisplayImage(m_idleFrames.at(m_currentFrameIndex), false);
}
void PetWindow::setDisplayImage(const QString &imagePath, bool centerWindow)
{ {
QPixmap pixmap(imagePath); QPixmap pixmap(imagePath);
if (pixmap.isNull()) if (pixmap.isNull())
@@ -134,10 +163,13 @@ void PetWindow::setDisplayImage(const QString &imagePath)
m_imageLabel->setPixmap(scaled); m_imageLabel->setPixmap(scaled);
resize(scaled.size()); resize(scaled.size());
if (const QScreen *screen = QGuiApplication::primaryScreen()) if (centerWindow)
{ {
const QRect available = screen->availableGeometry(); if (const QScreen *screen = QGuiApplication::primaryScreen())
move(available.center() - rect().center()); {
const QRect available = screen->availableGeometry();
move(available.center() - rect().center());
}
} }
} }
+10 -1
View File
@@ -2,8 +2,12 @@
#include <QLabel> #include <QLabel>
#include <QPoint> #include <QPoint>
#include <QStringList>
#include <QTimer>
#include <QWidget> #include <QWidget>
struct CharacterState;
class PetWindow : public QWidget class PetWindow : public QWidget
{ {
public: public:
@@ -17,11 +21,16 @@ protected:
private: private:
void loadInitialImage(); void loadInitialImage();
void setDisplayImage(const QString &imagePath); void startIdleAnimation(const CharacterState &idleState);
void advanceIdleFrame();
void setDisplayImage(const QString &imagePath, bool centerWindow);
void setAlwaysOnTop(bool enabled); void setAlwaysOnTop(bool enabled);
QLabel *m_imageLabel; QLabel *m_imageLabel;
QTimer m_animationTimer;
QStringList m_idleFrames;
QPoint m_dragOffset; QPoint m_dragOffset;
int m_currentFrameIndex;
bool m_dragging; bool m_dragging;
bool m_alwaysOnTop; bool m_alwaysOnTop;
}; };