目录
内容介绍
一.添加头文件
二.初始化蛇与奖品
三.设置背景图,蛇与奖品
1.设置背景图
2.画蛇
3.画奖品
四.小蛇移动
1.控制方向
2.向上移动
3.向下移动
4.向右移动
5.向左移动
五.随机生成奖品位置
六.是否吃到奖品
七.删除操作
八.游戏结束
九.效果演示
十.代码演示
.h
.cpp
内容介绍
首先,在构造函数中,创建了一个定时器,并设置了信号和槽的连接,这样定时器每次超时时间到达,就会调用timeout函数。同时,在构造函数中也创建了蛇和奖品,并将它们画在了界面上。
在keyPressEvent函数中,根据用户按下的方向键,来改变蛇的移动方向。
在addTop、addDown、addRight、addLeft函数中,根据蛇的当前移动方向,来生成蛇的新身体部分,并插入到蛇的身体列表的最前面。
在addNewReward函数中,生成一个新的奖品,并将它的位置记录在rewardNode变量中。
在paintEvent函数中,使用QPainter来画出背景、蛇和奖品,并判断蛇是否与奖品或者自己的身体发生了碰撞,如果发生了碰撞,则游戏结束。
在deleteLast函数中,删除蛇的最后一节身体。
在checkContact函数中,判断蛇的身体是否发生了重合,如果发生了重合,则返回true,否则返回false。
在timeout函数中,根据蛇的当前移动方向,生成新的身体部分,并插入到蛇的身体列表的最前面,同时判断蛇的头部是否碰到了奖品,如果碰到了,则增长蛇的身体,并生成一个新的奖品,如果蛇的身体发生了重合,则游戏结束。
一.添加头文件
#include <QKeyEvent>
是 C++ 源代码文件中包含 Qt 库的头文件,用于处理键盘事件。在应用程序中,可以通过重写 QWidget::keyPressEvent()
或 QWidget::keyReleaseEvent()
函数来处理键盘事件。这两个函数的参数都是 QKeyEvent
对象,可以用它来获取键盘事件的详细信息,例如按下或释放的键、键的序号、修饰键等。
#include <QTimer>
是 C++ 源代码文件中包含 Qt 库的头文件,用于创建定时器。QTimer
是 Qt 中用于定时操作的类,可以用来触发特定时间间隔后的操作。通过 QTimer
,可以实现定时执行某些任务、定时更新界面等功能。
#include <QPainter>
是 C++ 源代码文件中包含 Qt 库的头文件,用于绘制图形和图像。QPainter
是 Qt 中用于绘制图形和图像的类,可以用来绘制各种形状、文本、图像等。通过 QPainter
,可以实现自定义绘制、图形界面美化等功能。
二.初始化蛇与奖品
三.设置背景图,蛇与奖品
1.设置背景图
QPixmap pix;pix.load("D://3.jpg");painter.drawPixmap(0,0,600,368,pix);
2.画蛇
创建了一个 QPainter
对象 painter
,并设置了画笔颜色为黑色、画刷颜色为深紫色,填充方式为实心填充。然后,将画笔和画刷设置到 painter
对象中。最后,遍历 snake
数组,绘制每个矩形。
3.画奖品
首先设置了画笔颜色为红色、画刷颜色为深紫色,填充方式为实心填充。然后,将画笔和画刷设置到 painter
对象中。接着,绘制了一个奖品圆形。如果 checkContact()
函数返回 true
,则表示与奖品接触,此时会设置字体为方正舒体,大小为30,加粗,斜体,并绘制游戏结束提示信息。最后,停止计时器,并调用父类的 paintEvent()
函数。
四.小蛇移动
1.控制方向
(1).定义一个 QKeyEvent 指针 event,用于接收键盘事件。
(2).使用 switch 语句根据 event->key() 返回的键值进行不同的操作。
如果按下的是 Qt::Key_Up 键,则判断当前移动方向 moveFlag 是否为 DIR_DOWN,如果不是,则将 moveFlag 设置为 DIR_UP。
如果按下的是 Qt::Key_Down 键,则判断当前移动方向 moveFlag 是否为 DIR_UP,如果不是,则将 moveFlag 设置为 DIR_DOWN。
如果按下的是 Qt::Key_Left 键,则判断当前移动方向 moveFlag 是否为 DIR_RIGHT,如果不是,则将 moveFlag 设置为 DIR_LEFT。
如果按下的是 Qt::Key_Right 键,则判断当前移动方向 moveFlag 是否为 DIR_LEFT,如果不是,则将 moveFlag 设置为 DIR_RIGHT。
如果按下的是 Qt::Key_Space 键,则判断游戏是否已经开始,如果未开始,则将 gameStart 设置为 true,启动定时器 timer,并设置定时器的时间间隔为 time;如果游戏已经开始,则将 gameStart 设置为 false,停止定时器 timer。
如果按下的是其他键,则不做任何操作。
2.向上移动
小蛇向上移动可以看做将最下面的方块删除,在最上方增加一个方块,实现小蛇向上移动。其他方向依照这种逻辑即可。
3.向下移动
4.向右移动
5.向左移动
五.随机生成奖品位置
六.是否吃到奖品
1.定义一个整型变量 count
,初始化为 1。
2.判断蛇的第一个节点 snake[0]
是否与食物 rewardNode
重合,如果重合,则 count
加 1,调用 addNewReward()
函数添加新的食物。
3.使用 while
循环 count
次,根据当前移动方向 moveFlag
的值,分别调用 addTop()
、addDown()
、addLeft()
、addRight()
函数,添加新的蛇节点。
4.调用 deleteLast()
函数删除蛇的最后一个节点。
5.调用 update()
函数更新界面。
七.删除操作
八.游戏结束
检查蛇身是否相撞,标准游戏结束
九.效果演示
十.代码演示
.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QKeyEvent>
#include <QWidget>
#include <QTimer>
#include <QPainter>namespace Ui {
class Widget;
}typedef enum Direct{DIR_LEFT,DIR_RIGHT,DIR_UP,DIR_DOWN
}dir_t;class Widget : public QWidget
{Q_OBJECTpublic:explicit Widget(QWidget *parent = nullptr);~Widget();protected:void keyPressEvent(QKeyEvent *event);void addTop();void addDown();void addRight();void addLeft();void addNewReward();void paintEvent(QPaintEvent *event);void deleteLast();bool checkContact();private:Ui::Widget *ui;dir_t moveFlag = DIR_UP;bool gameStart = false;QTimer *timer;int time = 100;//超时时间间隔//奖品QRectF rewardNode;//蛇QList <QRectF> snake;//小方块的高度int nodeWidth = 20;int nodeHeight = 20;protected slots://定时器void timeout();};#endif // WIDGET_H
.cpp
#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget)
{ui->setupUi(this);//使用定时器timer = new QTimer();//信号槽connect(timer,SIGNAL(timeout()),this,SLOT(timeout()));resize(600,368);//初始化蛇身子QRectF rect(300,180,nodeHeight,nodeWidth);snake.append(rect);addTop();addTop();//初始化奖品addNewReward();
}Widget::~Widget()
{delete ui;
}//控制方向
void Widget::keyPressEvent(QKeyEvent *event)
{switch (event->key()) {case Qt::Key_Up:if(moveFlag != DIR_DOWN){moveFlag = DIR_UP;}break;case Qt::Key_Down:if(moveFlag != DIR_UP){moveFlag = DIR_DOWN;}break;case Qt::Key_Left:if(moveFlag != DIR_RIGHT){moveFlag = DIR_LEFT;}break;case Qt::Key_Right:if(moveFlag != DIR_LEFT){moveFlag = DIR_RIGHT;}break;case Qt::Key_Space:if(gameStart == false){gameStart = true;//启动定时器timer->start(time);}else{gameStart = false;timer->stop();}break;default:break;}
}void Widget::addTop()
{QPointF leftTop;QPointF rightBotom;if(snake[0].y() - nodeHeight < 0){leftTop = QPointF(snake[0].x() , this->height() - nodeHeight);rightBotom = QPointF(snake[0].x() + nodeWidth , this-> height());}else{leftTop = QPointF(snake[0].x(),snake[0].y() - nodeHeight);rightBotom = snake[0].topRight();}snake.insert(0,QRectF(leftTop,rightBotom));
}void Widget::addDown()
{QPointF leftTop;QPointF rightBotom;if(snake[0].y() + nodeHeight * 2 > this -> height()){leftTop = QPointF(snake[0].x() , 0);rightBotom = QPointF(snake[0].x() + nodeWidth , nodeHeight);}else{leftTop = snake[0].bottomLeft();rightBotom = snake[0].bottomRight() + QPointF(0,nodeHeight);}snake.insert(0,QRectF(leftTop,rightBotom));
}void Widget::addRight()
{QPointF leftTop;QPointF rightBotom;if(snake[0].x() + nodeWidth*2 > this->width()){leftTop = QPointF(0,snake[0].y());}else{leftTop = snake[0].topRight();}rightBotom = leftTop + QPointF(nodeWidth,nodeHeight);snake.insert(0,QRectF(leftTop,rightBotom));
}void Widget::addLeft()
{QPointF leftTop;QPointF rightBotom;if(snake[0].x() - nodeWidth < 0){leftTop = QPointF(this->width() - nodeWidth , snake[0].y());}else{leftTop = snake[0].topLeft() - QPointF(nodeWidth,0);}rightBotom = leftTop + QPointF(nodeWidth,nodeHeight);snake.insert(0,QRectF(leftTop,rightBotom));
}void Widget::addNewReward()
{rewardNode = QRectF(qrand()%(this->width()/20) * 20,qrand()%(this->height()/20) * 20,nodeHeight,nodeWidth);
}void Widget::paintEvent(QPaintEvent *event)
{QPainter painter(this);QPen pen;QBrush brush;//背景图QPixmap pix;pix.load("D://3.jpg");painter.drawPixmap(0,0,600,368,pix);//画蛇pen.setColor(Qt::black);brush.setColor(Qt::darkMagenta);brush.setStyle(Qt::SolidPattern);painter.setPen(pen);painter.setBrush(brush);for(int i = 0 ; i < snake.length(); i++){painter.drawRect(snake[i]);}//画奖品pen.setColor(Qt::red);brush.setColor(Qt::darkMagenta);brush.setStyle(Qt::SolidPattern);painter.setPen(pen);painter.setBrush(brush);painter.drawEllipse(rewardNode);if(checkContact()){QFont font("方正舒体",30,QFont::ExtraLight,false);painter.setFont(font);painter.drawText((this->width()-300)/2,(this->height()-30)/2,QString("GAME OVER"));timer->stop();}QWidget::paintEvent(event);
}void Widget::deleteLast()
{snake.removeLast();
}bool Widget::checkContact()
{for(int i=0; i<snake.length() ; i++){for(int j=i+1 ; j<snake.length();j++){if(snake[i] == snake[j]){return true;}}}return false;
}void Widget::timeout()
{int count = 1;//判断是否有重合if(snake[0].intersects(rewardNode)){count++;addNewReward();}while (count--) {switch (moveFlag) {case DIR_UP:addTop();break;case DIR_DOWN:addDown();break;case DIR_LEFT:addLeft();break;case DIR_RIGHT:addRight();break;default:break;}}deleteLast();update();
}