目录
内容介绍
首先,在构造函数中,创建了一个定时器,并设置了信号和槽的连接,这样定时器每次超时时间到达,就会调用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_OBJECT
public:
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();
}