要制作一个贪吃蛇小游戏,知识点包含:信号与槽 ,connect 定时器,QTimer 绘制事件,paintEvent ,按键事件,keyPressEvent 随机数,资源文件,应用程序图标,Qt程序发布/打包。
步骤:
①初始化。1.初始化定时器。 2.固定界面大小。3.加载图片,即蛇的头、身体和食物。 4.游戏初始化,需要为蛇设置初始长度,设置几个节点的坐标,保存于两个数组中。随机生成食物的x和y坐标,然后启动定时器。
②定时器。如果游戏正在进行中,需要检查蛇是否吃到食物,即蛇头与食物的位置坐标是否重叠,如果吃到了食物,蛇身的长度加1,然后需要重新生成食物的位置坐标。游戏中需要两个计时器去刷新,一个用来刷新蛇身,一个用来刷新食物。食物需要随机生成,被吃掉后需要删除,有一定的停留时间。keyPressEvent来监测按键的按下,控制贪吃蛇的移动,使用定时器来设定刷新的时间,使用随机函数生成食物的节点。在游戏中还需要检查蛇是否撞到蛇身,如果撞到蛇身,即游戏结束,如果游戏结束,就停止定时器,重新绘制结束的界面。
③核心算法。生成食物的位置,吃食物,检测是否碰撞,蛇的移动,按键,绘制等。
代码参考:
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
resize(600,400);
setStyleSheet("QWidget{background:pink}");
snake.append(QRectF(200,200,snakeNodeWidth,snakeNodeHeight));
addTopRectF();
addTopRectF();
// 设置第一个奖励
rewardNode.append(QRectF(400,200,snakeNodeWidth,snakeNodeWidth));
timer = new QTimer;
connect(timer, SIGNAL(timeout()),this,SLOT(timeOut()));
rewardTimer = new QTimer;
connect(rewardTimer,SIGNAL(timeout()),this,SLOT(rewardTimeOut()));
this->setWindowTitle("贪吃兔小游戏");
this->setWindowIcon(QIcon(":/1.jpeg"));
}
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)))
{
flage++; //吃一个奖励,蛇身加长一段
rewardNode.removeAt(i);
break;
}
}
while(flage--){
switch (moveFlage) {
case Up:
addTopRectF();
break;
case Down:
addDownRectF();
break;
case Right:
addRightRectF();
break;
case Left:
addLeftRectF();
break;
default:
break;
}
}
deleteLastRectF();
update();
}
void Widget::rewardTimeOut()
{
qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
if(rewardNode.length() > 5)
{
rewardNode.removeAt(qrand()%3);
}
rewardNode.append(QRectF(qrand()%(this->width()/20)*20,qrand()%(this->height()/20)*20,snakeNodeWidth,snakeNodeWidth));
if(qrand()%3 == 3){
rewardNode.append(QRectF(qrand()%(this->width()/20)*20-5,qrand()%(this->height()/20)*20-5,snakeNodeWidth*2,snakeNodeWidth*2));
}
}
// 向上移动
void Widget::addTopRectF()
{
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::addDownRectF()
{
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::addLeftRectF()
{
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::addRightRectF()
{
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::deleteLastRectF()
{
snake.removeLast();
}
void Widget::startTheGame()
{
timer->start(time);
rewardTimer->start(time2*30);
gameStart = false;
}
void Widget::endTheGame()
{
timer->stop();
rewardTimer->stop();
gameStart = true;
}
// 绘图
void Widget::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
QPen pen;
QBrush brush;
QFont fontg ( "黑体", 20, 50);
painter.setRenderHint(QPainter::Antialiasing);
pen.setColor(Qt::blue);
brush.setColor(Qt::white);
brush.setStyle(Qt::SolidPattern);
painter.setPen(pen);
painter.setBrush(brush);
for(int i=0; i<snake.length(); i++){
//painter.drawRect(snake.at(i));
painter.drawImage(snake.at(i), QImage(":/6.png"), QRectF(0,0,1076,909));
}//画蛇
brush.setColor(Qt::yellow);
painter.setBrush(brush);
for(int i=0; i<rewardNode.length(); i++){
//painter.drawEllipse(rewardNode.at(i));
painter.drawImage(rewardNode.at(i), QImage(":/4.png"), QRectF(0,0,750,1024));
}//画奖励
pen.setColor(Qt::black);
painter.setPen(pen);
painter.setFont(fontg);
// painter.drawText(240,40,QString("得分:")+QString("%1").arg());
emit changeScore(snake.length()-3);
if(snakeStrike()){
QFont font("幼圆",30,QFont::ExtraLight,false);
painter.setFont(font);
painter.drawText((this->width()-300)/2,(this->height()-30)/2,QString("游戏结束"));
timer->stop();
rewardTimer->stop();
gameOver = true;
}
QWidget::paintEvent(event);
}
void Widget::keyPressEvent(QKeyEvent *event)
{
switch(event->key()){
case Qt::Key_Up:
if(moveFlage != Down){
moveFlage = Up;
}
break;
case Qt::Key_Down:
if(moveFlage != Up){
moveFlage = Down;
}
break;
case Qt::Key_Right:
if(moveFlage != Left){
moveFlage = Right;
}
break;
case Qt::Key_Left:
if(moveFlage != Right){
moveFlage = Left;
}
break;
case Qt::Key_Enter:
case Qt::Key_Return:
if(gameOver){
snake.clear();
rewardNode.clear();
moveFlage = Up;
snake.append(QRectF(200,500,snakeNodeWidth,snakeNodeHeight));
addTopRectF();
addTopRectF();
//首先生成一个奖励节点
rewardNode.append(QRectF(100,100,snakeNodeWidth,snakeNodeWidth));
timer->start(time);
rewardTimer->start(time2*30);
gameOver = false;
}
break;
case Qt::Key_Space:
if(gameStart && !gameOver){
timer->start(time);
rewardTimer->start(time2*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;
}