耍过贪吃蛇的朋友应该都知道运行起来,看着很简单,但是,实际在用代码写的时候,有一个逻辑判断会思考很久~就是贪吃蛇在拐弯的时候,怎么计算在连续多次拐弯的情况下,你绘制出来的贪吃蛇是不会断成几节,而且能够按照正确的路线进行行驶! 1.我这里采用的是
1.我这里采用的是一个map进行管理,将贪吃蛇所有的点存入到map中,然后进行实时的对数据进行更新
2.其他的话,就没有什么技术难点了,就是如何设计绘制贪吃蛇的位置刷新以及方框、随机原点的绘制;
我采取的是一个定时器的方式,每500ms进行一次刷新;对于绘制的话,需要将代码放置在:paintEvent()这个函数中,你将函数放置在其他位置,绘制都是无效的
源码链接:http://pan.baidu.com/s/1pL3Xq6v 密码:osq8 <无>
#ifndef SNAKE_H #define SNAKE_H #include <QMainWindow> #include <QGraphicsView> #include <QTimer> #include <QKeyEvent> #include <map> using namespace std; namespace Ui { class CSnake; } enum dirType { leftPos = 1, topPos = 2, rightPos = -1, bottomPos = -2, invaild = 0 }; typedef struct Point { int iX; int iY; dirType type; Point() { iX = 0; iY = 0; type = invaild; } }stPoint; class CSnake : public QMainWindow { Q_OBJECT public: explicit CSnake(QWidget *parent = 0); ~CSnake(); /*********************************** * 功 能:界面初始化函数 * 参 数:无 * 返回值:无 ***********************************/ void init(); /*********************************** * 功 能:绘制线条 * 参 数:无 * 返回值:无 ***********************************/ virtual void paintEvent(QPaintEvent *event); /*********************************** * 功 能:随机的产生一个白点 * 参 数:无 * 返回值:无 ***********************************/ void showPoint(); /*********************************** * 功 能:显示蛇 * 参 数:无 * 返回值:无 ***********************************/ void showSnake(); /*********************************** * 功 能:键盘按下事件 * 参 数:无 * 返回值:无 ***********************************/ void keyPressEvent(QKeyEvent *event) ; /*********************************** * 功 能:判断蛇是否吃到了蛇 * 参 数:无 * 返回值:无 ***********************************/ void checkFood(); private: Ui::CSnake *ui; //标志位 //是否需要刷新贪吃蛇 bool bInit; //是否需要刷新随机白点 bool bFlag; //设置背景颜色 QPalette* palette; //产生点的位置 int iX; int iY; //定义蛇的运行方向 dirType curType; //存储之前的运行方向 dirType preType; //记录蛇的长度 int iLen; //用该map进行蛇的绘制 map<int,stPoint> mapSnake; //用一个定时器让蛇进行轨迹的运行 QTimer* timer; private slots: /*********************************** * 功 能:让蛇进行运动 * 参 数:无 * 返回值:无 ***********************************/ void snakeRun(); }; #endif // SNAKE_H
#include "snake.h" #include "ui_snake.h" #include <QMessageBox> #include <QtAlgorithms> #include <QTime> #define ILARGE 20 CSnake::CSnake(QWidget *parent) : QMainWindow(parent), ui(new Ui::CSnake) { ui->setupUi(this); bFlag = true; bInit = false; //设置整个背景为黑色 palette = new QPalette; palette->setColor(QPalette::Background, QColor(100,100,100)); this->setPalette(*palette); iLen = 0; //定时器的初始化 timer = new QTimer; connect(timer,SIGNAL(timeout()),this,SLOT(snakeRun())); timer->start(500); //初始化 init(); } CSnake::~CSnake() { delete ui; if(timer) { delete timer; timer = NULL; } } void CSnake::init() { //判断蛇的运行轨迹 //判断X轴运行轨迹 if(iX <= 4) { curType = bottomPos; } else if(iX >= rect().height() / ILARGE - 4) { curType = topPos; } //判断Y轴运行轨迹 if(iY <=4) { curType = rightPos; } else if(iY >= rect().width() / ILARGE - 4) { curType = leftPos; } curType = topPos; } void CSnake::paintEvent(QPaintEvent *event) { //用线条绘制表格 QPainter painter(this); QPen pen; pen.setColor(Qt::black); painter.setPen(pen); int sum = rect().height() / ILARGE ; //绘制横向的线条 for(int i = 0 ; i < sum ; i++) { painter.drawLine(0,i*ILARGE,rect().width(),i*ILARGE); } //绘制纵向的线条 sum = rect().width() / ILARGE ; for(int i = 0 ;i < sum ; i++) { painter.drawLine(i*ILARGE,0,i*ILARGE,rect().height()); } //获得点的位置 showPoint(); //绘制点,并让尽量显示在方框中间 painter.setBrush(Qt::white); painter.drawEllipse(iX * ILARGE + 5,iY * ILARGE + 5,10,10); //显示蛇 showSnake(); //遍历转弯点 map<int,stPoint>::iterator iter; for(iter = mapSnake.begin() ; iter != mapSnake.end() ; iter++) { //如果是头的话,将蛇的头用红色的方框表示 if(iter == mapSnake.begin()) { painter.setBrush(Qt::red); } else { painter.setBrush(Qt::white); } painter.drawRect(iter->second.iX * ILARGE,iter->second.iY * ILARGE , ILARGE , ILARGE); } } void CSnake::showPoint() { //随机产生一个白点 if(bFlag) { int iWidth = rect().width() / ILARGE ; int iHeight = rect().height() / ILARGE; //让时间作为随机的种子,这样才能相对更随机 QTime time; time= QTime::currentTime(); qsrand(time.msec()+time.second()*1000); iX = qrand()% iWidth; iY = qrand() % iHeight; bFlag = false; } } void CSnake::showSnake() { //判断蛇是否吃到了东西 checkFood(); if(!bInit) { //随机产生一个白色方点 int iWidth = rect().width() / ILARGE ; int iSnakeX = rand() % iWidth; int iHeight = rect().height() / ILARGE; int iSnakeY = rand() % iHeight; bInit = true; stPoint pos; //记录蛇的位置信息 pos.iX = iSnakeX; pos.iY = iSnakeY; pos.type = curType; mapSnake.insert(make_pair(iLen, pos)); iLen++; } else { map<int,stPoint>::iterator iter ; //下一个需要紧随上一个步伐走 for(int i = iLen - 1 ; i >= 0 ; i--) { int iTmp = i; iTmp--; if(iTmp >= 0) { mapSnake[i].iX = mapSnake[iTmp].iX; mapSnake[i].iY = mapSnake[iTmp].iY; mapSnake[i].type = mapSnake[iTmp].type; } } iter = mapSnake.begin(); //判断下一帧的运行方向 switch (curType) { //x轴减少,Y轴不变 case leftPos: { iter->second.iX--; break; } //x不变,Y轴减少 case topPos: { iter->second.iY--; break; } //x增加,Y轴不变 case rightPos: { iter->second.iX++; break; } //x增加,Y轴不变 case bottomPos: { iter->second.iY++; break; } default: break; } } } void CSnake::keyPressEvent(QKeyEvent *event) { map<int,stPoint>::iterator iter; iter = mapSnake.begin(); if(event->key() == Qt::Key_Left) { curType = leftPos; } else if(event->key() == Qt::Key_Up) { curType = topPos; } else if(event->key() == Qt::Key_Right) { curType = rightPos; } else if(event->key() == Qt::Key_Down) { curType = bottomPos; } //改变头的方向 iter->second.type = curType; } void CSnake::checkFood() { map<int,stPoint>::iterator iBegin; iBegin = mapSnake.begin(); if(iX == iBegin->second.iX && iY == iBegin->second.iY) { bFlag = true; //找到最后一个点,根据最后点的运行方向,在后面添加方框 map<int,stPoint>::iterator iter; iter = mapSnake.end(); iter--; stPoint pos; switch (iter->second.type) { //往左走,则在右边的方框添加 case leftPos: { //y不变,x增加 pos.iX = iter->second.iX + 1; pos.iY = iter->second.iY; pos.type = iter->second.type; break; } case topPos: { //x不变,y增加 pos.iX = iter->second.iX ; pos.iY = iter->second.iY + 1; pos.type = iter->second.type; break; } case rightPos: { //y不变,x增加 pos.iX = iter->second.iX - 1; pos.iY = iter->second.iY; pos.type = iter->second.type; break; } case bottomPos: { //y不变,x增加 pos.iX = iter->second.iX ; pos.iY = iter->second.iY - 1; pos.type = iter->second.type; break; } default: break; } mapSnake.insert(make_pair(iLen , pos)); iLen++; } } void CSnake::snakeRun() { //判断,如果相加为0,代表死掉 int sum = curType + preType; if( sum == 0) { timer->stop(); QMessageBox::warning(0 , "提示" , "Game over!"); //程序结束 qApp->quit(); } else { //先改变之前存储的方向 preType = curType; int iWidth = rect().width() / ILARGE ; int iHeight = rect().height() / ILARGE; //判断是否撞墙死亡 if(mapSnake[0].iX < 0 || mapSnake[0].iY < 0 || mapSnake[0].iX > iWidth || mapSnake[0].iY > iHeight) { timer->stop(); QMessageBox::warning(0 , "提示" , "Game over!"); //程序结束 qApp->quit(); } //判断是否自己把自己咬住了 map<int,stPoint>::iterator iter; bool bDead = false; iter = mapSnake.begin(); for( iter++ ; iter != mapSnake.end() ; iter++) { if(mapSnake[0].iX == iter->second.iX && mapSnake[0].iY == iter->second.iY) { bDead = true; break; } } if(bDead) { timer->stop(); QMessageBox::warning(0 , "提示" , "Game over!"); //程序结束 qApp->quit(); } //让蛇按照之前的当前的运行方向进行运动 update(); } }
#include "snake.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); CSnake w; w.show(); w.setWindowTitle("贪吃蛇——made by HNN"); return a.exec(); }