Qt实战项目学习4———贪吃蛇小游戏

一.图形的绘制

1.蛇的绘制

蛇采用RectF方式绘制,每个Rect放入链表中组成

QRect  rect(x, y, width, height)    参数为,矩形顶点坐标,宽,高

QList  append() ——尾部添加节点

//.h中声明
QList<QRect> snake;
//.cpp构造中初始化
 QRectF rect(300,180,nodeWidth,nodeHeight);
 snake.append(rect);

绘图事件中绘制蛇

 for(int i=0;i<snake.length();i++)
    {
        painter.drawRect(snake[i]);
    }

2.奖励的绘制 

奖励的绘制同样使用rect

//.h中
QRectF rewordNode;
//.cpp的绘图事件中
 painter.drawEllipse(rewordNode);

奖品的随机出现单独封装函数,rect的顶点随机,长宽在.h中初始设置。

在构造函数中调用,初始化奖品

QRandomGenerator::global()->bounded(10)    生成0-10随机数 

void Widget::addNewReword()
{
    rewordNode=QRectF(QRandomGenerator::global()->bounded(this->width()/20)*20,
                     QRandomGenerator::global()->bounded(this->height()/20)*20,
                      nodeWidth,nodeHeight);

}

二.蛇的移动

1.按键与方向关联(重写键盘事件)

自定义枚举变量表示是否改变方向,声明方向改变标志判断,声明游戏是否开始标志。方向初始默认为向上

(枚举变量需类外声明)

//枚举变量表示方向
typedef enum Dridct{
     Dir_left, Dir_right, Dir_up, Dir_down
}dir_t;

int  moveFlag=Dir_up;   //改变方向标志
bool gameStart=false;   //游戏开始标志

重写键盘事件,将方向与摁键关联,空格键需判断游戏是否处于开始状态,若为开始状态则暂停,若为暂停状态则开始。若为正在向上时则不允许向下,其他方向同理。

void Widget::keyPressEvent(QKeyEvent *e)
{
    switch(e->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_Right:
        if(moveFlag != Dir_left)
           moveFlag=Dir_right;
        break;
    case Qt::Key_Left:
        if(moveFlag != Dir_right)
           moveFlag=Dir_left;
        break;

    case Qt::Key_Space:
        if(gameStart==false)    //此时游戏开始
        {
            gameStart=true;   
            //启动定时器
            timer->start(time);
        }
        else
        {
            gameStart=false;
            //关闭定时器
            timer->stop();
        }
        break;
     default:
        break;
    }
}

2.移动过程蛇身变化

以向上为例,当向上移动时,蛇链表头部向上增加一个矩形。

要判断是否超出了边框

//向上添加
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()+nodeWidth,this->height());
    }
    else
    {
        leftTop=QPointF(snake[0].x(),snake[0].y()-nodeHeight);
        rightBottom=snake[0].topRight();
    }
    snake.insert(0,QRectF(leftTop,rightBottom)); //在下标0处添加节点
}

QList 中

insetr() ——插入节点到                             removeLast()——尾部删除

 三.定时器事件控制

1.定时器

当游戏开始时,定时器开始,并且每隔180毫秒刷新界面。

//.h中声明出定时器
QTimer *timer;  
int time=100;  //超时时间间隔


//.cpp的构造函数中初始化定时器
timer=new QTimer(this);
connect(timer,SIGNAL(timeout()),this,SLOT(timeout()));

 2.自定义定时器槽函数

当游戏开始时,定时器开始,绘图事件重写,界面将不断刷新。槽函数中需要完成:蛇移动过程中图像的变化,以及吃掉奖励时的画面变化

void Widget::timeout()
{
    int count=1;
    //判断吃掉奖励  蛇头部是否与奖励重合
    if(snake[0].intersects(rewordNode))
    {
        count++;
        addNewReword();
        scoer++;   //记录分数
    }
    while(count--)
    {
          switch(moveFlag)
         {
          case Dir_up:
              //向上增加
              addTop();
               break;

          case Dir_down:
              addDown();
              break;

          case Dir_left:
              addLeft();
              break;

          case Dir_right:
              addRight();
              break;
          }
    }
    deletelast(); //封装的尾删函数 当未吃掉奖励时,删掉最后一个保持长度不变
    update();
}

四.判断游戏结束

检查蛇头是否碰到蛇身

自定义bool类函数

//检查是否碰到蛇身
bool Widget::checkContact()
{
    for(int i=0;i<snake.length();i++)
    {
        for(int j=i+1;j<snake.length();j++)
        {
            if(snake[j] == snake[i])
            {
                return true;
            }
        }
    }
   return false;
}

在绘图事件中绘制游戏结束 并且关闭定时器

 if(checkContact())
    {
        QFont font("方正舒体",30,QFont::ExtraLight,false);
        pen.setColor(Qt::red);
        painter.setPen(pen);
        painter.setFont(font);
        painter.drawText((this->width()-300)/2,
                         (this->height()-30)/2,
                         QString("GAME OVER!"));
        time->stop();

    }

效果如图所示

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值