“添加”->“添加文件”,打开所有的资源文件,再“保存所有文件”即可。这时,我们可以看到多了如下这些文件——2、设置标题、背景以及图标以及" />
首页 > 文章资讯 > 新闻资讯
Qt 贪吃蛇制作(含源码)
更新时间:2022-04-16 08:00:35 作者:云寺手游

这次给大家分享我制作的贪吃蛇——

首先,利用qt creator新建一个工程(不带ui界面)。如何创建一个工程,在上一篇文章已介绍,这里不再赘述。

1.添加资源文件

在工程里面新建一个名为res的文件夹,将所需要的图片资源拷贝过来。然后,右键点击工程名->添加新文件 -> Qt -> Qt ResourceFile->输入名称->完成。





接着,点击“添加”->"添加前缀”->“添加”->“添加文件”,打开所有的资源文件,再“保存所有文件”即可。





这时,我们可以看到多了如下这些文件——


2、设置标题、背景以及图标以及窗口大小等

在mainwindow.cpp的构造函数中添加如下代码:

this->setFixedSize(800, 480); setWindowIcon(QIcon(":/new/prefix1/res/bitbug_favicon.ico")); setWindowTitle("贪吃蛇"); this->setStyleSheet("QMainWindow{border-image: url(:/new/prefix1/res/page2.jpg);}");

测试运行,效果如下:


3、添加“点心”

接着,先给大蛇添加美味的“点心”。该“点心”可在界面任意空闲的位置出现。实现过程如下:

实现添加一个新类——Dessert。右击项目名称->添加新文件->C++ -> C++Class ,定义类名,最后“完成”。





完成之后,我们可以看到,项目中多了两个文件——dessert.h和dessert.cpp。然后我们在dessert.h添加如下代码:

int x; //点心的x轴坐标 int y; //点心的y轴坐标 QPushButton *btn; //用作设置背景 void makeDessert(Snake *h); //制造点心 Snake是我们大蛇链表的头节点,在后面才实现它

在dessert.cpp的构造函数中实现如下代码:

x = 0; y = 0; btn = new QPushButton(parent); btn->setFixedSize(20, 20); //点心图片的大小 btn->setStyleSheet("border-image: url(:/new/prefix1/res/eat.ico);"); //添加图片 srand((unsigned)time(NULL)); //为了产生随机数

在后面还要实现makeDessert函数:

void Dessert::makeDessert(Snake *h){ bool circle = false; Snake *p = NULL; while(1) { x = rand()%38+1; //产生随机值 不能与周围的“墙壁”重合 y = rand()%22+1; btn->move(x * 20, y * 20); p = h->next; while (p != NULL) { if(p->x == x && p->y == y) //不能与大蛇本身冲突 { circle = true; break; } p = p->next; } if(!circle) break; }}

然后,在mainwindow.h中添加它的头文件#include "dessert.h",并在类中定义它的一个对象:

Dessert *dessert;

之后,在mainwindow.cpp中的构造函数里实现它的初始化:

dessert = new Dessert(this);dessert->makeDessert(head);

完成之后,我们可以先注释掉与Snake有关的代码,运行测试以下:

void Dessert::makeDessert()//void Dessert::makeDessert(Snack *h){ bool circle = false;// Snack *p = NULL;// while(1) { x = rand()%38+1; y = rand()%22+1; btn->move(x * 20, y * 20);/* p = h->next; while (p != NULL) { if(p->x == x && p->y == y) { circle = true; break; } p = p->next; } if(!circle) break;*/ }}


可以看到,界面中多了一个红色的东西。然后我们再将刚才的注释取消。

4、初始化大蛇

首先,我们像刚才添加“点心”一样,添加两个文件——snake.cpp和snake.h(前面已有详细描述,这里不再赘述)。

然后,我们再snake.h实现如下代码:

#ifndef SNACK_H#define SNACK_H#include <QRect>#include <QPushButton>#include <QPixmap>#include <QMainWindow>#define SIZE 20enum Director{ UP, DOWN, LEFT, RIGHT,};class Snake{public: Snake(QMainWindow *parent); ~Snake(); int x; int y; //表示节点的坐标 QPushButton *btn; //用来设置设置背景 Snake *next; //用来指向下一个节点};#endif // SNACK_H

在snake.cpp中实现如下代码:

#include "snake.h"snake::snake(QMainWindow *parent){}snake::~snake(){}

之后,在mainwindow.h添加它的头文件#include "snack.h",并定义一个它的对象和初始化函数:

Snack *head; //大蛇链表的头结点void Snake_Init(int size);

接着,在mainwindow.cpp的构造函数中实现调用Snack_Init函数实现大蛇的初始化:

Snake_Init(5); //参数5代表大蛇的长度

注意:Snake_Init函数必须在“点心”的初始化之前调用。

之后,实现Snake_Init函数:

void MainWindow::Snack_Init(int size){ head = new Snack(this); head->x = 400; head->y = 240; head->next = NULL; Snack *p = NULL; while(size--) { p = head; while(p->next != NULL) { p = p->next; } Snack *node = new Snack(this); node->x = p->x - SIZE; node->y = p->y; node->btn = new QPushButton(this); node->btn->setFixedSize(SIZE, SIZE); node->btn->move(node->x, node->y); p->next = node; node->next = NULL; } //snack head p = head->next; p->btn->setStyleSheet("border-image: url(:/new/prefix1/res/right.png);"); //snack body while(p->next->next != NULL) { p = p->next; p->btn->setStyleSheet("border-image: url(:/new/prefix1/res/she.png);"); } //snack tail p->next->btn->setStyleSheet("border-image: url(:/new/prefix1/res/tou_left.png);");}


5、实现大蛇移动

接下来,我们我们将要用到一个定时器,实现大蛇的移动。

在mainwindow.h的类中实现添加如下代码:

QTimer *my_timer; //定时器Director dir; //大蛇移动的方向void setBackground(); void keyPressEvent(QKeyEvent *evoid setBackground(); //设置大蛇背景 void keyPressEvent(QKeyEvent *e) //键盘按键事件public slots: void snake_run(); //定时器超时函数

在mainwindow.cpp的构建函数实现相关初始化:

my_timer = new QTimer(this);connect(my_timer, &QTimer::timeout, this, &MainWindow::snake_run); //将snack_run槽函数连接定时器的超时信号my_timer->start(500); //设置定时器的超时时间,并启动定时器dir = RIGHT; //大蛇初始向右移动

实现槽函数snake_run,实现大蛇移动。它的原理是:删除链表最后一个节点,在头结点后插入新节点——

void MainWindow::snack_run(){ switch (dir) { case UP: { Snake *node = new Snack(this); node->x = head->next->x; node->y = head->next->y - 20; node->btn = new QPushButton(this); node->btn->setFixedSize(20, 20); node->btn->move(node->x, node->y); node->next = head->next; head->next = node; break; } case RIGHT: { Snake *node = new Snack(this); node->x = head->next->x + 20; node->y = head->next->y; node->btn = new QPushButton(this); node->btn->setFixedSize(20, 20); node->btn->move(node->x, node->y); node->next = head->next; head->next = node; break; } case DOWN: { Snake *node = new Snack(this); node->x = head->next->x; node->y = head->next->y + 20; node->btn = new QPushButton(this); node->btn->setFixedSize(20, 20); node->btn->move(node->x, node->y); node->next = head->next; head->next = node; break; } case LEFT: { Snake *node = new Snack(this); node->x = head->next->x - 20; node->y = head->next->y; node->btn = new QPushButton(this); node->btn->setFixedSize(20, 20); node->btn->move(node->x, node->y); node->next = head->next; head->next = node; break; } default: break; } if(head->next->x < 20 || head->next->x >= 780 || head->next->y < 20 || head->next->y >= 460 || snake_crash()) //大蛇碰到周围的“墙壁”或撞到自己 { my_timer->stop(); //停止定时器 this->setStyleSheet("QMainWindow{border-image: url(:/new/prefix1/res/gameover.png);}"); return ; } else if(head->next->x == dessert->x*20 && head->next->y == dessert->y*20) //吃到美味“点心” { dessert->makeDessert(head); } else { Snack *p = head; while(p->next->next != NULL) { p = p->next; } delete(p->next->btn); delete(p->next); p->next = NULL; } setBackground(); //设置背景}

实现setBackground函数,设置大蛇的背景:

void MainWindow::setBackground(){ switch (dir) { case UP: { head->next->btn->setStyleSheet("border-image: url(:/new/prefix1/res/up.png);"); break; } case RIGHT: { head->next->btn->setStyleSheet("border-image: url(:/new/prefix1/res/right.png);"); break; } case LEFT: { head->next->btn->setStyleSheet("border-image: url(:/new/prefix1/res/left.png);"); break; } case DOWN: { head->next->btn->setStyleSheet("border-image: url(:/new/prefix1/res/down.png);"); break; } default: break; } head->next->btn->show(); Snack *pre = head->next; Snack *current = pre->next; Snack *next = current->next; while(next != NULL) { if(((pre->x<current->x) && (pre->y==current->y) && (current->x==next->x)&&(current->y>next->y)) || (next->x<current->x && current->y==next->y && pre->x==current->x && pre->y<current->y)) { current->btn->setStyleSheet("border-image: url(:/new/prefix1/res/up_left.png);"); } else if((pre->x<current->x && pre->y==current->y && current->x==next->x && current->y<next->y) || (next->x<current->x && current->y==next->y && pre->x==current->x && pre->y>current->y)) { current->btn->setStyleSheet("border-image: url(:/new/prefix1/res/left_down.png);"); } else if((pre->x==current->x && pre->y>current->y && current->x<next->x && current->y==next->y) || (next->x==current->x && current->y<next->y && pre->x>current->x && pre->y==current->y)) { current->btn->setStyleSheet("border-image: url(:/new/prefix1/res/right_down.png);"); } else if((pre->x==current->x && pre->y<current->y &¤t->x<next->x && current->y==next->y) || (next->x==current->x && current->y>next->y && pre->x>current->x && pre->y==current->y)) { current->btn->setStyleSheet("border-image: url(:/new/prefix1/res/up_right.png);"); } else { current->btn->setStyleSheet("border-image: url(:/new/prefix1/res/she.png);"); } current->btn->show(); pre = pre->next; current = current->next; next = next->next; } if((pre->x<current->x) && (pre->y==current->y)) { current->btn->setStyleSheet("border-image: url(:/new/prefix1/res/tou_right.png);"); } else if(pre->x>current->x && pre->y==current->y) { current->btn->setStyleSheet("border-image: url(:/new/prefix1/res/tou_left.png);"); } else if(pre->x==current->x && pre->y>current->y) { current->btn->setStyleSheet("border-image: url(:/new/prefix1/res/tou_up.png);"); } else if(pre->x==current->x && pre->y<current->y) { current->btn->setStyleSheet("border-image: url(:/new/prefix1/res/tou_down.png);"); } current->btn->show();}

实现keyPressEvent函数,控制大蛇的方向(w、a、s、d分别对应上、左、下、右):

void MainWindow::keyPressEvent(QKeyEvent *e){ switch (e->key()) { case Qt::Key_W: { if(dir != DOWN) dir = UP; break; } case Qt::Key_A: { if(dir != RIGHT) dir = LEFT; break; } case Qt::Key_D: { if(dir != LEFT) dir = RIGHT; break; } case Qt::Key_S: { if(dir != UP) dir = DOWN; break; } default: break; }}

实现snake_crash函数,检测大蛇有没有”吃"到自己:

bool MainWindow::snake_crash(){ Snake *h = head->next; Snack *p = h->next; while (p != NULL) { if(h->x == p->x && h->y == p->y) { return true; } p = p->next; } return false;}

至此,“贪吃蛇”游戏已制作完成,大家可运行测试,自己玩以下自己亲手制作的游戏。


猜你喜欢
最新资讯