计算机软件实习项目二——贪吃蛇

贪吃蛇的需求分析

1.通过方向键控制蛇头进行左右上下移动

2.随机生成食物供贪吃蛇吃,吃到食物蛇身变长

3.蛇头碰到蛇身或边界结束游戏

具体实现

控制蛇上下移动:使用QTimer类定义一个定时器,该定时器不断地发出timeout信号,相应的槽函数就会不断地接收该信号来执行动作以控制蛇移动,然后不断地进行重新渲染,以达到蛇不断移动的效果。前面说过蛇的移动实际上是在头部增加一个小方块,在尾部删除一个小方块,因此可以封装4个成员函数分别控制蛇在4个方向的头部增加,同时再封装一个成员函数表示尾部的删除。

食物生成:食物可以用一个小方块来表示,然后封装一个成员函数来随机分配食物这个小方块的位置,先在构造函数中对其进行初始化,最后通过渲染函数将其画在界面中。

蛇身变长:只需判断蛇头小方块是否和食物小方块重合,一旦重合,那我们在头部多增加一个小方块,就表示蛇增长了。比如蛇朝右移动,我们在头部增加一个小方块,尾部删除一个小方块,表示蛇的移动,那现在,我们在头部增加两个小方块,在尾部删除一个小方块,就表示蛇增长了。

结束游戏:蛇头坐标与蛇身或边界重合,判定游戏结束。

源代码如下:

#include "widget.h"
#include "ui_widget.h"
#include<QPainter>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->setWindowTitle("贪吃蛇");
        timer = new QTimer();
        //定时器关联
        connect(timer,SIGNAL(timeout()),this,SLOT(timeout()));
        resize(1200,500);
        //初始化蛇身
        QRectF rect(500,230,nodeWidht,nodeHeight);
        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(100);//定时器启动
            }
            else {
                gamestart=false;
                timer ->stop();
            }
            break;
        default:
            break;
        }
    }
     void Widget::timeout(){
         if(checkContact())return;
         //吃到食物
         int counter = 1;
         if(snake[0].intersects(rewardNode)){
             counter++;
             score++;
             addNewReward();
         }
         while(counter--){
             switch(moveFlag){
             case DIR_UP://顶部加方块
                 addTop();
                 break;
             case DIR_DOWN:
                 addDown();
                 break;
             case DIR_LEFT:
                 addLeft();
                 break;
             case DIR_RIGHT:
                 addRight();
                 break;
             }
    }
         deleteLast();
         update();//自动调用重绘方法
    }
     void Widget::addTop(){//向上
         QPointF leftTop;
         QPointF rightBottom;
 
         if(snake[0].y() - nodeHeight < 0){
             leftTop = QPoint(snake[0].x(),this->height() - nodeHeight);
             rightBottom = QPointF(snake[0].x() + nodeWidht,this->height());
         }
         else{
 
         leftTop = QPointF(snake[0].x(),snake[0].y()-nodeHeight);//左下角坐标
         rightBottom = snake[0].topRight();//右下角坐标
         }
         snake.insert(0,QRectF(leftTop,rightBottom));
     }
     void Widget::paintEvent(QPaintEvent *event){
 
        //画游戏界面
         QPainter painter(this);
         QPen pen;
         QBrush brush;
         //背景图
         QPixmap pix;
         pix.load("D:/Qtcode/snake.jpg");
         painter.drawPixmap(0,0,1200,500,pix);
         //画蛇
         pen.setColor(Qt::yellow);
         brush.setColor(Qt::blue);
         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::green);
         brush.setColor(Qt::green);
         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("游戏结束"));
             timer->stop();
         }
 
         //画分数记录
         pen.setColor(Qt::red);
             brush.setColor(Qt::red);
             painter.setPen(pen);
             painter.setBrush(brush);
             QFont font("宋体",20,QFont::ExtraBold,false);
             painter.setFont(font);
             painter.drawText(0,nodeHeight*3,
                              QString("分数:"+QString::number(score*10)));
 
     }
     void Widget::deleteLast(){
         snake.removeLast();
     }
     void Widget::addDown(){//向下
         QPointF leftTop;
         QPointF rightBottom;
         //向下时如果接触到底端,则从对应的顶端重新生成蛇头
         if(snake[0].y() + nodeHeight * 2 > this->height()){
             leftTop = QPointF(snake[0].x(),0);
             rightBottom = QPointF(snake[0].x() + nodeWidht,nodeHeight);
 
         }
         //没有触碰下边界时,正常加减节点
         else{
             leftTop = snake[0].bottomLeft();
             rightBottom = snake[0].bottomRight() + QPointF(0,nodeHeight);
         }
         snake.insert(0,QRectF(leftTop,rightBottom));
     }
     void Widget::addLeft(){//向左
         QPointF leftTop;
         QPointF rightBottom;
         if(snake[0].x() - nodeWidht<0){
             leftTop = QPointF(this->width() - nodeWidht,snake[0].y());
         }
         else{
             leftTop = snake[0].topLeft() - QPointF(nodeWidht,0);
         }
         rightBottom = leftTop + QPointF(nodeWidht,nodeHeight);
          snake.insert(0,QRectF(leftTop,rightBottom));
     }
     void Widget::addRight(){//向右
         QPointF leftTop;
         QPointF rightBottom;
         if(snake[0].x() + nodeWidht*2 > this->width()){
             leftTop = QPointF(0,snake[0].y());
         }
         else{
             leftTop = snake[0].topRight();
         }
         rightBottom = leftTop + QPointF(nodeWidht,nodeHeight);
          snake.insert(0,QRectF(leftTop,rightBottom));
    }
     void Widget::addNewReward(){//随机生成食物
         rewardNode = QRectF(
                     qrand()%(this->width()/20)*20,
                     qrand()%(this->height()/20)*20,
                     nodeWidht,
                     nodeHeight);
     }
     bool Widget::checkContact(){//身体和头接触结束
         for(int i=1;i<snake.length();i++){
             if(snake[0] == snake[i]){
                 return true;
             }
         }
         return false;
     }
 
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值