c++ Qt 贪吃蛇小游戏

//Viewer.h
#pragma once
#include <QGraphicsView>
#include <QKeyEvent>
#include <QTimer>

class SheItem;

class Viewer :public QGraphicsView
{
	Q_OBJECT
public:
	enum class State
	{
		PAUSE,
		START
	};
	enum class Direction
	{
		UP,
		DOWN,
		LEFT,
		RIGHT
	};
	Viewer(QWidget* parent = nullptr);

	~Viewer();
	void keyPressEvent(QKeyEvent* event);
	void showMessage(const QString& message, int timeout = 0);
	void scored(int x = 1);
	void gameStart();
	void gamePause();
	void gameOver();
	
	int getSheWidth() { return _sheDiameter; }

signals:
	void mainWindowMessage(const QString&, int);
	void updateScoreLabel(int);
	void updateLevelLabel(int);

private:
	void start();
	void stop();
	void update();
	Direction _direction;
	QTimer* _timer;
	SheItem* _sheItem;
	State _state;
	int _sheDiameter;
	int _width;
	int _score;
	int _timeout;
	int _level;
	QGraphicsSimpleTextItem* _text;
};

//Viewer.cpp
#include <qDebug>
#include <windows.h>

#include "viewer.h"
#include "sheItem.h"


Viewer::Viewer(QWidget* parent) :
	QGraphicsView(parent),
	_direction(Direction::RIGHT),
	_width(50),
	_timeout(400),
	_sheDiameter(10),
	_state(State::PAUSE),
	_score(0),
	_level(0)
{
	_sheItem = new SheItem(_sheDiameter, _width, this);
	this->grabKeyboard();
	_timer = new QTimer(this);
	QGraphicsScene* scene = new QGraphicsScene(this);
	scene->setBackgroundBrush(Qt::gray);
	scene->setSceneRect(0, 0, (double)_width * _sheDiameter, (double)_width * _sheDiameter);
	this->setScene(scene);
	qDebug() << connect(_timer, &QTimer::timeout, this, &Viewer::update);
	QFont font;
	font.setFamily("微软雅黑");
	font.setPointSize(30);
	font.setCapitalization(QFont::Capitalize);
	_text = new QGraphicsSimpleTextItem();
	_text->setFont(font);
	_text->setZValue(10);
	this->scene()->addItem(_sheItem);
	this->scene()->addItem(_text);
}

Viewer::~Viewer()
{

}

void Viewer::keyPressEvent(QKeyEvent* event)
{
	if (_state != State::START) {
		event->ignore();
		return;
	}
	switch (event->key())
	{
	case Qt::Key_Left:
		if (_direction == Direction::RIGHT) {
			event->ignore();
			return;
		}
		_direction = Direction::LEFT;
		this->update();
		if (_state != State::START) {
			event->accept();
			return;
		}
		this->stop();
		this->start();
		event->accept();
		break;
		
	case Qt::Key_Right:
		if (_direction == Direction::LEFT) {
			event->ignore();
			return;
		}
		_direction = Direction::RIGHT;
		this->update();
		if (_state != State::START) {
			event->accept();
			return;
		}
		this->stop();
		this->start();
		event->accept();
		break;

	case Qt::Key_Up:
		if (_direction == Direction::DOWN) {
			event->ignore();
			return;
		}
		_direction = Direction::UP;
		this->update();
		if (_state != State::START) {
			event->accept();
			return;
		}
		this->stop();
		this->start();
		event->accept();
		break;

	case Qt::Key_Down:
		if (_direction == Direction::UP) {
			event->ignore();
			return;
		}
		_direction = Direction::DOWN;
		this->update();
		if (_state != State::START) {
			event->accept();
			return;
		}
		this->stop();
		this->start();
		event->accept();
		break;
	}
	
}

void Viewer::showMessage(const QString& message, int timeout)
{
	emit this->mainWindowMessage(message, timeout);
}

void Viewer::scored(int x)
{
	_score += x;
	while (_score >= (_level + 1) * 10) {
		_level++;
		emit updateLevelLabel(_level + 1);
	}
	emit updateScoreLabel(_score);
}

void Viewer::gameStart()
{
	emit updateLevelLabel(1);
	emit updateScoreLabel(0);
	_state = State::START;
	_direction = Direction::RIGHT;
	_text->setText("");
	this->start();
}

void Viewer::gamePause()
{
	_text->setText("pause!");
	_state = State::PAUSE;
	_timer->stop();
}

void Viewer::start()
{
	float timeout = _timeout;
	int i = _level;
	while (i){
		timeout *= 0.8;
		i--;
	}
	_timer->start(timeout);
}

void Viewer::gameOver()
{
	_text->setText("game over!");
	_state = State::PAUSE;
	_timer->stop();
	_sheItem->initialize();
	_level = 0;
	_score = 0;
}

void Viewer::stop()
{
	_timer->stop();
}

void Viewer::update()
{
	int k = _sheItem->move(_direction);
	switch (k)
	{
	case 0:break;
	case 1:this->scored(); break;
	case -1:
	case -2:this->gameOver(); break;
	}
}
#pragma once
#include <QGraphicsItem>
#include <QObject>
#include <list>

#include "viewer.h"


class SheItem :public QObject, public QGraphicsItem
{
	Q_OBJECT
	Q_INTERFACES(QGraphicsItem)
public:

	SheItem(int diameter, int width, Viewer* parent = nullptr);
	int move(Viewer::Direction direction);
	~SheItem();
	void initialize();
	QRectF boundingRect() const;
	void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = 0);
	void generateFood();

protected:
	std::list<QPoint> _path;
	QPoint _food;
	int _width;
	int _diameter;
};



//sheItem.cpp
#include <random>
#include <ctime>
#include <algorithm>

#include "sheItem.h"


int SheItem::move(Viewer::Direction direction)
{
	QPoint point;
	switch (direction)
	{
	case Viewer::Direction::UP:
		point = QPoint(_path.front().x(), _path.front().y() - 1);
		break;
	case Viewer::Direction::DOWN:
		point = QPoint(_path.front().x(), _path.front().y() + 1);
		break;
	case Viewer::Direction::LEFT:
		point = QPoint(_path.front().x() - 1, _path.front().y());
		break;
	case Viewer::Direction::RIGHT:
		point = QPoint(_path.front().x() + 1, _path.front().y());
		break;
	default:
		return 0;
	}
	if (point.x() < 0 || point.x() >= _width || point.y() < 0 || point.y() >= _width) {
		return -1;
	}
	if (point == _food) {
		_path.push_front(point);
		generateFood();
		update();
		return 1;
	}
	if (std::find(_path.begin(), _path.end(), point) != _path.end()) {
		return -2;
	}
	_path.push_front(point);
	_path.pop_back();
	update();
	return 0;
}
SheItem::SheItem(int diameter, int width, Viewer* parent) :
	QObject(parent),
	_diameter(diameter),
	_width(width)
{
	srand(std::clock());
	_path.push_front(QPoint(_width / 2 - 1, _width / 2));
	_path.push_front(QPoint(_width / 2, _width / 2));
	_path.push_front(QPoint(_width / 2 + 1, _width / 2));
	this->generateFood();
	this->setPos(QPoint());
}
SheItem::~SheItem()
{

}

void SheItem::initialize()
{
	_path.clear();
	_path.push_front(QPoint(_width / 2 - 1, _width / 2));
	_path.push_front(QPoint(_width / 2, _width / 2));
	_path.push_front(QPoint(_width / 2 + 1, _width / 2));
	this->generateFood();
}

QRectF SheItem::boundingRect() const
{
	return QRectF(0, 0, (double)_width * _diameter, (double)_width * _diameter);
}

void SheItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
	QPen pen(Qt::black, (double)_diameter - 1);
	painter->setPen(pen);
	for (const auto& point : _path) {
		painter->drawPoint(point * _diameter);
	}
	pen.setColor(Qt::red);
	painter->setPen(pen);
	painter->drawPoint(_food * _diameter);
	pen.setColor(Qt::green); 
	pen.setWidth(1);
	painter->setPen(pen);
	QRectF rect = this->boundingRect();
	rect = QRectF(rect.x() - 3, rect.y() - 3, rect.width() + 6 - _diameter, rect.height() + 6 - _diameter);
	painter->drawRect(rect);
}

void SheItem::generateFood()
{
	QPoint point(rand() % _width, rand() % _width);
	while (std::find(_path.begin(), _path.end(), point) != _path.end()) {
		point = QPoint(rand() % _width, rand() % _width);
	}
	_food = point;
}

//tanchishe.h
#pragma once

#include <QtWidgets/QMainWindow>
#include "ui_tanchishe.h"

class tanchishe : public QMainWindow
{
	Q_OBJECT

public:
	tanchishe(QWidget *parent = Q_NULLPTR);

private:
	Ui::tanchisheClass ui;

};
//tanchishe.cpp
#include <QDebug>

#include "tanchishe.h"

tanchishe::tanchishe(QWidget *parent)
	: QMainWindow(parent)
{
	ui.setupUi(this);
	QFont font;
	font.setFamily("微软雅黑");
	font.setPointSize(28);
	ui.scoreLabel->setFont(font);
	ui.levelLabel->setFont(font);
	qDebug() << connect(ui.view, &Viewer::updateScoreLabel, ui.scoreLabel, static_cast<void (QLabel::*)(int)>(&QLabel::setNum));
	qDebug() << connect(ui.view, &Viewer::updateLevelLabel, ui.levelLabel, static_cast<void (QLabel::*)(int)>(&QLabel::setNum));
	qDebug() << connect(ui.startButton, &QPushButton::clicked, ui.view, &Viewer::gameStart);
	qDebug() << connect(ui.pauseButton, &QPushButton::clicked, ui.view, &Viewer::gamePause);
}
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值