这次给大家分享我制作的贪吃蛇——
首先,利用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 20
enum 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 *e
void 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;
}
至此,“贪吃蛇”游戏已制作完成,大家可运行测试,自己玩以下自己亲手制作的游戏。
本文暂时没有评论,来添加一个吧(●'◡'●)