Qt小项目之贪吃蛇


前言

为了进一步巩固Qt的知识,在完成五子棋小项目之后,在Qt方面我便开始着手了对贪吃蛇项目的设计,由于本人在51单片机的点阵上已经完成过贪吃蛇小游戏,所以,这一次有点巩固的感觉了。因为其思路和逻辑与我在单片机上的几乎一摸一样,所有前来总结一下。


一、贪吃蛇小项目的总体介绍

在这里简单介绍一下贪吃蛇项目的大概思路:首先,我们需要创建整体的路线框,以及设置具体的窗口大小。其次,就是蛇的身体的绘制以及蛇是如何运动的,我们知道,头才是真正控制走向的部位,所以我们可以让蛇身跟着蛇头运动,具体的话,请看以下步骤中的代码实现。在绘制完蛇身后,我们需要创建蛇的食物,食物是随机产生的,需要用到rand()函数。最后,还需有判断蛇头是否跑出布局和是否会咬到蛇身。实现这几步,基本上就完成了。

二、贪吃蛇项目的具体步骤

1.创建具体的路线框图(由于我也没想到该去什么名字)

代码如下:

#define board_num_x   40            //设置行数
#define board_num_y   40            //设置列数
#define board_width   20            //设置宽度
#define board_height  20            //设置高度
void MyWidget::Draw_board(){
    QPainter painter(this);   //创建画笔对象
    for(int i=0;i<=board_num_x;i++)
    {
        for(int j=0;j<=board_num_y;j++){
            painter.drawLine(i*board_width,0,i*board_width,j*board_height);//开始画
        }
        painter.drawLine(0,i*board_width,board_num_x*board_width,i*board_width);
    }
}

我们绘制了一个40*40的表格,横向间距为20,纵向间距为20,这一步比较基础,所以就没过多介绍。里面的参数都是通过宏定义实现的。

2.创建蛇身

代码如下:

QPoint body[1600];       //存储蛇身
int length=2;            //记录蛇身长度

void MyWidget::Snake_Init(){		//蛇身的初始化
    body[0]=QPoint(0,1);			//将body[0]设置为蛇头
    body[1]=QPoint(0,0);			//设置为蛇身
}

void MyWidget::Draw_Snake(){		//绘制蛇身
    QPainter painter(this);			//创建对象
    QBrush brush;
    brush.setColor(Qt::red);		//设置画刷颜色
    brush.setStyle(Qt::SolidPattern);//设置填充样式
    painter.setBrush(brush);
    Is_eat();						//该函数是判断蛇头有没有吃到食物的
    for(int i=0;i<length;i++){		//从前往后依次遍历,及实现蛇身绘制
        painter.drawRect(body[i].rx()*board_width,body[i].ry()*board_height,board_width,board_height);    //绘制蛇的每一部分
    }
}

在这一部分中,我通过一个QPoint数据类型的数组,来存储蛇头和蛇身。蛇的初始化,我简单的将蛇分为一个蛇头和一节身体,以后在蛇吃到食物后蛇身会加长,具体会在后文给出。

蛇的走向判断

代码如下:

void MyWidget::keyPressEvent(QKeyEvent *event){		//键盘按键检测事件
    if(event->key()==Qt::Key_Down){			//当摁到向下的按钮时
        if(flag!=2){						//判断当前方向是否和将要运动的方向相反,不相反则执行
            flag=1;
        }
    }
    if(event->key()==Qt::Key_Up){			//当摁到向上的按钮时
        if(flag!=1){
            flag=2;
        }
    }
    if(event->key()==Qt::Key_Left){			//当摁到向左的按钮时
        if(flag!=4){
            flag=3;
        }
    }
    if(event->key()==Qt::Key_Right){		//当摁到向右的按钮时
        if(flag!=3){
            flag=4;
        }
    }
}

上面这部分代码通过引入头文件 QKeyEvent 来实现,这是Qt自带的库,用于对键盘按键的检测。其中,flag为1时表示向下运动,为2时向上运动,为3时向左运动,为4时向右运动,该标志位用于后续运动时的走向。

void MyWidget::time_init(){			//创建定时器,并初始化
    timer=new QTimer(this);			//创建对象
    timer->setInterval(1000);		//设置定时时长为1000ms
    timer->start();					//定时器开始运行
}

这部分代码为创建定时器,并初始化。设置定时器的定时周期为1000ms,并让起开始运行。

void MyWidget::on_timer_timeout(){		//定时器达到计时时会执行该函数
    for(int i=length;i>0;i--){		//从后往前遍历,实现前文提到的蛇身跟随蛇头运动的行为
        body[i]=body[i-1];
    }
    switch(flag){			//flag为走向标记位
    case 1:
        body[0]=QPoint(body[0].rx(),body[0].ry()+1);	//向下运动
        break;
    case 2:
        body[0]=QPoint(body[0].rx(),body[0].ry()-1);	//向上运动
        break;
    case 3:
        body[0]=QPoint(body[0].rx()-1,body[0].ry());	//向左运动
        break;
    case 4:
        body[0]=QPoint(body[0].rx()+1,body[0].ry());	//向右运动
        break;
    }
    Snake_Dead();			//蛇的死亡条件判断,后文会给出
}

在这一部分中,实现了对存储蛇身的数组的更新,并且每次更新时长都为1s,即蛇会在每过1s后进行移动。

食物创建

代码如下:

int food_flag=0;         //食物有无标志位
int food_x;              //食物生成的x坐标
int food_y;              //食物生成的y坐标

void MyWidget::Creat_food(){
    if(food_flag==0){				//当没有食物时,创建食物
        food_x=rand()%board_width;	//使用rand()函数,随机产生数字,作为食物的x坐标
        food_y=rand()%board_height;//作为y坐标
        food_flag=1;				//将标志位设置为一,即存在食物
    }
    QPainter *painter=new QPainter(this);
    QBrush brush;
    brush.setColor(Qt::red);		//设置画刷颜色
    brush.setStyle(Qt::SolidPattern);	//设置填充样式
    painter->setBrush(brush);
    painter->drawRect(food_x*board_width,food_y*board_height,board_width,board_height);			//在食物的位置绘制食物
}

这一部分,通过随机产生一个二维坐标,并在该坐标处进行绘画食物的操作。

吃食物

代码如下:

void MyWidget::Is_eat(){     //判断是否吃到
    if(body[0].rx()==food_x&&body[0].ry()==food_y){		//当蛇头的坐标等与食物的坐标时,就认为已经迟到食物了
        length++;		//蛇身长度加一
        food_flag=0;	//食物标志位置0,说明没有食物了
    }	
}

在这一部分就很简单了,通过判断蛇头的坐标是否与食物的坐标相等,相等的话就认为蛇吃到食物了,与此同时,将蛇身的长度加一,并把食物标志物置0,一遍在后续中在产生一个食物。

贪吃蛇的死亡判断

void MyWidget::Snake_Dead(){
    for(int i=1;i<length;i++){		//这一部分用于判断蛇头是否撞到蛇身
        if(body[0]==body[i]){
            timer->stop();			//撞到的话,将定时器停止,即蛇静止,游戏结束
        }
    }
    if(body[0].rx()==-1||body[0].rx()==41||body[0].ry()==-1||body[0].ry()==41){				//该部分用于判断蛇头坐标是否出界
        timer->stop();	//如果出界,定时器停止
    }
}

总结

以上就是今天要讲的内容,本文只是简简单单的对贪吃蛇项目进行讲解,如果有错误,还请各位大佬指出。另外,如有需要源码的,请留言。下次再见!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值