前言
好久没更新了,新工作转做QT开发,周末写个小游戏练练手,大佬略过,开发环境Qt5.14.2 !
一、效果图
功能很简单,不到200行代码,直接上图
二、源码
代码如下,注释很详细,就不再说明
2.1 头文件
#ifndef SNAKEGAME_H
#define SNAKEGAME_H
#include <QMainWindow>
#include <QLabel>
#include <QList>
#include <QTimer>
// 蛇移动方向,上下左右
enum class Direction
{
Up = 1,
Down,
Left,
Right
};
class SnakeGame : public QMainWindow
{
Q_OBJECT
public:
explicit SnakeGame(QWidget *parent = 0);
~SnakeGame();
// 使用键盘控制方向
void keyPressEvent(QKeyEvent *event);
// 产生新食物
QLabel* getFood(void);
private slots:
// 蛇根据方向移动,调用一次移动一个步长
void snakeMove(void);
private:
const int m_iFoodSize{ 30 }; // 食物大小 矩形方块 一个步长等于一个食物大小
QLabel* m_lbFood{ nullptr }; // 随机生成的食物label
QList<QLabel*> m_lbListSnake{ }; // 蛇长度lable列表
QTimer* m_timerGame{ nullptr }; // 游戏定时器 蛇移动 刷新界面
Direction m_eSnakeMoveDir{ Direction::Up }; // 蛇移动方向
};
#endif // SNAKEGAME_H
2.2 源文件
#include "SnakeGame.h"
#include <QPalette>
#include <QTime>
#include <QPainter>
#include <QMessageBox>
SnakeGame::SnakeGame(QWidget *parent) :
QMainWindow(parent)
{
this->resize(800, 600);
// 随机数种子
qsrand(QTime::currentTime().msec());
// 生成蛇头,并设置成圆形
m_lbListSnake.push_back(getFood());
m_lbListSnake[0]->setStyleSheet(QString("QLabel{background-color:red; border-radius:%1px;}").arg(m_iFoodSize / 2));
// 生成食物
m_lbFood = getFood();
// 初始化游戏刷新定时器,连接槽函数
m_timerGame = new QTimer;
connect(m_timerGame, &QTimer::timeout, this, &SnakeGame::snakeMove);
m_timerGame->start(300);
}
SnakeGame::~SnakeGame()
{
}
void SnakeGame::keyPressEvent(QKeyEvent *event)
{
switch (event->key()) {
case Qt::Key_Up:
// 不允许反方向走
if(m_eSnakeMoveDir != Direction::Down)
{
m_eSnakeMoveDir = Direction::Up;
}
break;
case Qt::Key_Down:
if(m_eSnakeMoveDir != Direction::Up)
{
m_eSnakeMoveDir = Direction::Down;
}
break;
case Qt::Key_Left:
if(m_eSnakeMoveDir != Direction::Right)
{
m_eSnakeMoveDir = Direction::Left;
}
break;
case Qt::Key_Right:
if(m_eSnakeMoveDir != Direction::Left)
{
m_eSnakeMoveDir = Direction::Right;
}
break;
default:
break;
}
}
QLabel *SnakeGame::getFood()
{
// 创建食物
QLabel* lbFood = new QLabel(this);
lbFood->resize(m_iFoodSize, m_iFoodSize);
// 设置随机背景色
lbFood->setAutoFillBackground(true);
lbFood->setPalette(QPalette(QColor(qrand() % 256, qrand() % 256, qrand() % 256)));
lbFood->setFrameShape(QFrame::Box);
// 设置位置随机,位置为FoodSize的整数倍,起始位置要减去一个步长
int iPosX = ( qrand() % ( this->width() - m_iFoodSize) ) / m_iFoodSize * m_iFoodSize;
int iPosY = ( qrand() % ( this->height() - m_iFoodSize) ) / m_iFoodSize * m_iFoodSize;
lbFood->move(iPosX, iPosY);
lbFood->show();
return lbFood;
}
void SnakeGame::snakeMove()
{
// 蛇头移动前的坐标
int iSnakeHeadX = m_lbListSnake[0]->x();
int iSnakeHeadY = m_lbListSnake[0]->y();
// 撞墙结束游戏
if(iSnakeHeadX < 0 || iSnakeHeadY < 0 ||
iSnakeHeadX > this->width() || iSnakeHeadY > this->height())
{
QMessageBox::warning(this, "Tips", "game over!");
this->close();
}
// 撞到自己结束游戏,跳过蛇头,遍历列表
int iSnakeLen = m_lbListSnake.length();
for(auto i=1; i<iSnakeLen; i++)
{
if(iSnakeHeadX == m_lbListSnake[i]->x() && iSnakeHeadY == m_lbListSnake[i]->y())
{
QMessageBox::warning(this, "Tips", "game over!");
this->close();
}
}
// 当食物和蛇头重合时吃掉食物
if(iSnakeHeadX == m_lbFood->x() && iSnakeHeadY == m_lbFood->y())
{
// 食物插入蛇头列表
m_lbListSnake.push_back(m_lbFood);
// 再重新生成一个食物
m_lbFood = getFood();
}
// 后一个元素移动到前一个元素位置
for(auto i=iSnakeLen-1; i>0; --i)
{
m_lbListSnake[i]->move(m_lbListSnake[i-1]->pos());
}
// 移动一个步长,重新计算坐标
switch (m_eSnakeMoveDir) {
case Direction::Up:
iSnakeHeadY -= m_iFoodSize;
break;
case Direction::Down:
iSnakeHeadY += m_iFoodSize;
break;
case Direction::Left:
iSnakeHeadX -= m_iFoodSize;
break;
case Direction::Right:
iSnakeHeadX += m_iFoodSize;
break;
default:
break;
}
// 把蛇头移动到新坐标
m_lbListSnake[0]->move(iSnakeHeadX, iSnakeHeadY);
}
2.3 main函数
#include "SnakeGame.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
SnakeGame w;
w.show();
return a.exec();
}