Essential Qt 第十八章 贪吃蛇(下)

                前一章制作了贪吃蛇游戏的框架,只是实现了一些基本功能,而这一在会进一步完善程序所需要的各项功能,首先看下程序完成后的样子


              相较于前一章,个程序添加了一个难度选择框,一个信息显示框,以及三个按钮用于控制游戏的各项功能,对比前一章的程序,这个程序主要多了以下功能

              1 游戏结束后可以新建游戏

              2 提供难度选择,蛇的移动速度会根据难度的不同而有不同

              3 提供了暂停/开始功能

              4 吃到10个食物为游戏胜利

              5 提供了一个信息显示栏,用于显示游戏的各种游戏状态


           实现上述,功能,首先想程序头文件里添加一个QGroupBox,三个QRadioButton,三个QPushButton和一个QLabel

	QPushButton* newGame_PushButton;
        QPushButton* goOrStop_PushButton;
	QPushButton* close_PushButton;

	QRadioButton* easy_RadioButton;
	QRadioButton* normal_RadioButton;
	QRadioButton* hard_RadioButton;

        QLabel* info_Label;

	QGroupBox* level_GroupBox;
      
           这里省略了构造函数里添加的有关布局的代码,我来逐一看下添加功能的实现,第一步是新建游戏代码,这里通过一个私有槽resetGame()来实现

void Snake::resetGame()
{
    snakePath_List.clear();  //清楚保存蛇外形的链表
    clock_Timer->stop();  //停止计时器
    putFood();    //放置食物和蛇,他们都采用默认值
    setSnakeShape();
    if(easy_RadioButton->isChecked())   //选择游戏难度,即蛇的移动速度
        clock_Timer->setInterval(700);
    else if(normal_RadioButton->isChecked())
        clock_Timer->setInterval(500);
    else if(hard_RadioButton->isChecked())
        clock_Timer->setInterval(300);

    getFoodNumber_int = 0;   //该变量保存吃到食物的个数
    currentDirction_enum = GoLeft;   //蛇的初始移动方向为向左
    gameIsOver_bool = false;    //游戏状态为未结束
    isMoving_bool = false;    //游戏状态为未运行
    goOrStop_PushButton->setText(tr("开始"));  
    info_Label->setText(tr("准备就绪"));   //在游戏信息板上显示游戏信息
}
           要开始一个新的游戏,需要先把蛇和食物放回原位,蛇还需要变为原来的样子,通过计时器的setInterval()函数来设置游戏的难度,简单:蛇移动间隔为0.7秒,正常:移动间隔为0.5秒,困难:移动间隔为0.3秒,这个类还添加了三个成员变量来控制游戏的状态,其中getFoodNumber_int用于记录已经吃到食物的数量,在新建游戏是这个值会被重置为0,gameIsOver_bool用于标记游戏是否已经结束,当蛇撞墙/吃到自己/吃到10个食物后,变量ganeIsover_bool为被设为false,而新建一个游戏是这个变量会被设为true,最后是变量isMoving_bool,该变量用于标记游戏里蛇是否在前进,新建游戏后尚未开始,蛇处于停止状态,所以这里设为false,当点击开始,蛇开始运动时,这个值会被设为true


          下一个功能是游戏的暂停/开始功能,这个功能通过槽keepGoing()来实现

void Snake::keepMoving()
{
    if(gameIsOver_bool)  //如果游戏结束,则该函数不做任何事
        return;
    if(isMoving_bool)
    {
        clock_Timer->stop();
        isMoving_bool = false;
        goOrStop_PushButton->setText(tr("开始"));
        info_Label->setText(tr("游戏暂停"));
    }
    else
    {
        clock_Timer->start();
        isMoving_bool = true;
        goOrStop_PushButton->setText(tr("暂停"));
        info_Label->setText(tr("游戏运行中"));
    }
}

             这个函数的作用是点击“开始”,启动计时器,点击“暂停”,停止计时器,同时在信息显示板上显示游戏的当前状态,需要注意的是这个功能只有在游戏运行过程中才能使用,当游戏已经结束是,该函数不做任何事,也就是说,游戏结束后点击开始/暂停按钮不会有任何改变


            最后是游戏胜利条件,吃到10个食物获得胜利,要实现这个功能,需要修改movingFood()函数的功能,改动不多,但考虑到本章内容比较少,为了让文章显得比较长,所以这里贴出完成的movingFood()函数的代码

void Snake::movingFood()
{
    if(getFoodNumber_int == 10)
    {
        info_Label->setText(tr("游戏胜利"));
        clock_Timer->stop();
        gameIsOver_bool = true;
        food_GraphicsRectItem->setPos(-50,-50);//把食物移到view外面
        return;
    }
	qsrand(QTime(0, 0, 0).secsTo(QTime::currentTime()));
	GridPoint p;
	while (true)
	{
		p.x = qrand() % 20;
		p.y = qrand() % 20;
		if (!(snakePath_List.contains(p)))
			break;
	}
	putFood(p.x, p.y);
}
   变量getFoodNumber_int的计算实在movingSnake()函数里实现的,在发射eatFood()信号前先实现了++getFoodNumber_int功能,所以这里就直接判断是不是已经吃到10个食物了,吃到第11个食物是就判断游戏结束,在信息面板上显示“游戏胜利“,这里有个细节是判断吃到了第11个食物后,不会生产新的食物,也就是说原先的食物不会被移动到一个新的位置,而此时定时器停止,蛇停止运动,食物会位于蛇的最前端,这样略显难看,所以这里把食物移动到QGraphicsView外面,当开始新游戏时,食物会被放到正确的位置上

           关于内存:前面说过QGraphicsItem以及继承他的各种item均没有把QObject作为基类,他们无法使用信号于槽,在Qt内存章节中介绍过,当Qt对象销毁时,他会自动销毁他的所有子对象,但这里有个前提条件,就是这些子对象必须是QOject的子类,否则无法被自动销毁。而这里的这个例子里,使用了各种item均不是QObject子类,但对于元素/视图架构,Qt做了特殊处理,当QGraphicsScene销毁时,会自动销毁QGraphicsScene上所有的item,所以就没必要在析构函数里显示的delete每个item了,不过这里有个比较例外的情况,当处于某种需要使用QGraphicsScene的removeItem(QGraphicsItem* item)函数时,被移除scene的item将不会被自动效果,需要在析构函数中手动delete,这个removeItem()函数只是把 item从scene上移除而并没有销毁他。但大多数情况下,需要某个item不出现的时候,会把这个item移动到view显示区域之外,而不是使用removeItem()函数,这样可以避免内存管理上可能出现的问题


完整代码https://pan.baidu.com/s/1gfngtUz

                           

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值