目录
概要
此次贪吃蛇实现三个主页面:游戏大厅页面,关卡选择页面,游戏页面。一个退出游戏窗口页面,和历史战绩页面。
游戏大厅与关卡选择页面
如上图所示,这两个页面也是比较容易实现的,第一个页面就利用qrc实现对图片,音频,笔记本等资源的托管,使用 void GameHall::paintEvent(QPaintEvent *event) 这个成员函数,在里面有QPixmap这个类,加载响应的qrc图片,对我们的窗口进行绘制。利用 setFixedSize 这个属性固定窗口,使其不能进行放大和缩小。 setWindowIcon设置窗口图片,在利用setWindowTitle来设置窗口的标题内容。使用QPushButton新建一个按钮,用move对按钮的位置进行合理的布局,用QFont对字体样式进行设计,并命名为进入游戏,在创建一个窗口,用connect连接信号与槽。设置打开关卡选择页面。用setStyleSheet对按钮的样式进行设计。
关卡选择页面和上面所用到的基本一样,三种模式和一个历史战绩对齐进行布局和设置样式,在右下角创建一个按钮并绘制上图片,设置信号槽,不同于上一个页面的按钮,这用close关闭当前页面,在打开之前的页面就形成了返回页面的切换。之后再创建一个页面与三种游戏模式关联上,再设置点击历史战绩出现一个窗口来显示历史战绩。
技术细节
枚举出蛇移动的方向,我们知道QList<QRectF>再Qt框架中是一个储存矩形列表的数据结构,用定时器QTimer来操纵蛇移动的速度,对开始游戏创建一个按钮,点击按钮触发 timer->start()来启动定时器,调用一个函数使他满足,向上移动的逻辑就是在蛇的上⽅加⼊⼀个⼩⽅块, 然后把最后⼀个⼩⽅块删除即可。用cnt是表示蛇的食物,也就是矩形,如果蛇头和矩形相交cnt++实现两次循环增加一个节点,当循环完毕,由于cnt是在定时器的槽函数里面定义的,所以当走下一格的时候,会重定义。之后会矩形行走。
部分代码展示
createNewFood(); timer = new QTimer(this); connect(timer, &QTimer::timeout, this, [=](){ int cnt = 1; //统计和食物相交的次数 if(snakeList.empty()) { qDebug() << "connect(timer, &QT"; } if(snakeList.front().intersects(FoodRect)) // intersects是QT提供的判断两个矩形是否相交的方法 { createNewFood(); // 相交在增加一次食物 cnt++; } while (cnt--) { switch (moveDirect) { case SnakeDirect::UP: moveUp(); break; case SnakeDirect::DOWN: moveDown(); break; case SnakeDirect::LEFT: moveLeft(); break; case SnakeDirect::RIGHT: moveRight(); break; } } // 蛇移动,头节点移动,后面的节点跟上,但是最后一个节点是删除在添加 snakeList.pop_back();//删除最后一个节点 update();//更新链表 }); // 蛇是一个矩形,在移动的时候根据左上角和右下角进行定义 void gameroom::moveUp() { QPointF leftTop; // 左上角坐标 QPointF rightBottom; // 右下角坐标 auto snakeNode = snakeList.front(); // 蛇头(list的头结点) int headX = snakeNode.x(); // 头结点的横坐标 int headY = snakeNode.y(); // 头结点的纵坐标 // 左上角 if(headY < 0) // 超出窗口顶部的范围 { // 向上移动纵坐标改变,横坐标不会改变 leftTop = QPointF(headX, 600 - kSnakeNodeHeight); //左上角的位置(点)就是我们定义游戏区域窗口的位置-蛇头(链表)的高度 } else // 没有超出 { // 坐标为左手坐标,越向上Y越小,如果没有超出,那么现在左上角的高度是蛇头(链表)本身的高度减去它矩形的高度就得出坐标了 leftTop = QPointF(headX, headY - kSnakeNodeHeight); } // 右下角(由于它是基于左上角来判定的所以不用判定是否穿墙) // 左上角点的坐标加上蛇头(链表)的高度与宽度,右下角在左上角的右下方基于坐标是变大的 rightBottom = leftTop + QPointF(kSnakeNodeWidth, kSnakeNodeHeight); // 如果是基于左上角来定右下角那么右下角的大小永远是这样计算的 snakeList.push_front(QRectF(leftTop, rightBottom));// 利用头插的方法将节点更新到链表当中 }
后面的就是用创建按钮来与启动游戏、暂停游戏、上下左右移动的槽函数进行绑定,并设置其快捷键。并根据自己选择创建按钮样式等。
小结
主要利用定时器将各个定义的对象关联起来,以蛇向上为例子,定时器每隔2秒自动更新,判断是否和食物相交,是在进入下一个循环的时候,多循环一个就可以了,进入while循环通过枚举,来进入向上移动的函数,向上移动函数的作用是,在当前位置的头上增加一个矩形,退出循环后删除最后一个矩形,通过定时器没个2秒自动调用上述情况就形成了移动。类似于翻书动画,是指有多张连续动作漫画图片的小册子,因人类视觉暂留而感觉图像动了起来,也可说是一种动画手法。同时对蛇进行渲染,由于要删除尾巴,同时头和身子不一样,所以对渲染分成了三部分。头身子尾部,这样就形成了可以移动的蛇。