RaceGame-Qt游戏项目构建-图形界面

RaceGame-Qt游戏项目构建-图形界面

游戏界面概述

游戏界面的绘制主要包括:地图/墙体,玩家,操作按钮。

QML 框架实现

由于使用旧版的 QWidget 框架还需要单独写一个绘制类,Qt-quick 提供了 QML 框架工具,可以以组件的形式创建窗口界面,处理点击事件和链接函数。只需要把游戏管理类设计成与 QML 形成交互,即可实现游戏逻辑、界面显示,而不用写多余的类。因此之前用 QWidget 框架构建的 class DrawGame 一系列类就不需要了。

QWidget 框架实现起来不同的是,C++QML 联合编程,需要在调用界面之前注册C++类。 而 QWidget 的界面由 Ui 类来控制。

Main.qml

游戏开始界面,包括两个组件:Component EntryComponent Game

Entry.qml

游戏设置界面,可以选择玩家数量,选择游戏地图。

Game.qml

游戏界面,含有游戏地图的绘制,玩家移动的显示。以及一些控制游戏过程的按钮。

说明

游戏界面效果在我的 RaceGame-游戏框架 之中可以看到。

QWidget 框架实现

(此部分基于 QWidget 开发,游戏界面上的组件需要在 C++ 类中创建和销毁,这样写出来的代码比较复杂。因此抛弃了这部分类,直接使用 QML 开发界面组件)

Qt 提供了很多图形库,可以直接使用,绘制游戏地图、更新玩家位置,显示操作按钮等。游戏的主体逻辑已经通过 Player 类和 GameMap 类实现,只需要根据玩家信息、地图信息,绘制出图形化界面即可。

DrawGame 相关类

DrawGame 相关类存放在 drawgame.h 头文件中,相应的源文件在 drawgame.cpp 文件中。原理比较简单,主要实现游戏界面的绘制。

一、 class DrawGame

核心类,绘制工具,需要提供边界信息,具有一个纯虚函数 draw() ,在派生类中实现。

class DrawGame
{
public:
    DrawGame(int width, int height);
protected:
    int Width;
    int Height;
public:
    virtual void draw() const = 0;
    virtual void destoryDraw() const = 0;
};

由于 QtQPainter 库需要在绘制事件中使用,我在这里直接使用Qt 的 QLabel 元素充当填充物,用于直接在窗口绘制图形。 并且 QLabel 标签不仅可以添加文本信息,还能够直接使用 CSS 样式表,自由度高。

不过需要注意的是,刷新帧率高、绘制图形频繁的场合,使用 QLabel + CSS 的形式也许会产生延迟,不利于高刷新的游戏场合。对于保持形状的图形,可以脱离刷新频率的限制,只绘制一次。

RaceGame 游戏并不涉及巨大的绘制开销,使用 QLabel + CSS 的形式可以满足需求。

二、 class DrawPlayer

DrawGame 的派生类,用于绘制玩家。

创建对象初始化的时候需要传递一个 Player 对象指针,用于绘制玩家。还需要传递一个绘制的父窗口,我直接在主界面中绘制。

class DrawPlayer : public DrawGame {
public:
    DrawPlayer(std::shared_ptr<Player> player, QWidget * parent);
private:
    QLabel * label;
    std::shared_ptr<Player> ptr;
public:
    static const QList<QString> playersColor;
    void draw() const override;
    void destoryDraw() const override;
};

因为玩家每一帧都在移动,位置不断在变化,因此在每一帧玩家位置变化之后,都会调用这个类的 draw() 方法。 在 Player 类族中的 玩家移动 playersMove 类中,也管理着绘制的工具,因此绘制玩家是每一帧都在调用的。

每一个玩家对应着一个绘制类,对应一个 QLabel 标签,QLabel * label 创建一次即可,不需要重复销毁创建,每一帧改变 label 的位置即可。

三、 class DrawMap

DrawGame 的派生类,用于绘制地图/墙体。

class DrawMap : public DrawGame {
public:
    DrawMap(QWidget * parent);
private:

    std::shared_ptr<GameMap> ptr;
    static std::array<std::array<QLabel *, MapHeight>, MapWidth> mapLabels;
    static const QList<QString> mapColorList;
public:
    void draw() const override;
    static void draw_a_wall(char x, char y);
    void destoryDraw() const override;
};

具有一个指向 GameMap 对象的指针。地图信息储存在一个 45 * 80 的二维 char 类型矩阵中, char 储存着 wallLevel 信息,根据这些信息绘制不同颜色、形状的墙体。

四、 class DrawManager

抽象类,绘制管理器,使用单例设计模式,把 DrawPlayerDrawMap 的对象储存在管理器的共享指针中,直接使用 管理器绘制游戏界面。

// sinleton
class DrawManager {
private:
    QWidget * parent;
    static std::shared_ptr<DrawManager> drawMgr;
    DrawManager();
public:
    QList<std::shared_ptr<DrawPlayer>> drawPlayerList;
    std::shared_ptr<DrawMap> drawMap;
    void createDrawing();
    void destoryDraw();
    void setParent(QWidget * p);
    static std::shared_ptr<DrawManager> getInstance();
};
posted @ 2025-01-09 22:42  北纬31是条纬线哦  阅读(86)  评论(0)    收藏  举报