Add basic character state switching

This commit is contained in:
2026-05-28 10:55:22 +08:00
parent 69c3d34ae8
commit ece41bafc9
2 changed files with 61 additions and 18 deletions
+54 -13
View File
@@ -45,7 +45,7 @@ PetWindow::PetWindow(QWidget *parent)
layout->addWidget(m_imageLabel);
connect(&m_animationTimer, &QTimer::timeout, this, [this]() {
advanceIdleFrame();
advanceStateFrame();
});
loadInitialImage();
@@ -91,6 +91,7 @@ void PetWindow::mousePressEvent(QMouseEvent *event)
{
m_dragging = true;
m_dragOffset = event->globalPosition().toPoint() - frameGeometry().topLeft();
playState(QStringLiteral("drag"), false);
event->accept();
return;
}
@@ -103,6 +104,7 @@ void PetWindow::mouseReleaseEvent(QMouseEvent *event)
if (event->button() == Qt::LeftButton)
{
m_dragging = false;
playState(QStringLiteral("idle"), false);
event->accept();
return;
}
@@ -113,39 +115,78 @@ void PetWindow::mouseReleaseEvent(QMouseEvent *event)
void PetWindow::loadInitialImage()
{
QString loadError;
const CharacterPackage package = CharacterPackageLoader::load(characterPackagePath(), &loadError);
const CharacterState *idleState = package.state(QStringLiteral("idle"));
if (idleState != nullptr && !idleState->framePaths.isEmpty())
m_characterPackage = CharacterPackageLoader::load(characterPackagePath(), &loadError);
if (m_characterPackage.hasState(QStringLiteral("idle")))
{
startIdleAnimation(*idleState);
playState(QStringLiteral("idle"), true);
return;
}
setDisplayImage(previewImagePath(), true);
}
void PetWindow::startIdleAnimation(const CharacterState &idleState)
void PetWindow::playState(const QString &stateName, bool centerWindow)
{
if (m_currentStateName == stateName && !m_currentFrames.isEmpty())
{
return;
}
const CharacterState *state = m_characterPackage.state(stateName);
if (state == nullptr || state->framePaths.isEmpty() || state->fps <= 0)
{
return;
}
m_animationTimer.stop();
m_idleFrames = idleState.framePaths;
m_currentStateName = stateName;
m_currentFrames = state->framePaths;
m_currentFrameIndex = 0;
setDisplayImage(m_idleFrames.at(m_currentFrameIndex), true);
setDisplayImage(m_currentFrames.at(m_currentFrameIndex), centerWindow);
const int intervalMs = qMax(1, 1000 / idleState.fps);
const int intervalMs = qMax(1, 1000 / state->fps);
m_animationTimer.start(intervalMs);
}
void PetWindow::advanceIdleFrame()
void PetWindow::advanceStateFrame()
{
if (m_idleFrames.isEmpty())
if (m_currentFrames.isEmpty())
{
m_animationTimer.stop();
return;
}
m_currentFrameIndex = (m_currentFrameIndex + 1) % m_idleFrames.size();
setDisplayImage(m_idleFrames.at(m_currentFrameIndex), false);
const CharacterState *state = m_characterPackage.state(m_currentStateName);
if (state == nullptr)
{
m_animationTimer.stop();
return;
}
if (m_currentFrameIndex + 1 >= m_currentFrames.size())
{
if (state->loop)
{
m_currentFrameIndex = 0;
}
else if (!state->nextState.isEmpty())
{
playState(state->nextState, false);
return;
}
else
{
m_animationTimer.stop();
return;
}
}
else
{
++m_currentFrameIndex;
}
setDisplayImage(m_currentFrames.at(m_currentFrameIndex), false);
}
void PetWindow::setDisplayImage(const QString &imagePath, bool centerWindow)
+7 -5
View File
@@ -1,13 +1,13 @@
#pragma once
#include "../character/CharacterPackage.h"
#include <QLabel>
#include <QPoint>
#include <QStringList>
#include <QTimer>
#include <QWidget>
struct CharacterState;
class PetWindow : public QWidget
{
public:
@@ -21,14 +21,16 @@ protected:
private:
void loadInitialImage();
void startIdleAnimation(const CharacterState &idleState);
void advanceIdleFrame();
void playState(const QString &stateName, bool centerWindow);
void advanceStateFrame();
void setDisplayImage(const QString &imagePath, bool centerWindow);
void setAlwaysOnTop(bool enabled);
QLabel *m_imageLabel;
QTimer m_animationTimer;
QStringList m_idleFrames;
CharacterPackage m_characterPackage;
QString m_currentStateName;
QStringList m_currentFrames;
QPoint m_dragOffset;
int m_currentFrameIndex;
bool m_dragging;