贪吃蛇
创建项目时使用QWidget,项目名随意,
首先各种类的生命
1.贪吃蛇本体使用小方块来代替
2.使用QList类来保存贪吃蛇的本体
3.使用定时器来设定奖励以及贪吃蛇本体的刷新时间
4.使用随机函数,来在屏幕上随机生成奖励节点
5.使用keyPressEvent来监控按键的按下,控制贪吃蛇的移动
6.通过添加新文件QDialog实现登录界面
登录界面实现
dialog.h文件
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QMessageBox>
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
private slots:
void on_login_clicked();
void on_Exit_clicked();
private:
Ui::Dialog *ui;
};
#endif // DIALOG_H
dialog.cpp文件
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
this->setWindowTitle("GreedySnake!");
ui->passwordline->setEchoMode(QLineEdit::Password);
}
Dialog::~Dialog()
{
delete ui;
}
void Dialog::on_login_clicked()
{
if(ui->nameline->text().trimmed() == "Baiyang" && ui->passwordline->text() == "123456")//登录用户名和密码可自行修改
{
this->accept();
}
else
{
QMessageBox::warning(this,tr("警告!"),tr("用户名或密码错误!"),QMessageBox::Yes);
ui->nameline->clear();
ui->passwordline->clear();
ui->nameline->setFocus();
}
}
void Dialog::on_Exit_clicked()
{
reject();
Dialog::close();
}
修改main.cpp如下
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Dialog dialog;
if(dialog.exec() == QDialog::Rejected)
return 0;
Widget w;
w.show();
return a.exec();
}
注:修改main函数是为了通过dialog界面,也就是登录界面来判断是否打开游戏界面
dialog.ui设计
注:图中控件的名字和text内容自行修改
注:Widget的ui界面通过代码去实现,所以不用自行设计
Widget.h声明
#ifndef WIDGET_H
#define WIDGET_H
#include "dialog.h"
#include <QWidget>
#include <QKeyEvent>
#include <QPen>
#include <QBrush>
#include <QRectF>
#include <QPainter>
#include <QDebug>
#include <QTime>
#include <QTimer>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
protected:
void paintEvent(QPaintEvent *);
void keyPressEvent(QKeyEvent *);
private:
void TopRectF();
void DownRectF();
void LeftRectF();
void RightRectF();
void deleteLastRectF();
bool snakeStrike();
enum Move{Left,Right,Up,Down};
protected slots:
void timeOut();
void rewardTimeOut();
private:
Ui::Widget *ui;
QList<QRectF>rewardNode;
QList<QRectF>snake;
int snakeNodeWidth = 10;
int snakeNodeHeight = 10;
QTimer *timer;
QTimer *rewardTimer;
int time = 100;
int moveFlog = Up;
bool gameOver = false;
bool gameStart = false;
};
#endif // WIDGET_H
Widget类函数的实现
构造函数
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
resize(500,500);
setStyleSheet("QWidget{background:black}");
setWindowOpacity(0.8);
snake.append(QRectF(200,500,snakeNodeWidth,snakeNodeHeight));
TopRectF();
rewardNode.append(QRectF(qrand()%(this->width()/20)*20,qrand()%(this->height()/20)*20,snakeNodeWidth,snakeNodeWidth));
timer = new QTimer;
connect(timer,SIGNAL(timeout()),this,SLOT(timeOut()));
rewardTimer = new QTimer;
connect(rewardTimer,SIGNAL(timeout()),this,SLOT(rewardTimeOut()));
}
Widget::~Widget()
{
delete ui;
}
奖励节点与贪吃蛇本体刷新
void Widget::timeOut()
{
int flage = 1;
for(int i=0;i<rewardNode.length();i++)
{
if(rewardNode.at(i).contains(snake.at(0).topLeft()+QPointF(snakeNodeWidth/2,snakeNodeHeight/2)))
{
if(rewardNode.at(i).width()>snakeNodeWidth)
flage += 2;
flage++;
rewardNode.removeAt(i);
break;
}
}
while(flage--)
{
switch (moveFlog) {
case Up:
TopRectF();
break;
case Down:
DownRectF();
break;
case Left:
LeftRectF();
break;
case Right:
RightRectF();
break;
default:
break;
}
}
deleteLastRectF();
update();
}
void Widget::rewardTimeOut()
{
qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
if(rewardNode.length() > 5)
rewardNode.removeAt(qrand()%5);
rewardNode.append(QRectF(qrand()%(this->width()/20)*20,qrand()%(this->height()/20)*20,snakeNodeWidth,snakeNodeWidth));
if(qrand()%5 == 3)
rewardNode.append(QRectF(qrand()%(this->width()/20)*20-5,qrand()%(this->height()/20)*20-5,snakeNodeWidth*2,snakeNodeWidth*2));
}
向上移动
void Widget::TopRectF()
{
if(snake.at(0).y()-snakeNodeHeight < 0)
{
snake.insert(0,QRectF(QPointF(snake.at(0).x(),this->height()-snakeNodeHeight),QPointF(snake.at(0).x()+snakeNodeWidth,this->height())));
}
else
{
snake.insert(0,QRectF(snake.at(0).topLeft()+QPointF(0,-snakeNodeHeight),snake.at(0).topRight()));
}
}
向下移动
void Widget::DownRectF()
{
if(snake.at(0).y()+snakeNodeHeight*2 > this->height())
{
snake.insert(0,QRectF(QPointF(snake.at(0).x(),snakeNodeHeight),QPointF(snake.at(0).x()+snakeNodeWidth,0)));
}
else
{
snake.insert(0,QRectF(snake.at(0).bottomLeft(),snake.at(0).bottomRight()+QPointF(0,snakeNodeHeight)));
}
}
向左移动
void Widget::RightRectF()
{
if(snake.at(0).x()+snakeNodeWidth*2 > this->width())
{
snake.insert(0,QRectF(QPointF(0,snake.at(0).y()),QPointF(snakeNodeWidth,snake.at(0).y()+snakeNodeHeight)));
}
else
{
snake.insert(0,QRectF(snake.at(0).topRight(),snake.at(0).bottomRight()+QPointF(snakeNodeWidth,0)));
}
}
向右移动
void Widget::LeftRectF()
{
if(snake.at(0).x()-snakeNodeWidth < 0)
{
snake.insert(0,QRectF(QPointF(this->width()-snakeNodeWidth,snake.at(0).y()),
QPointF(this->width(),snake.at(0).y()+snakeNodeHeight)));
}
else
{
snake.insert(0,QRectF(snake.at(0).topLeft()+QPointF(-snakeNodeWidth,0),snake.at(0).bottomLeft()));
}
}
删除结尾数据
void Widget::deleteLastRectF()
{
snake.removeLast();
}
绘图
void Widget::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
QPen pen;
QBrush brush;
QFont font("方正舒体",12,QFont::ExtraLight,false);
painter.setRenderHint(QPainter::Antialiasing);
pen.setColor(Qt::green);
brush.setColor(Qt::yellow);
brush.setStyle(Qt::SolidPattern);
painter.setPen(pen);
painter.setBrush(brush);
for(int i=0;i<snake.length();i++)
painter.drawRect(snake.at(i));
brush.setColor(Qt::red);
painter.setBrush(brush);
for(int i=0;i<rewardNode.length();i++)
painter.drawEllipse(rewardNode.at(i));
pen.setColor(Qt::white);
painter.setPen(pen);
painter.setFont(font);
painter.drawText(20,20,QString("当前得分:")+QString("%1").arg(snake.length()));
if(snakeStrike())
{
QFont font("方正舒体",30,QFont::ExtraLight,false);
painter.setFont(font);
painter.drawText((this->width()-300)/2,(this->height()-30)/2,QString("GAME OVER!"));
timer->stop();
rewardTimer->stop();
gameOver = true;
}
QWidget::paintEvent(event);
}
按键事件
void Widget::keyPressEvent(QKeyEvent *event)
{
switch (event->key()) {
case Qt::Key_Up:
if(moveFlog != Down)
moveFlog = Up;
break;
case Qt::Key_Down:
if(moveFlog != Up)
moveFlog = Down;
break;
case Qt::Key_Right:
if(moveFlog != Left)
moveFlog = Right;
break;
case Qt::Key_Left:
if(moveFlog != Right)
moveFlog = Left;
break;
case Qt::Key_Enter:
case Qt::Key_Return:
if(gameOver)
{
snake.clear();
rewardNode.clear();
moveFlog = Up;
snake.append(QRectF(200,500,snakeNodeWidth,snakeNodeHeight));
TopRectF();
TopRectF();
rewardNode.append(QRectF(qrand()%(this->width()/20)*20,qrand()%(this->height()/20)*20,snakeNodeWidth,snakeNodeWidth));
timer->start(time);
rewardTimer->start(time*30);
gameOver = false;
}
break;
case Qt::Key_Space:
if(gameStart && !gameOver)
{
timer->start(time);
rewardTimer->start(time*30);
gameStart = false;
}
else if(!gameStart && !gameOver)
{
timer->stop();
rewardTimer->stop();
gameStart = true;
}
break;
default:
break;
}
}
判断蛇头是否与蛇身相撞
bool Widget::snakeStrike()
{
for(int i=0;i<snake.length();i++)
{
for(int j=i+1;j<snake.length();j++)
{
if(snake.at(i) == snake.at(j))
return true;
}
}
return false;
}
实现效果如下:
注:双击空格开始游戏
注:登录界面只实现了登录,并未实现注册,如果要实现注册,通过添加数据库,或者链表来保存用户数据即可。