上一期我们实现了地图的绘制,本篇文章我们进一步实现人物的移动
1基础的概念流程
首先我们要了解一个游戏运行的机制
游戏运行是一帧一帧运行的,多个帧按照一定的时间间隔串起来就形成了我们眼中的游戏画面
此外我们游戏还需要接受玩家的键盘和鼠标信息,然后进行玩家信息的更新
了解了以上的概念,我们继续实现玩家的移动画面
2实现玩家信息的写入和获取
这里采用tiled的对象层设置一个玩家的信息
然后读取map的信息存储到一个vector中
bool MapLoading::parseObjectLayer(const QJsonObject &layerObj, ObjectLayer &objectLayer) {
objectLayer.name = layerObj["name"].toString();
objectLayer.visible = layerObj["visible"].toBool(true); // 默认为可见
// 解析对象数组
QJsonArray objectsArray = layerObj["objects"].toArray();
for (const QJsonValue &objectValue : objectsArray) {
QJsonObject obj = objectValue.toObject();
MapObject mapObject;
// 解析对象基本属性
mapObject.id = obj["id"].toInt();
mapObject.name = obj["name"].toString();
mapObject.type = obj["type"].toString();
mapObject.x = obj["x"].toDouble();
mapObject.y = obj["y"].toDouble();
mapObject.width = obj["width"].toDouble();
mapObject.height = obj["height"].toDouble();
mapObject.gid = obj["gid"].toInt(0); // 如果是图块对象
mapObject.visible = obj["visible"].toBool(true);
// 解析自定义属性
if (obj.contains("properties")) {
QJsonArray propertiesArray = obj["properties"].toArray();
for (const QJsonValue &propValue : propertiesArray) {
QJsonObject propObj = propValue.toObject();
QString propName = propObj["name"].toString();
QJsonValue propValueData = propObj["value"];
mapObject.properties[propName] = propValueData;
}
}
objectLayer.objects.append(mapObject);
}
return true;
}
}
3实现键盘事件的获取
简单的采用键盘事件捕获即可完成
void GameRenderer::keyPressEvent(QKeyEvent *event) { if (event->key() == Qt::Key_W) { m_player->setPosition(m_player->position() + QPointF(0, -10)); } if (event->key() == Qt::Key_A) { m_player->setPosition(m_player->position() + QPointF(-10, 0)); } if (event->key() == Qt::Key_S) { m_player->setPosition(m_player->position() + QPointF(0, 10)); } if (event->key() == Qt::Key_D) { m_player->setPosition(m_player->position() + QPointF(10, 0)); } }
4玩家类的实现,预留了一些接口,方便后续实现
// Player.h
#ifndef PLAYER_H
#define PLAYER_H
#include <QObject>
#include <QPointF>
#include <QString>
#include <QTimer>
namespace gameTools {
class Player : public QObject
{
Q_OBJECT
// 基本属性
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
Q_PROPERTY(QPointF position READ position WRITE setPosition NOTIFY positionChanged)
Q_PROPERTY(double direction READ direction WRITE setDirection NOTIFY directionChanged)
// 状态属性
Q_PROPERTY(int health READ health WRITE setHealth NOTIFY healthChanged)
Q_PROPERTY(int maxHealth READ maxHealth WRITE setMaxHealth NOTIFY maxHealthChanged)
Q_PROPERTY(int mana READ mana WRITE setMana NOTIFY manaChanged)
Q_PROPERTY(int maxMana READ maxMana WRITE setMaxMana NOTIFY maxManaChanged)
Q_PROPERTY(int level READ level WRITE setLevel NOTIFY levelChanged)
Q_PROPERTY(int experience READ experience WRITE setExperience NOTIFY experienceChanged)
// 移动相关属性
Q_PROPERTY(double speed READ speed WRITE setSpeed NOTIFY speedChanged)
Q_PROPERTY(bool isMoving READ isMoving WRITE setIsMoving NOTIFY isMovingChanged)
Q_PROPERTY(QString animationState READ animationState NOTIFY animationStateChanged)
public:
explicit Player(const int x, const int y, QObject *parent = nullptr);
// 基本属性访问器
QString name() const;
void setName(const QString &name);
QPointF position() const;
void setPosition(const QPointF &position);
double direction() const;
void setDirection(double direction);
// 状态属性访问器
int health() const;
void setHealth(int health);
int maxHealth() const;
void setMaxHealth(int maxHealth);
int mana() const;
void setMana(int mana);
int maxMana() const;
void setMaxMana(int maxMana);
int level() const;
void setLevel(int level);
int experience() const;
void setExperience(int experience);
// 移动相关访问器
double speed() const;
void setSpeed(double speed);
bool isMoving() const;
void setIsMoving(bool isMoving);
QString animationState() const;
// 游戏逻辑方法
Q_INVOKABLE void moveTo(const QPointF &targetPosition);
Q_INVOKABLE void stopMoving();
Q_INVOKABLE void takeDamage(int damage);
Q_INVOKABLE void heal(int amount);
Q_INVOKABLE void addExperience(int exp);
Q_INVOKABLE bool checkLevelUp();
signals:
void nameChanged();
void positionChanged();
void directionChanged();
void healthChanged();
void maxHealthChanged();
void manaChanged();
void maxManaChanged();
void levelChanged();
void experienceChanged();
void speedChanged();
void isMovingChanged();
void animationStateChanged();
// 游戏事件信号
void playerMoved(const QPointF &newPosition);
void playerDamaged(int damage);
void playerHealed(int amount);
void playerLevelUp(int newLevel);
void playerDied();
private slots:
void updateMovement();
private:
void updateAnimationState();
void calculateNextLevelExperience();
QString m_name;
QPointF m_position;
double m_direction; // 角度,0-360度
QPointF m_targetPosition;
int m_health;
int m_maxHealth;
int m_mana;
int m_maxMana;
int m_level;
int m_experience;
int m_nextLevelExperience;
double m_speed;
bool m_isMoving;
QString m_animationState;
QTimer *m_movementTimer;
};
} // namespace gameTools
#endif // PLAYER_H
5结果
把上面串联起来就可以得到一个移动的玩家,下一步打算实现玩家在视角的居中以及地图边界的设置,同时添加玩家素材

