[学习][笔记] qt5 从入门到入坟:<13>基于GraphicsViewFrame的贪吃蛇实现

简介: [学习][笔记] qt5 从入门到入坟:<13>基于GraphicsViewFrame的贪吃蛇实现

贪吃蛇实现

对于游戏而言,

我们需要一个QGraphicsScene,作为游戏发生的舞台;

一个QGraphicsView,作为观察游戏舞台的组件;

以及若干元素,用于表示游戏对象,比如蛇、食物以及障碍物等。

绘制地图

Qt 学习之路 2(31):贪吃蛇游戏(1)

需求:

创建 400* 400 的20*20灰色格子的黑色边界的地图

成品代码:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
class QGraphicsScene;
class QGraphicsView;
class GameController;
class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MainWindow(QWidget *parent = 0);
    ~MainWindow();
//private slots:
//    void adjustViewSize();
private:
    void initScene();
    void initSceneBackground();
    QGraphicsScene *scene;
    QGraphicsView *view;
    GameController *game;
};
#endif // MAINWINDOW_H
#include <QGraphicsView>
#include <QTimer>
#include <qaction.h>
#include <qmenubar.h>
#include <qapplication.h>
#include <qmessagebox.h>
#include "mainwindow.h"
//#include "constant.h"
const int TILE_SIZE = 20;
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    scene(new QGraphicsScene(this)),
    view(new QGraphicsView(scene, this))/*,
    game(new GameController(*scene, this))*/
{
    setCentralWidget(view);
    resize(600, 600);
    initScene();
    initSceneBackground();
    QTimer::singleShot(0, this, SLOT(adjustViewSize()));
}
void MainWindow::initScene()
{
    scene->setSceneRect(-100, -100, 200, 200);
}
void MainWindow::initSceneBackground()
{
    QPixmap bg(TILE_SIZE, TILE_SIZE);
    QPainter p(&bg);
    p.setBrush(QBrush(Qt::gray));
    p.drawRect(0, 0, TILE_SIZE, TILE_SIZE);
    view->setBackgroundBrush(QBrush(bg));
}
MainWindow::~MainWindow()
{
}

思路:

1.初始化地图大小 600600
2.初始矩形的逻辑坐标为(-100,-100)为原点
长宽逻辑长为200
200

3.初始化背景为QBrush为灰色,

QPixmap作为背景画刷,铺满整个视图,(默认是重复平铺),大小10*10

注意:

static void QTimer::singleShot(int msec, QObject * receiver, const char * member);

在 msec 毫秒之后,调用 receiver 的 member 槽函数。在我们的代码中,第一个参数传递的是 0,也就是 0ms 之后,调用this->adjustViewSize()

效果图:

设计蛇和食物

Qt 学习之路 2(32):贪吃蛇游戏(2)

设计食物

需求

绘制

一个红色的小圆饼,大小要比地图中的一个方格要小

实现

思路:

代码:

// food.h //
#ifndef FOOD_H
#define FOOD_H
#include <QGraphicsItem>
class Food : public QGraphicsItem
{
public:
    Food(qreal x, qreal y);
    QRectF boundingRect() const override;
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) override;
    QPainterPath shape() const override;
};
#endif // FOOD_H
// food.cpp //
#include <QPainter>
#include "constants.h"
#include "food.h"
static const qreal FOOD_RADIUS = 3.0;
Food::Food(qreal x, qreal y)
{
    setPos(x, y);
    setData(GD_Type, GO_Food);//该图形元素添加额外的数据信息
}
QRectF Food::boundingRect() const //返回一个用于包裹住图形元素的矩形
{
    return QRectF(-TILE_SIZE,    -TILE_SIZE,
                   TILE_SIZE * 2, TILE_SIZE * 2 );
}
void Food::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) //使用QPainter将图形元素绘制出来。
{
    painter->save();
    painter->setRenderHint(QPainter::Antialiasing);
    painter->fillPath(shape(), Qt::red);
    painter->restore();
}
QPainterPath Food::shape() const //矢量轮廓线,绘制路径
{
    QPainterPath p;
    p.addEllipse(QPointF(TILE_SIZE / 2, TILE_SIZE / 2), FOOD_RADIUS, FOOD_RADIUS); //draw circle
    return p;
}
#ifndef GAMECONTROLLER_H
#define GAMECONTROLLER_H
#include <QObject>
#include <QGraphicsScene>
#include <QTimer>
#include <QAction>
class Snake;
class Food;
class GameController : public QObject
{
    Q_OBJECT
public:
    GameController();
    GameController(QGraphicsScene *scene, QObject *parent);
    virtual ~GameController() {}
public slots:
    void pause();
    void resume();
private:
    QAction * resumeAction;
    QTimer timer;
    QGraphicsScene *scene;
    Snake *snake;
};
#endif // GAMECONTROLLER_H
//gamecontroller.cpp
#include <QEvent>
#include <QGraphicsScene>
#include <QKeyEvent>
#include <QMessageBox>
#include <QAction>
#include "gamecontroller.h"
#include "food.h"
//#include "snake.h"
GameController::GameController(QGraphicsScene *scene, QObject *parent) :
    QObject(parent),
    scene(scene)
    /*,snake(new Snake(this))*/
{
    timer.start(1000/33);
    Food *a1 = new Food(0, -50);
    scene->addItem(a1);
    //scene->addItem(snake);
    scene->installEventFilter(this);
    resume();
}
void GameController::pause()
{
    disconnect(&timer, SIGNAL(timeout()),
               scene,  SLOT(advance()));
}
void GameController::resume()
{
    connect(&timer, SIGNAL(timeout()),
            scene,  SLOT(advance()));
}

GameController的工作是,初始化场景中的游戏对象,开始游戏循环。每一个游戏都需要有一个游戏循环,类型于事件循环。想象一个每秒滴答 30 次的表。每次响起滴答声,游戏对象才有机会执行相应的动作:移动、检查碰撞、攻击或者其它一些游戏相关的活动。为方便起见,我们将这一次滴答成为一帧,那么,每秒 30 次滴答,就是每秒 30 帧。游戏循环通常使用定时器实现,因为应用程序不仅仅是一个游戏循环,还需要响应其它事件,比如游戏者的鼠标键盘操作。正因为如此,我们不能简单地使用无限的 for 循环作为游戏循环。

在 Graphics View Framework 中,每一帧都应该调用一个称为advance()的函数。QGraphicsScene::advance()会调用场景中每一个元素自己的advance()函数。所以,如果图形元素需要做什么事,必须重写QGraphicsItem的advance(),然后在游戏循环中调用这个函数。

设计蛇

需求

1.蛇具有复杂得多的形状。因为蛇的形状随着游戏者的控制而不同,因此,我们必须找出一个能够恰好包含蛇头和所有身体块的矩形。这也是 boundingRect() 函数所要解决的问题。

2.蛇会长大(比如吃了食物之后)。因此,我们需要在蛇对象中增加一个用于代表蛇身体长度的growing变量:当growing为正数时,蛇的身体增加一格;当growing为负数时,蛇的身体减少一格。

3.advance()函数用于编码移动部分,这个函数会在一秒内调用 30 次(这是我们在GameController的定时器中决定的)。

实现

思路:

1.绘制一个黄色方框 添加到scene里面

2.控制小蛇

绘制蛇

代码:

#ifndef SNAKE_H
#define SNAKE_H
#include <QGraphicsItem>
#include "gamecontroller.h"
class Snake :public QGraphicsItem
{
public:
    Snake();
    Snake(GameController *controller);
    QRectF boundingRect() const override;
    QPainterPath shape() const override;
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
private:
    QPointF  head;
    QList<QPointF> tail;
};
//snake.cpp 
#include <QPainter>
#include <constants.h>
#include "snake.h"
static const qreal SNAKE_SIZE = TILE_SIZE;
Snake::Snake(GameController *controller) :
    head(0, 0)/*,
    growing(7),
    speed(5),
    moveDirection(NoMove),
    controller(controller)*/
{
}
QRectF Snake::boundingRect() const
{
    qreal minX = head.x();
    qreal minY = head.y();
    qreal maxX = head.x();
    qreal maxY = head.y();
    foreach (QPointF p, tail) {
        maxX = p.x() > maxX ? p.x() : maxX;
        maxY = p.y() > maxY ? p.y() : maxY;
        minX = p.x() < minX ? p.x() : minX;
        minY = p.y() < minY ? p.y() : minY;
    }
    QPointF tl = mapFromScene(QPointF(minX, minY));
    QPointF br = mapFromScene(QPointF(maxX, maxY));
    QRectF bound = QRectF(tl.x(),  // x
                          tl.y(),  // y
                          br.x() - tl.x() + SNAKE_SIZE,      // width
                          br.y() - tl.y() + SNAKE_SIZE       //height
                          );
    return bound;
}
QPainterPath Snake::shape() const
{
    QPainterPath path;
    path.setFillRule(Qt::WindingFill);
    path.addRect(QRectF(0, 0, SNAKE_SIZE, SNAKE_SIZE));
    foreach (QPointF p, tail) {
        QPointF itemp = mapFromScene(p);
        path.addRect(QRectF(itemp.x(), itemp.y(), SNAKE_SIZE, SNAKE_SIZE));
    }
    return path;
}
void Snake::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
{
    painter->save();
    painter->fillPath(shape(), Qt::yellow);
    painter->restore();
}
#endif // SNAKE_H
//gamecontroller.cpp
#include "gamecontroller.h"
#include "food.h"
#include "snake.h"
GameController::GameController(QGraphicsScene *scene, QObject *parent) :
    QObject(parent),
    scene(scene),
    snake(new Snake(this))
{
    timer.start(1000/33);
    Food *a1 = new Food(0, -50);
    scene->addItem(a1);
    scene->addItem(snake);
    scene->installEventFilter(this);
    resume();
}
控制蛇

详解 QT Event 以及 Event Filter 事件处理

代码实现:

#ifndef GAMECONTROLLER_H
#define GAMECONTROLLER_H
#include <QObject>
#include <QGraphicsScene>
#include <QTimer>
#include <QAction>
class Snake;
class Food;
class GameController : public QObject
{
    Q_OBJECT
public:
    GameController();
    GameController(QGraphicsScene &scene, QObject *parent);
    virtual ~GameController() {}
public slots:
    void pause();
    void resume();
protected:
     bool eventFilter(QObject *object, QEvent *event);
private:
     void handleKeyPressed(QKeyEvent *event);
     void addNewFood();
     void setResume();
private:
     QAction * resumeAction;
     QTimer timer;
     QGraphicsScene &scene;
     Snake *snake;
     bool isPause;
};
#endif // GAMECONTROLLER_H
//gamecontroller.cpp
#include <QEvent>
#include <QGraphicsScene>
#include <QKeyEvent>
#include <QMessageBox>
#include <QAction>
#include "gamecontroller.h"
#include "food.h"
#include "snake.h"
#include "mainwindow.h"
GameController::GameController(QGraphicsScene &scene, QObject *parent) :
    QObject(parent),
    scene(scene),
    snake(new Snake(*this))
{
    timer.start(1000/33);
    Food *a1 = new Food(0, -50);
    scene.addItem(a1);
    scene.addItem(snake);
    scene.installEventFilter(this);
    resume();
}
void GameController::()
{
    disconnect(&timer, SIGNAL(timeout()),
               &scene,  SLOT(advance()));
}
void GameController::resume()
{
    connect(&timer, SIGNAL(timeout()),
            &scene,  SLOT(advance()));
}
bool GameController::eventFilter(QObject *object, QEvent *event)
{
    if (event->type() == QEvent::KeyPress) {
        handleKeyPressed((QKeyEvent *)event);
        return true;
    } else {
        return QObject::eventFilter(object, event);
    }
}
void GameController::handleKeyPressed(QKeyEvent *event)
{
    if (!isPause)
        switch (event->key()) {
            case Qt::Key_Left:
                snake->setMoveDirection(Snake::MoveLeft);
                break;
            case Qt::Key_Right:
                snake->setMoveDirection(Snake::MoveRight);
                break;
            case Qt::Key_Up:
                snake->setMoveDirection(Snake::MoveUp);
                break;
            case Qt::Key_Down:
                snake->setMoveDirection(Snake::MoveDown);
                break;
            case Qt::Key_Space:
                ();
                break;
        }
    else resume();
}



相关文章
|
2月前
|
Web App开发 编解码 安全
视频会议技术 入门探究:WebRTC、Qt与FFmpeg在视频编解码中的应用
视频会议技术 入门探究:WebRTC、Qt与FFmpeg在视频编解码中的应用
168 4
|
3月前
|
数据挖掘 C++
QT基础入门——项目案例(七)
QT基础入门——项目案例(七)
97 0
QT基础入门——项目案例(七)
|
3月前
|
API
QT基础入门——Qt事件(五)
QT基础入门——Qt事件(五)
54 0
QT基础入门——Qt事件(五)
|
3月前
|
Unix Java Linux
QT基础入门——认识与创建QT(一)
QT基础入门——认识与创建QT(一)
62 0
QT基础入门——认识与创建QT(一)
|
2月前
|
Linux 编译器 API
探索Qt图像处理的奥秘:从入门到精通
探索Qt图像处理的奥秘:从入门到精通
85 2
|
2月前
|
SQL 存储 关系型数据库
【C/C++ 应用开发 数据库】入门 Qt数据库编程:从基本操作到高级技巧
【C/C++ 应用开发 数据库】入门 Qt数据库编程:从基本操作到高级技巧
80 0
|
3月前
|
编解码
QT基础入门——文件操作(六)
QT基础入门——文件操作(六)
27 0
QT基础入门——文件操作(六)
|
3月前
|
容器
QT基础入门——界面布局和常用控件(四)
QT基础入门——界面布局和常用控件(四)
38 0
QT基础入门——界面布局和常用控件(四)
|
3月前
|
存储
QT基础入门——QMainWindow与对话框QDialog(三)
QT基础入门——QMainWindow与对话框QDialog(三)
55 0
QT基础入门——QMainWindow与对话框QDialog(三)
|
3月前
QT基础入门——信号和槽机制(二)
QT基础入门——信号和槽机制(二)
70 0
QT基础入门——信号和槽机制(二)

推荐镜像

更多