一.项目演示
Greed
二.使用Qt_Creator创建项目名
1.选择Application,创建Qt Widgets Application
然后一直下一步创建完毕
2.渲染游戏大厅界面,如图所示
下方为gamehall.h 期中的paintEvent为虚函数可以进行重写,用于绘制界面
#ifndef GAMEHALL_H
#define GAMEHALL_H
#include <QWidget>
#include<QPainter>
QT_BEGIN_NAMESPACE
namespace Ui { class GameHall; }
QT_END_NAMESPACE
class GameHall : public QWidget
{
Q_OBJECT
public:
GameHall(QWidget *parent = nullptr);
~GameHall();
//重写绘图事件
void paintEvent(QPaintEvent *event);
private:
Ui::GameHall *ui;
};
#endif // GAMEHALL_H
绘制界面时可以创建qrc资源文件如下步骤
将准备好的资源复制粘贴到项目文件中就可以进行使用 更方便一些了
gamehall.cpp中 为窗口设置大小,设置标题,以及图标创建画家实例化,实例绘图,画家记性绘制页面
GameHall::GameHall(QWidget *parent)
: QWidget(parent)
, ui(new Ui::GameHall)
{
ui->setupUi(this);
//设置窗口大小
this->setFixedSize(1000,800);
//设置窗口标题
this->setWindowTitle("贪吃蛇");
//设置窗口图标
this->setWindowIcon(QIcon(":/ico.png"));
//设置字体 大小
QFont font("微软雅黑",24);
}
void GameHall::paintEvent(QPaintEvent *event)
{
//实例化画家
QPainter painter(this);
//QPixmap 实例化绘图设备
QPixmap pix(":/game_hall.png");
//绘画
painter.drawPixmap(0,0,this->width(),this->height(),pix);
}
此时运行一下页面为
因为我们是设置点击有声音效果的打开API 后QSound需要 添加multimedia
3.先添加qmke声音配置
配置完成以后就可以使用QSound 声音效果了
4.添加开始按钮
效果如下
代码如下
//开始游戏按钮
QPushButton*strBtn=new QPushButton(this);
strBtn->setFont(font);
strBtn->setText("开始游戏");//设置开始文字
strBtn->move(430,530);
//取消开始游戏的边框
strBtn->setStyleSheet("QPushButton{border:0px;}");
QPushButton*exitButton=new QPushButton(this);
exitButton->setText("退出游戏");
exitButton->move(430,650);
exitButton->setFont(font);
// 去除边框
exitButton->setStyleSheet("QPushButton{border:0px;}");
5.给开始按钮,退出按钮设置信号槽
开始按钮时我们要跳转到另一个页面,需要新建c++ class类
开始 退出按钮代码如下
GameSelect*gameSelect=new GameSelect;
connect(strBtn,&QPushButton::clicked,[=](){
this->close();
//设置第二个窗口和第一个大小一样
gameSelect->setGeometry(this->geometry());
gameSelect->show();
QSound::play(":clicked.wav");
});
//退出游戏
connect(exitButton,&QPushButton::clicked,[=](){
this->close();
});
点击开始按钮就会跳转到新的页面,点击退出游戏时就关闭游戏 ,下图是点击开始游戏初始页面
三.绘制游戏开始选项页面
1.gameselect.h页面代码
#ifndef GAMESELECT_H
#define GAMESELECT_H
#include <QWidget>
#include<QPainter>
class GameSelect : public QWidget
{
Q_OBJECT
public:
explicit GameSelect(QWidget *parent = nullptr);
void paintEvent(QPaintEvent *event);
signals:
};
#endif // GAMESELECT_H
同gamehall.h 我们绘制页面需要用到paintEvent
2.gamehall.cpp 中 painEvent代码
void GameSelect::paintEvent(QPaintEvent *event)
{
//实例化画家
QPainter painter(this);
//QPixmaap 实例化绘图设备
QPixmap pix(":/game_select.png");
painter.drawPixmap(0,0,this->width(),this->height(),pix);
}
3.设置页面的标题,大小,图标,以及添加各类按钮
//创建返回按钮
QPushButton*backButton=new QPushButton(this);
//设置返回按钮图标
backButton->setIcon(QIcon(":/back.png"));
//设置返回按钮位置
backButton->move(900,720);
QFont font("微软雅黑",23);
QPushButton*simpleButton=new QPushButton(this);
simpleButton->setText("简单模式");
simpleButton->setFont(font);
simpleButton->move(400,150);
QPushButton*normalButton=new QPushButton(this);
normalButton->setText("正常模式");
normalButton->setFont(font);
normalButton->move(400,300);
QPushButton*hardButton=new QPushButton(this);
hardButton->setText("困难模式");
hardButton->setFont(font);
hardButton->move(400,500);
QPushButton*historyButton=new QPushButton(this);
historyButton->setText("历史战绩");
historyButton->setFont(font);
historyButton->move(400,700);
4.目前运行程序如图所示
5.给右下角返回按钮添加信号槽机制,点击就返回第一个页面
connect(backButton,&QPushButton::clicked,[=](){
this->close();
QSound::play(":/clicked.wav");
GameHall*gamehall=new GameHall();
gamehall->show();
});
6.创建第三个页面游戏房间页面,当点击模式后进入房间
四.绘制游戏房间
1.gameroom.h代码如下
#ifndef GAMEROOM_H
#define GAMEROOM_H
#include<QPainter>
#include <QObject>
#include <QWidget>
#include<QTimer>
#include<QList>
#include<QSound>
enum class SnakeDirect{//枚举设置蛇的方向
UP=0,
DOWN,
LEFT,
RIGHT
};
class GameRoom : public QWidget
{
Q_OBJECT
public:
explicit GameRoom(QWidget *parent = nullptr);
void paintEvent(QPaintEvent *event);//重新绘画事件
void moveup();//向上移动
void moveDown();//蛇向下移动
void moveLeft();//向左移动
void moveRight();//向右移动
bool checkFail();//判断游戏是否结束
void createNewFood();//食物创建
void setTimeOut(int timeout){
moveTimeOut=timeout;
}
signals:
private:
const int KSnakeNodeWidth=20;//表示蛇身体节点的宽度
const int kSnakeNodeHeight=20;//表示蛇身体节点的高度
const int KDefaultTimeout=200;//蛇默认移动速度
QList<QRectF>snakeList;
QRectF foodRect;//表示食物节点
SnakeDirect moveDirect=SnakeDirect::UP;//设置蛇的默认方向上
QTimer*timer;//定时器
QSound *sound;
bool isGameStart=false;//表示是否可以开始游戏
int moveTimeOut=KDefaultTimeout;
};
#endif // GAMEROOM_H
1.首先设置大小,窗口标题,设置划分区域,渲染游戏页面
void GameRoom::paintEvent(QPaintEvent *event)
{
//实例化画家
QPainter painter(this);
//QPixmap
QPixmap pix;
pix.load(":/heiwukong.png");
painter.drawPixmap(0,0,800,800,pix);
pix.load(":/bg1.png");
painter.drawPixmap(800,0,200,900,pix);}
GameRoom::GameRoom(QWidget *parent) : QWidget(parent)
{
this->setWindowTitle("游戏页面");//设置标题
this->setWindowIcon(QIcon(":/ico.png"));//设置图标
this->setFixedSize(1000,800);}
2.向上移动的实现
void GameRoom::moveup()
{
QPointF leftTop;//左上角坐标
QPointF rightBottom;//右下角坐标
auto snakeNode=snakeList.front();//头
int headX=snakeNode.x();
int headY=snakeNode.y();
if(headY<0)//穿墙
{
leftTop=QPointF(headX,this->height()-kSnakeNodeHeight);
}else//无穿墙
{
leftTop=QPointF(headX,headY-kSnakeNodeHeight);
}
rightBottom=leftTop+QPointF(KSnakeNodeWidth,kSnakeNodeHeight);
snakeList.push_front(QRectF(leftTop,rightBottom));//节点更新到链表中
//snakeList.push_back(QRectF(leftTop,rightBottom));
}
3.向下移动的实现
void GameRoom::moveDown()
{
QPointF leftTop;
QPointF rightBottom;
auto snakeNode=snakeList.front();
int headX=snakeNode.x();
int headY=snakeNode.y();
if(headY>this->height())
{
leftTop=QPointF(headX,0);
}else
{
leftTop=snakeNode.bottomLeft();
}
rightBottom=leftTop+QPointF(KSnakeNodeWidth,kSnakeNodeHeight);
snakeList.push_front(QRectF(leftTop,rightBottom));
}
4.向左移动的实现
void GameRoom::moveLeft()
{
QPointF leftTop;
QPointF rightBottom;
auto snakeNode=snakeList.front();
int headX=snakeNode.x();
int headY=snakeNode.y();
if(headX<0)
{
leftTop=QPointF(800-KSnakeNodeWidth,headY);
}else
{
leftTop=QPointF(headX-KSnakeNodeWidth,headY);
}
rightBottom=leftTop+QPointF(KSnakeNodeWidth,kSnakeNodeHeight);
snakeList.push_front(QRectF(leftTop,rightBottom));
}
5.向右移动的实现
void GameRoom::moveRight()
{
QPointF leftTop;//左上角坐标
QPointF rightBottom;//右下角坐标
auto snakeNode=snakeList.front();
int headX=snakeNode.x();
int headY=snakeNode.y();
if(headX+KSnakeNodeWidth>780)
{
leftTop=QPointF(0,headY);
}else
{
leftTop=snakeNode.topRight();
}
rightBottom=leftTop+QPointF(KSnakeNodeWidth,kSnakeNodeHeight);
snakeList.push_front(QRectF(leftTop,rightBottom));
}
6.判断游戏是否结束
当蛇身之间互相碰撞时,即蛇身上的节点重合时游戏结束
bool GameRoom::checkFail()
{
for(int i=0;i<snakeList.size();i++)
{
for(int j=i+1;j<snakeList.size();j++)
{
//获取两个节点的位置 如果相同为true结束游戏
if(snakeList.at(i)==snakeList.at(j))
{
return true;
}
}
}
return false;
}
7.渲染贪吃蛇
//加载蛇头的资源文件
if(moveDirect==SnakeDirect::UP)
{
pix.load(":/up.png");
}else if(moveDirect==SnakeDirect::DOWN)
{
pix.load(":/down.png");
}else if(moveDirect==SnakeDirect::LEFT)
{
pix.load(":/left.png");
}else if(moveDirect==SnakeDirect::RIGHT)
{
pix.load(":/right.png");
}
auto snakeHead=snakeList.front();//获取蛇头节点
painter.drawPixmap(snakeHead.x(),snakeHead.y(),snakeHead.width(),snakeHead.height(),pix);
//绘制蛇身
pix.load(":/Bd.png");
for(int i=1;i<snakeList.size()-1;i++)
{
auto node=snakeList.at(i);
painter.drawPixmap(node.x(),node.y(),node.width(),node.height(),pix);
}
//绘制蛇的尾巴
auto snakeTaile=snakeList.back();
painter.drawPixmap(snakeTaile.x(),snakeTaile.y(),snakeTaile.width(),snakeTaile.height(),pix);
8.初始化贪吃蛇
在GameRoom::GameRoom(QWidget *parent) : QWidget(parent)中
//初始化贪吃蛇
snakeList.push_back(QRectF(this->width()*0.5,(this->height()/2),KSnakeNodeWidth,kSnakeNodeHeight));
moveup();
moveup();
9.渲染食物
void GameRoom::createNewFood()
{
foodRect=QRectF(qrand()%(800/KSnakeNodeWidth)*KSnakeNodeWidth,
qrand()%(this->height()/kSnakeNodeHeight)*kSnakeNodeHeight,
KSnakeNodeWidth,
kSnakeNodeHeight);
}
10.当吃上食物时增添一个节点并删除最后节点
//创建食物
createNewFood();
timer=new QTimer(this);
connect(timer,&QTimer::timeout,[=](){
int cnt=1;
if(snakeList.front().intersects(foodRect))//判断两个矩形 食物和蛇头会不会相交
{
createNewFood();
cnt++;//统计相交的次数
QSound::play(":/eatfood.wav");
}
while(cnt--)
{
switch(moveDirect)
{
case SnakeDirect::UP:
moveup();
break;
case SnakeDirect::DOWN:
moveDown();
break;
case SnakeDirect::LEFT:
moveLeft();
break;
case SnakeDirect::RIGHT:
moveRight();
break;
}
}
snakeList.pop_back();//删除最后一个节点
update();//更新链表
});
11.设置开始 和 停止按钮
QPushButton*startButton=new QPushButton(this);
QPushButton*stopButton=new QPushButton(this);
startButton->move(860,150);
startButton->setText("开始");
stopButton->move(860,240);
stopButton->setText("停止");
//startButton->setStyleSheet("QPushButton{border:0px}");
//stopButton->setStyleSheet("QPushButton{border:0px}");
QFont font("微软雅黑",20);
startButton->setFont(font);
stopButton->setFont(font);
sound=new QSound(":/taicongming.wav");
connect(startButton,&QPushButton::clicked,[=](){
isGameStart=true;
timer->start(moveTimeOut);
sound->play();
sound->setLoops(-1);//为真一直播放
});
//停止
connect(stopButton,&QPushButton::clicked,[=](){
isGameStart=false;
timer->stop();
sound->stop();
});
12.设置四个方向按钮控制蛇的移动
//方向控制
QPushButton*up=new QPushButton(this);
QPushButton*down=new QPushButton(this);
QPushButton*left=new QPushButton(this);
QPushButton*right=new QPushButton(this);
up->move(880,400);
down->move(880,500);
left->move(840,450);
right->move(920,450);
up->setText("↑");
down->setText("↓");
left->setText("←");
right->setText("→");
up->setStyleSheet("QPushButton{border:0px}");
down->setStyleSheet("QPushButton{border:0px}");
left->setStyleSheet("QPushButton{border:0px}");
right->setStyleSheet("QPushButton{border:0px}");
QFont ft("黑体",35);
up->setFont(ft);
down->setFont(ft);
left->setFont(ft);
right->setFont(ft);
//规定上箭头
connect(up,&QPushButton::clicked,[=](){
if(moveDirect!=SnakeDirect::DOWN)
{
moveDirect=SnakeDirect::UP;
}
});
//规定下箭头
connect(down,&QPushButton::clicked,[=](){
if(moveDirect!=SnakeDirect::UP)
{
moveDirect=SnakeDirect::DOWN;
}
});
//规定左箭头
connect(left,&QPushButton::clicked,[=](){
if(moveDirect!=SnakeDirect::RIGHT)
{
moveDirect=SnakeDirect::LEFT;
}
});
//规定右箭头
connect(right,&QPushButton::clicked,[=](){
if(moveDirect!=SnakeDirect::LEFT)
{
moveDirect=SnakeDirect::RIGHT;
}
});
13.设置退出游戏按钮,弹出消息框
//设置退出按钮
QPushButton*exitButton=new QPushButton(this);
exitButton->setText("退出游戏");
exitButton->setFont(font);
exitButton->move(830,700);
//设置消息弹出框
QMessageBox*messageBox=new QMessageBox(this);
QPushButton*ok=new QPushButton("ok");
QPushButton*cancel=new QPushButton("cancel");
//按钮添加到消息盒子
messageBox->addButton(ok,QMessageBox::AcceptRole);
messageBox->addButton(cancel,QMessageBox::RejectRole);
messageBox->setWindowTitle("退出游戏");
messageBox->setText("确认退出游戏吗?????");
connect(exitButton,&QPushButton::clicked,[=](){
isGameStart=false;
timer->stop();
sound->stop();
messageBox->show();
messageBox->exec();//事件轮询
QSound::play(":/clicked.wav");
GameSelect*select=new GameSelect;
if(messageBox->clickedButton()==ok)
{
this->close();
select->show();
}else
{
messageBox->close();
}
});
如图所示
14.渲染积分以及失败效果
//绘制分数
pix.load(":/sorce_bg.png");
painter.drawPixmap(this->width()*0.85,this->height()*0.06,90,40,pix);
//画笔
QPen pen;
pen.setColor(Qt::black);
painter.setPen(pen);
QFont font("方正舒体",22);
painter.setFont(font);
painter.drawText(this->width()*0.9,this->height()*0.1,QString("%1").arg(snakeList.size()));
//往文件里面写入分数
int score=snakeList.size();
QFile file("D:/SSNNake/1.txt");
if(file.open(QIODevice::WriteOnly|QIODevice::Text))//判断是否打开了
{
QTextStream out(&file);
int num=score;
out<<num;
file.close();
}
//渲染绘制失败效果
if(checkFail())
{
pen.setColor(Qt::red);
painter.setPen(pen);
QFont font1("方正舒体",50);
painter.setFont(font1);
painter.drawText(this->width()*0.25,this->height()*0.5,
QString("GAME OVEER!"));
timer->stop();
sound->stop();
int count=1;
while(count--)
{
QSound::play(":/nizaibuzai.wav");
}
}
15.设置三种不同的模式难度
回到gameselect.cpp中
connect(simpleButton,&QPushButton::clicked,[this](){
this->close();
GameRoom *gameroom=new GameRoom;
gameroom->show();
gameroom->setGeometry(this->geometry());
QSound::play(":/clicked.wav");
gameroom->setTimeOut(350);
});
connect(normalButton,&QPushButton::clicked,[=](){
this->close();
GameRoom *gameroom=new GameRoom;
gameroom->show();
gameroom->setGeometry(this->geometry());
QSound::play(":/clicked.wav");
gameroom->setTimeOut(300);
});
connect(hardButton,&QPushButton::clicked,[=](){
this->close();
GameRoom *gameroom=new GameRoom;
gameroom->show();
gameroom->setGeometry(this->geometry());
QSound::play(":/clicked.wav");
gameroom->setTimeOut(200);
});
16.网文件写入历史战绩,并打开文件获取历史战绩
connect(historyButton,&QPushButton::clicked,[=](){
QWidget*widget=new QWidget();
widget->setWindowTitle("历史战绩");
//设置窗口大小
widget->setFixedSize(500,300);
QTextEdit*edit=new QTextEdit(widget);
edit->setFont(font);
edit->setFixedSize(500,300);
QFile file("D:/SSNNake/1.txt");
file.open(QIODevice::ReadOnly);
QTextStream in(&file);
//读取历史战绩 将读出的字符串转化成int
// int data=in.readLine().toInt();
//追加历史战绩 将 int类型转化成 字符串String
// edit->append(QString::number(data));
edit->append("得分为:");
edit->append(in.readLine());
widget->show();
});
写入历史战绩
//往文件里面写入分数
int score=snakeList.size();
QFile file("D:/SSNNake/1.txt");
if(file.open(QIODevice::WriteOnly|QIODevice::Text))//判断是否打开了
{
QTextStream out(&file);
int num=score;
out<<num;
file.close();
}
五.全部代码
gamehall.h
#ifndef GAMEHALL_H
#define GAMEHALL_H
#include <QWidget>
#include<QPainter>
QT_BEGIN_NAMESPACE
namespace Ui { class GameHall; }
QT_END_NAMESPACE
class GameHall : public QWidget
{
Q_OBJECT
public:
GameHall(QWidget *parent = nullptr);
~GameHall();
//重写绘图事件
void paintEvent(QPaintEvent *event);
private:
Ui::GameHall *ui;
};
#endif // GAMEHALL_H
gamehall.cpp
#include "gamehall.h"
#include "ui_gamehall.h"
#include<QPixmap>
#include<QPainter>
#include<QIcon>
#include<gameselect.h>
#include<QPushButton>
#include<QLabel>
#include<QFont>
#include<QSound>
GameHall::GameHall(QWidget *parent)
: QWidget(parent)
, ui(new Ui::GameHall)
{
ui->setupUi(this);
//设置窗口大小
this->setFixedSize(1000,800);
//设置窗口标题
this->setWindowTitle("贪吃蛇");
//设置窗口图标
this->setWindowIcon(QIcon(":/ico.png"));
//设置字体 大小
QFont font("微软雅黑",24);
//开始游戏按钮
QPushButton*strBtn=new QPushButton(this);
strBtn->setFont(font);
strBtn->setText("开始游戏");//设置开始文字
strBtn->move(430,530);
//取消开始游戏的边框
strBtn->setStyleSheet("QPushButton{border:0px;}");
//跳转到第二个窗口
GameSelect*gameSelect=new GameSelect;
connect(strBtn,&QPushButton::clicked,[=](){
this->close();
//设置第二个窗口和第一个大小一样
// gameSelect->setGeometry(this->geometry());
gameSelect->show();
QSound::play(":clicked.wav");
});
//退出游戏
QPushButton*exitButton=new QPushButton(this);
exitButton->setText("退出游戏");
exitButton->move(430,650);
exitButton->setFont(font);
// 去除边框
exitButton->setStyleSheet("QPushButton{border:0px;}");
connect(exitButton,&QPushButton::clicked,[=](){
//关闭是没有声音的
//QSound::play(":clicked.wav");
this->close();
});
}
GameHall::~GameHall()
{
delete ui;
}
void GameHall::paintEvent(QPaintEvent *event)
{
//实例化画家
QPainter painter(this);
//QPixmap 实例化绘图设备
QPixmap pix(":/game_hall.png");
//绘画
painter.drawPixmap(0,0,this->width(),this->height(),pix);
}
gameselect.h
#ifndef GAMESELECT_H
#define GAMESELECT_H
#include <QWidget>
#include<QPainter>
class GameSelect : public QWidget
{
Q_OBJECT
public:
explicit GameSelect(QWidget *parent = nullptr);
void paintEvent(QPaintEvent *event);
signals:
};
#endif // GAMESELECT_H
gameselect .cpp
#include "gameselect.h"
#include"gamehall.h"
#include<QIcon>
#include<QPushButton>
#include<QSound>
#include<QPixmap>
#include<QFont>
#include"gameroom.h"
#include<QTextEdit>
#include<QFile>
#include<QTextStream>
GameSelect::GameSelect(QWidget *parent) : QWidget(parent)
{
//设置窗口大小
this->setFixedSize(1000,800);
//设置窗口标题
this->setWindowTitle("游戏选择关卡");
//设置窗口图标
this->setWindowIcon(QIcon(":/ico.png"));
//创建返回按钮
QPushButton*backButton=new QPushButton(this);
//设置返回按钮图标
backButton->setIcon(QIcon(":/back.png"));
//设置返回按钮位置
backButton->move(900,720);
connect(backButton,&QPushButton::clicked,[=](){
this->close();
QSound::play(":/clicked.wav");
GameHall*gamehall=new GameHall();
gamehall->show();
});
QFont font("微软雅黑",23);
QPushButton*simpleButton=new QPushButton(this);
simpleButton->setText("简单模式");
simpleButton->setFont(font);
simpleButton->move(400,150);
QPushButton*normalButton=new QPushButton(this);
normalButton->setText("正常模式");
normalButton->setFont(font);
normalButton->move(400,300);
QPushButton*hardButton=new QPushButton(this);
hardButton->setText("困难模式");
hardButton->setFont(font);
hardButton->move(400,500);
connect(simpleButton,&QPushButton::clicked,[this](){
this->close();
GameRoom *gameroom=new GameRoom;
gameroom->show();
gameroom->setGeometry(this->geometry());
QSound::play(":/clicked.wav");
gameroom->setTimeOut(350);
});
connect(normalButton,&QPushButton::clicked,[=](){
this->close();
GameRoom *gameroom=new GameRoom;
gameroom->show();
gameroom->setGeometry(this->geometry());
QSound::play(":/clicked.wav");
gameroom->setTimeOut(300);
});
connect(hardButton,&QPushButton::clicked,[=](){
this->close();
GameRoom *gameroom=new GameRoom;
gameroom->show();
gameroom->setGeometry(this->geometry());
QSound::play(":/clicked.wav");
gameroom->setTimeOut(200);
});
QPushButton*historyButton=new QPushButton(this);
historyButton->setText("历史战绩");
historyButton->setFont(font);
historyButton->move(400,700);
connect(historyButton,&QPushButton::clicked,[=](){
QWidget*widget=new QWidget();
widget->setWindowTitle("历史战绩");
//设置窗口大小
widget->setFixedSize(500,300);
QTextEdit*edit=new QTextEdit(widget);
edit->setFont(font);
edit->setFixedSize(500,300);
QFile file("D:/SSNNake/1.txt");
file.open(QIODevice::ReadOnly);
QTextStream in(&file);
//读取历史战绩 将读出的字符串转化成int
// int data=in.readLine().toInt();
//追加历史战绩 将 int类型转化成 字符串String
// edit->append(QString::number(data));
edit->append("得分为:");
edit->append(in.readLine());
widget->show();
});
}
void GameSelect::paintEvent(QPaintEvent *event)
{
//实例化画家
QPainter painter(this);
//QPixmaap 实例化绘图设备
//QPixmap pix(":/game_select.png");
QPixmap pix(":/danzai.png");
painter.drawPixmap(0,0,this->width(),this->height(),pix);
}
gameroom.h
#ifndef GAMEROOM_H
#define GAMEROOM_H
#include<QPainter>
#include <QObject>
#include <QWidget>
#include<QTimer>
#include<QList>
#include<QSound>
enum class SnakeDirect{//枚举设置蛇的方向
UP=0,
DOWN,
LEFT,
RIGHT
};
class GameRoom : public QWidget
{
Q_OBJECT
public:
explicit GameRoom(QWidget *parent = nullptr);
void paintEvent(QPaintEvent *event);//重新绘画事件
void moveup();//向上移动
void moveDown();//蛇向下移动
void moveLeft();//向左移动
void moveRight();//向右移动
bool checkFail();//判断游戏是否结束
void createNewFood();//食物创建
void setTimeOut(int timeout){
moveTimeOut=timeout;
}
signals:
private:
const int KSnakeNodeWidth=20;//表示蛇身体节点的宽度
const int kSnakeNodeHeight=20;//表示蛇身体节点的高度
const int KDefaultTimeout=200;//蛇默认移动速度
QList<QRectF>snakeList;
QRectF foodRect;//表示食物节点
SnakeDirect moveDirect=SnakeDirect::UP;//设置蛇的默认方向上
QTimer*timer;//定时器
QSound *sound;
bool isGameStart=false;//表示是否可以开始游戏
int moveTimeOut=KDefaultTimeout;
};
#endif // GAMEROOM_H
gameroom.cpp
#include "gameroom.h"
#include<QIcon>
#include<QPixmap>
#include<QTimer>
#include<QPushButton>
#include<QFont>
#include<QSound>
#include<QMessageBox>
#include<QFile>
#include<QTextStream>
#include"gameselect.h"
GameRoom::GameRoom(QWidget *parent) : QWidget(parent)
{
this->setWindowTitle("游戏页面");//设置标题
this->setWindowIcon(QIcon(":/ico.png"));//设置图标
this->setFixedSize(1000,800);
//初始化贪吃蛇
snakeList.push_back(QRectF(this->width()*0.5,(this->height()/2),KSnakeNodeWidth,kSnakeNodeHeight));
moveup();
moveup();
//创建食物
createNewFood();
timer=new QTimer(this);
connect(timer,&QTimer::timeout,[=](){
int cnt=1;
if(snakeList.front().intersects(foodRect))//判断两个矩形 食物和蛇头会不会相交
{
createNewFood();
cnt++;//统计相交的次数
QSound::play(":/eatfood.wav");
}
while(cnt--)
{
switch(moveDirect)
{
case SnakeDirect::UP:
moveup();
break;
case SnakeDirect::DOWN:
moveDown();
break;
case SnakeDirect::LEFT:
moveLeft();
break;
case SnakeDirect::RIGHT:
moveRight();
break;
}
}
snakeList.pop_back();//删除最后一个节点
update();//更新链表
});
QPushButton*startButton=new QPushButton(this);
QPushButton*stopButton=new QPushButton(this);
startButton->move(860,150);
startButton->setText("开始");
stopButton->move(860,240);
stopButton->setText("停止");
//startButton->setStyleSheet("QPushButton{border:0px}");
//stopButton->setStyleSheet("QPushButton{border:0px}");
QFont font("微软雅黑",20);
startButton->setFont(font);
stopButton->setFont(font);
sound=new QSound(":/taicongming.wav");
connect(startButton,&QPushButton::clicked,[=](){
isGameStart=true;
timer->start(moveTimeOut);
sound->play();
sound->setLoops(-1);//为真一直播放
});
//停止
connect(stopButton,&QPushButton::clicked,[=](){
isGameStart=false;
timer->stop();
sound->stop();
});
//方向控制
QPushButton*up=new QPushButton(this);
QPushButton*down=new QPushButton(this);
QPushButton*left=new QPushButton(this);
QPushButton*right=new QPushButton(this);
up->move(880,400);
down->move(880,500);
left->move(840,450);
right->move(920,450);
up->setText("↑");
down->setText("↓");
left->setText("←");
right->setText("→");
up->setStyleSheet("QPushButton{border:0px}");
down->setStyleSheet("QPushButton{border:0px}");
left->setStyleSheet("QPushButton{border:0px}");
right->setStyleSheet("QPushButton{border:0px}");
QFont ft("黑体",35);
up->setFont(ft);
down->setFont(ft);
left->setFont(ft);
right->setFont(ft);
//规定上箭头
connect(up,&QPushButton::clicked,[=](){
if(moveDirect!=SnakeDirect::DOWN)
{
moveDirect=SnakeDirect::UP;
}
});
//规定下箭头
connect(down,&QPushButton::clicked,[=](){
if(moveDirect!=SnakeDirect::UP)
{
moveDirect=SnakeDirect::DOWN;
}
});
//规定左箭头
connect(left,&QPushButton::clicked,[=](){
if(moveDirect!=SnakeDirect::RIGHT)
{
moveDirect=SnakeDirect::LEFT;
}
});
//规定右箭头
connect(right,&QPushButton::clicked,[=](){
if(moveDirect!=SnakeDirect::LEFT)
{
moveDirect=SnakeDirect::RIGHT;
}
});
//设置退出按钮
QPushButton*exitButton=new QPushButton(this);
exitButton->setText("退出游戏");
exitButton->setFont(font);
exitButton->move(830,700);
//设置消息弹出框
QMessageBox*messageBox=new QMessageBox(this);
QPushButton*ok=new QPushButton("ok");
QPushButton*cancel=new QPushButton("cancel");
//按钮添加到消息盒子
messageBox->addButton(ok,QMessageBox::AcceptRole);
messageBox->addButton(cancel,QMessageBox::RejectRole);
messageBox->setWindowTitle("退出游戏");
messageBox->setText("确认退出游戏吗?????");
connect(exitButton,&QPushButton::clicked,[=](){
isGameStart=false;
timer->stop();
sound->stop();
messageBox->show();
messageBox->exec();//事件轮询
QSound::play(":/clicked.wav");
GameSelect*select=new GameSelect;
if(messageBox->clickedButton()==ok)
{
this->close();
select->show();
}else
{
messageBox->close();
}
});
}
void GameRoom::paintEvent(QPaintEvent *event)
{
//实例化画家
QPainter painter(this);
//QPixmap
QPixmap pix;
pix.load(":/heiwukong.png");
painter.drawPixmap(0,0,800,800,pix);
pix.load(":/bg1.png");
painter.drawPixmap(800,0,200,900,pix);
//加载蛇头的资源文件
if(moveDirect==SnakeDirect::UP)
{
pix.load(":/up.png");
}else if(moveDirect==SnakeDirect::DOWN)
{
pix.load(":/down.png");
}else if(moveDirect==SnakeDirect::LEFT)
{
pix.load(":/left.png");
}else if(moveDirect==SnakeDirect::RIGHT)
{
pix.load(":/right.png");
}
auto snakeHead=snakeList.front();//获取蛇头节点
painter.drawPixmap(snakeHead.x(),snakeHead.y(),snakeHead.width(),snakeHead.height(),pix);
//绘制蛇身
pix.load(":/Bd.png");
for(int i=1;i<snakeList.size()-1;i++)
{
auto node=snakeList.at(i);
painter.drawPixmap(node.x(),node.y(),node.width(),node.height(),pix);
}
//个人感觉无所谓这一点
//绘制蛇的尾巴
auto snakeTaile=snakeList.back();
painter.drawPixmap(snakeTaile.x(),snakeTaile.y(),snakeTaile.width(),snakeTaile.height(),pix);
//绘制食物
pix.load(":/food.bmp");
painter.drawPixmap(foodRect.x(),foodRect.y(),foodRect.width(),foodRect.height(),pix);
//绘制分数
pix.load(":/sorce_bg.png");
painter.drawPixmap(this->width()*0.85,this->height()*0.06,90,40,pix);
//画笔
QPen pen;
pen.setColor(Qt::black);
painter.setPen(pen);
QFont font("方正舒体",22);
painter.setFont(font);
painter.drawText(this->width()*0.9,this->height()*0.1,QString("%1").arg(snakeList.size()));
//往文件里面写入分数
int score=snakeList.size();
QFile file("D:/SSNNake/1.txt");
if(file.open(QIODevice::WriteOnly|QIODevice::Text))//判断是否打开了
{
QTextStream out(&file);
int num=score;
out<<num;
file.close();
}
//渲染绘制失败效果
if(checkFail())
{
pen.setColor(Qt::red);
painter.setPen(pen);
QFont font1("方正舒体",50);
painter.setFont(font1);
painter.drawText(this->width()*0.25,this->height()*0.5,
QString("GAME OVEER!"));
timer->stop();
sound->stop();
int count=1;
while(count--)
{
QSound::play(":/nizaibuzai.wav");
}
}
}
void GameRoom::moveup()
{
QPointF leftTop;//左上角坐标
QPointF rightBottom;//右下角坐标
auto snakeNode=snakeList.front();//头
int headX=snakeNode.x();
int headY=snakeNode.y();
if(headY<0)//穿墙了
{
leftTop=QPointF(headX,this->height()-kSnakeNodeHeight);
}else//无穿墙
{
leftTop=QPointF(headX,headY-kSnakeNodeHeight);
}
rightBottom=leftTop+QPointF(KSnakeNodeWidth,kSnakeNodeHeight);
snakeList.push_front(QRectF(leftTop,rightBottom));//节点更新到链表中
//snakeList.push_back(QRectF(leftTop,rightBottom));
}
void GameRoom::moveDown()
{
QPointF leftTop;
QPointF rightBottom;
auto snakeNode=snakeList.front();
int headX=snakeNode.x();
int headY=snakeNode.y();
if(headY>this->height())
{
leftTop=QPointF(headX,0);
}else
{
leftTop=snakeNode.bottomLeft();
}
rightBottom=leftTop+QPointF(KSnakeNodeWidth,kSnakeNodeHeight);
snakeList.push_front(QRectF(leftTop,rightBottom));
}
void GameRoom::moveLeft()
{
QPointF leftTop;
QPointF rightBottom;
auto snakeNode=snakeList.front();
int headX=snakeNode.x();
int headY=snakeNode.y();
if(headX<0)
{
leftTop=QPointF(800-KSnakeNodeWidth,headY);
}else
{
leftTop=QPointF(headX-KSnakeNodeWidth,headY);
}
rightBottom=leftTop+QPointF(KSnakeNodeWidth,kSnakeNodeHeight);
snakeList.push_front(QRectF(leftTop,rightBottom));
}
void GameRoom::moveRight()
{
QPointF leftTop;//左上角坐标
QPointF rightBottom;//右下角坐标
auto snakeNode=snakeList.front();
int headX=snakeNode.x();
int headY=snakeNode.y();
if(headX+KSnakeNodeWidth>780)
{
//我理解的
//leftTop=QPointF(KSnakeNodeWidth,headY);
//他写的
leftTop=QPointF(0,headY);
}else
{
//我理解的
//leftTop=QPointF(KSnakeNodeWidth+headX,headY);
//他写的
leftTop=snakeNode.topRight();
}
rightBottom=leftTop+QPointF(KSnakeNodeWidth,kSnakeNodeHeight);
snakeList.push_front(QRectF(leftTop,rightBottom));
}
bool GameRoom::checkFail()
{
for(int i=0;i<snakeList.size();i++)
{
for(int j=i+1;j<snakeList.size();j++)
{
//获取两个节点的位置 如果相同为true结束游戏
if(snakeList.at(i)==snakeList.at(j))
{
return true;
}
}
}
return false;
}
void GameRoom::createNewFood()
{
//看不懂生成的随机数 不知道你想做什么
foodRect=QRectF(qrand()%(800/KSnakeNodeWidth)*KSnakeNodeWidth,
qrand()%(this->height()/kSnakeNodeHeight)*kSnakeNodeHeight,
KSnakeNodeWidth,
kSnakeNodeHeight);
}