还剩9页未读,继续阅读
本资源只提供10页预览,全部文档请下载后查看!喜欢就下载吧,查找使用更方便
文本内容:
上一个帖子已经介绍了用开发板制作的花里胡哨的〃手柄〃,这个帖子介绍一下贪吃蛇UFun游戏界面的制作两者之间采用串口通信,上个帖子介绍了数据发送的格式约定,这里就不在赘述了,详见帖子[开发板评测】贪吃蛇
(一)用开发板做游戏手柄uFun uFun帖子内用的是开源版Qt,版本为游戏界面及功能略为粗糙,文末提供了源码以及编译完成的程序下载附件Bl Widget按任意卬始游戏先来分析一下帖子内这款游戏想要实现的功能首先实现串口通信是必须的绘制一条能动的贪吃蛇和一个食物是游戏的基础能判断游戏的结束,分为撞墙死和自闭而死painter.drawEllipsefoodPoint.x block_width,foodPoint.yQblock_height block_width block_height;z zifthis-startFlag==false{二QFont fontpainter.font;font.setPixelSizeblock_height*3;painter.setFontfont;按任意键开始游戏painter.drawTextthis-rectQ,Qt::AlignCenter,”试图模仿以前小霸王之类的游戏机,做的手柄也能即插即用uFun确定功能之后,就要构思怎么去实现了串口通信可以采用提供的类轻松实现;Qt5QSerialPort为了能动,采用了定时器定时重绘的方法每次重绘都更新一下贪吃蛇位置,这样贪吃蛇就动起来了;贪吃蛇的躯体可以用一个数组来存储每一节身体的位置坐标,为了方便,采用了自Qt带的实现;QList+QPoint食物被吃了之后需要随机出现,采用了随机数生成器来生成食QRandomGenerator物的坐标;既然已经存储了贪吃蛇身体的坐标,场地的坐标范围也是已知的,只要将贪吃蛇下一个行进的坐标和它们比较就能知道游戏有没有结束;为了实现即插即用,拔掉再插还能用,可以对类的信号进QSerialPort errorOccurred行处理,为了方便,只要串口出错就关闭串口没有串口连接时就在游戏中不断尝试连接串口,遇到第一个能用的串口直接打开,之后停止尝试这里做了一个假设,就是按照常理游戏机上只会插手柄其中位置坐标并不是按像素算的贪吃蛇的身体是由一个个小长方形构成的,长方形有一定的长和宽,位置坐标是以一个长方形为单位的,游戏界面的大小也是长方形的整数倍;//长方形的宽#define block_width15//长方形的高#define block_height15//游戏界面的宽为#define x_count50block_width*x_count//游戏界面的高为#define y_count40block_height*y_count程序中定义了一个变量用来标识游戏是否开始bool startFlag我尝试着对实现贪吃蛇躯体做了个很不成熟的类封装,有些成员函数都是在编程过程中需要才加上的#ifndef SNAKE_H#define SNAKE_H#include QPoint#include QList//宏定义四个方向#define dir_up1#define dir_down2#define dirjeft3#define dir_right4class Snakepublic:SnakeQPoint headLocation,int lenth=3,int cur_dir=dir_right;//获取贪吃蛇长度int getLenth;//获取当前前进方向int getCurDirecton;//获取贪吃蛇的整个身体,主要在绘制里用QListQPointgetBodyO;//获取贪吃蛇头部的坐标位置QPoint getHeadLocationQ;bool addBlockintcurDir;//添加一块身体//向某个方向前进一步bool makeStepint dir;//判断某一点是否在蛇的身体内bool isInSnakeQPoint point;bool//判断某一点是否在蛇的身体内isInSnakeint x,int y;//尝试走一步,输入一个坐标和前进方向,获void tryGoQPoint*point,intdir;取走一步之后的新坐标点private://用来记录当前前进的方向int curDirection;//用来存储贪吃蛇的身体各单元坐标点QListQPoint snake_body;;#endif//SNAKE_H说明一下其中和函数,实际上实现过程就是把身体最后一个坐标位addBlockmakeStep置去除,并在列表中加入新的头位置串口初始化中主要需要连接处理串口的两个信号一个是出错信号主要做的工作是把出错时已经打开的串口关闭,errorOccurred,这样程序循环内才会继续尝试打开串口在初始化时也会有一次尝试寻找可用的串口;另一个是接收到数据的信号其中的数据处理思路和开发板处理思路相同,不再readyRead,uFun赘述当接收到信息之后,会把方向暂存在一个变量里,只有当定时器到点重绘时才会真正更新前进方向,也就是说只认重绘前最后一次方向//帧信息处理过程ifch=={//一帧接收结束//当停在游戏开始界面时,检测到按键就直接置位开始游戏ifthis-startFlag==false{this-startFlag=true;ifpTimer-isActive==falsepTimer-start;return;//A-1eft D-right W-up S-downswitch rcvData.toUtf
8.at0{case A*:case a:ifthis-curDirection!=dir_rightthis-preDirection=dirjeft;break;case D:cased:ifthis-curDirection!=dirjeftthis-preDirection=dir_right;break;case W:case w:ifthis-curDirection!=dir_downthis-preDirection=dir_up;break;case S:case s:ifthis-curDirection!=dir_upthis-preDirection=dir_down;break;frameFlag=false;}采用随机数生成器生成食物的坐标当生成食物不合理时,会重复生成此处随机种子很简单,但效果看起来也无大碍,此外没有处理食物生在死角那种极端情况void Widget::makeFoodQRandomGenerator generator;quint32x,y;whiletrue{generator.seedstatic_castquint32QTime::currentTime.second;x=generator.generateO;y=generator.generateO;x%=x_count;y%=y_count;ifpSnake-isInSnakestatic_castintx static_castinty==falsezbreak;food Point.setXstatic_cast intx;foodPoint.setYstatic_castinty;DEBUG_coutxy;界面动起来的核心是重绘定时器每次定时器到点触发信号,都会进行判断游戏timeout是否结束,是否吃到食物,并且会调用或函数更新一下贪吃蛇的位addBlockmakeStep置,最后重绘界面每局游戏结束后会直接开始下一轮游戏调节定时器时间就可以加快游戏速度,提升难度pTimer=new QTimerthis;//控制重绘的时间间隔,可以控制游戏难pTimer-setInterval150;度connectpTimer QTimer::timeout this,z z[=]{//如果串口没有连接成功,则一直尝试ifpSerialPort-isOpen==false{DEBUG_coutstill try;QListQSerialPortInfo infoList=QSerialPortInfo::availablePorts;//如果连接上一个串口直接跳出,没有可用串口会在程序中不断循环杳找串口并尝试连接QSerialPortlnfo info;foreachinfo infoList{pSerialPort-setPortNameinfo.portName;zifpSerial Port-openQIODevice::Read Writebreak;ifthis-startFlag==true{//只有每次绘制的时候才会真正修改蛇的前进方向this-curDirection=this-preDirection;//判断是否增加长度以及是否游戏结束ifthis-isGameOver{//游戏结束后清除标志变量,以进行下一场游戏this-startFlag=false;pSnake=new SnakeQPointx_count/2y_count/2,5,ZcurDirection;makeFood;else{QPoint point=pSnake-getHeadLocation;//尝试前进一步pSnake-tryGo8ipoint,this-curDirection;//判断有没有吃到食物,,ifpoint==foodPoint{pSerialPort-write F,;//发送表示吃到食物F pSnake-addBlockthis-curDirection;//更新食物的位置this-makeFood;else{pSnake-makeStepcurDirection;this-update;};pTimer-start;游戏界面的绘制都在绘制事件响应函数函数内完成绘制过程很简单,就是把paintEvent蛇和食物画出来,在游戏没开始时,多绘制一行提示文字void Widget::paintEventQPaintEvent*eventQPainter painterthis;;painter.setBrushQColor#ffOOOOQListQPoint snake_body=pSnake-getBody;QPointpoint;foreachpoint,snake_body{painter.drawRectpoint.x*block_width,point.yO*block_height,block_width block_height;z。