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();
};

本文作者:北纬31是条纬线哦

本文链接:https://www.cnblogs.com/beiwei31/p/18663030

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   北纬31是条纬线哦  阅读(19)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起
  1. 1 If 丁可
If - 丁可
00:00 / 00:00
An audio error has occurred.

I came your danger soul 我靠近你危险的灵魂

Think so you'll say hello 想着你会主动打招呼

Breaking you find to go 忽然你想要转身离去

Break down you might be lone 黯然神伤或许你也会孤独吧

Angel you down thinking 天使如你可否冷静思虑

Think so you freaking down 还以为你会不药而愈

Say hi to send you go 一声问候就让你安心离开

Break down you might be lone 黯然神伤或许你也会孤独吧

And you know you saying to go 你自顾自洒脱的离去

Breaking down I find to go 终于遍体鳞伤的我选择离开

I can't down to soul 怎敢抚慰那深至灵魂的痛

You don't know I love you so 却不知这份爱的深沉

Angel now you think so 我的爱人事到如今你还会这样想吧

Don't freak the danger soul 是我不该诱惑你危险不安的灵魂吧

Breaking I find to go 终于遍体鳞伤的我选择离开

Break down you might be lone 黯然神伤或许你也会孤独吧

And you know you saying to go 你自顾自洒脱的离去

You don't know I love you so 却不知这份爱的深沉

Breaking down you trying to go 伤痕累累你试图不告而别

I can't down to soul 怎敢抚慰那深至灵魂的痛

And you know you trying to go 你自顾自洒脱的离去

You don't know I love you so 却不知这份爱的深沉

Breaking down you trying to go 伤痕累累你试图不告而别

I can't down to soul 怎敢抚慰那深至灵魂的痛