From 40174287f39e08fbeebb46c0e2099df4f83136ed Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Wed, 15 May 2019 15:00:52 +0200 Subject: Improve graphics rendering --- src/mainwindow.cpp | 20 ++++++- src/mainwindow.h | 8 +++ src/snake.cpp | 172 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/snake.h | 33 ++++++++++ 4 files changed, 232 insertions(+), 1 deletion(-) create mode 100644 src/snake.cpp create mode 100644 src/snake.h diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 15736f0..a9ff11e 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -27,13 +27,16 @@ #include "settings.h" #include "global.h" +#include "snake.h" + MainWindow::MainWindow(bool primary, int screen, const QRect &screenRect, QWidget *parent) : QWidget(parent), m_ScreenRect(screenRect), m_Primary(primary), m_LoginForm(nullptr), m_messages(nullptr), - m_Clock(nullptr) + m_Clock(nullptr), + m_Snake(nullptr) { setObjectName(QString("MainWindow_%1").arg(screen)); @@ -109,6 +112,21 @@ MainWindow::~MainWindow() { } +void MainWindow::paintEvent(QPaintEvent *event) +{ + QWidget::paintEvent(event); + if (m_Snake != nullptr) { + m_Snake->paint(event); + } +} + +void MainWindow::mouseDoubleClickEvent(QMouseEvent *) +{ + if (m_Snake == nullptr) { + m_Snake = new Snake(this); + } +} + QSize MainWindow::createLogo(QRect max) { QSize retval(0, 0); diff --git a/src/mainwindow.h b/src/mainwindow.h index b6a756c..02db75e 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -23,6 +23,8 @@ namespace Ui { class QTextEdit; +class Snake; + class MainWindow : public QWidget { Q_OBJECT @@ -49,6 +51,11 @@ public: LoginForm* loginForm() { return m_LoginForm; } +protected: + virtual void paintEvent(QPaintEvent *event); + + virtual void mouseDoubleClickEvent(QMouseEvent *); + public slots: void showStandby(); void updateClock(); @@ -63,6 +70,7 @@ private: QImage m_background; QTextEdit *m_messages; QLabel *m_Clock; + Snake *m_Snake; }; #endif // MAINWINDOW_H diff --git a/src/snake.cpp b/src/snake.cpp new file mode 100644 index 0000000..6f18670 --- /dev/null +++ b/src/snake.cpp @@ -0,0 +1,172 @@ +#include "snake.h" + +#include +#include +#include +#include +#include +#include + +#define SCALING (16) + +#define DIR_UP 0 +#define DIR_DOWN 1 +#define DIR_LEFT 2 +#define DIR_RIGHT 3 + +#define FIELD(x,y) _field[(x) + ((y) * _width)] +#define FIELD_FREE 0 +#define FIELD_SNAKE 1 +#define FIELD_FOOD 2 + +Snake::Snake(QWidget *widget) + : _widget(widget), + _field(nullptr), + _direction(DIR_UP) +{ + _width = widget->width() / SCALING; + _height = widget->height() / SCALING; + _snakeLen = 5; + if (_width <= 0 || _height <= 0) + return; + _field = (int*)calloc(_width * _height, sizeof(*_field)); + _x = _y = -1; + qDebug() << "Field:" << _width << _height; + QTimer *t = new QTimer(widget); + t->start(100); + // Game logic + QTimer::connect(t, &QTimer::timeout, [this]() { + switch (_direction) { + case DIR_UP: + _y--; break; + case DIR_DOWN: + _y++; break; + case DIR_LEFT: + _x--; break; + case DIR_RIGHT: + _x++; break; + } + if (_x < 0 || _x >= _width || _y < 0 || _y >= _height || + FIELD(_x, _y) == FIELD_SNAKE) { + // Snek ded + qDebug() << "DEATH"; + memset(_field, 0, sizeof(*_field) * _width * _height); + _x = _width / 2; + _y = _height / 2; + _snake.clear(); + _widget->update(); + _snakeLen = 5; + addFood(); + return; + } + // Normal + if (_snake.size() >= _snakeLen) { + const QPoint &p = _snake.front(); + if (FIELD(p.x(), p.y()) == FIELD_SNAKE) { + FIELD(p.x(), p.y()) = FIELD_FREE; + _widget->update(p.x() * SCALING, p.y() * SCALING, SCALING, SCALING); + } + _snake.pop_front(); + } + if (FIELD(_x, _y) == FIELD_FOOD) { + if (qrand() % _snakeLen > 40) { + _snakeLen = 10; + while (_snake.size() > _snakeLen) { + _snake.pop_front(); + } + addFood(); + } else { + _snakeLen += 5; + } + addFood(); + } + FIELD(_x, _y) = FIELD_SNAKE; + _snake.append(QPoint(_x, _y)); + _widget->update(_x * SCALING, _y * SCALING, SCALING, SCALING); + // AI + int what[4], dist[4]; + int best = 0; + scanDir(0, -1, what[DIR_UP], dist[DIR_UP]); + scanDir(0, 1, what[DIR_DOWN], dist[DIR_DOWN]); + scanDir(-1, 0, what[DIR_LEFT], dist[DIR_LEFT]); + scanDir(1, 0, what[DIR_RIGHT], dist[DIR_RIGHT]); + for (int i = 1; i < 4; ++i) { + if (what[i] == FIELD_FOOD) { + if (what[best] != FIELD_FOOD || dist[best] > dist[i]) { + best = i; + } + } else if (what[best] != FIELD_FOOD && dist[i] > dist[best]) { + best = i; + } + } + if (what[best] == FIELD_FOOD) { + _direction = best; + } else if (dist[_direction] <= 1) { + _direction = best; + } + }); +} + +Snake::~Snake() +{ + free(_field); +} + +void Snake::scanDir(int dx, int dy, int &what, int &dist) +{ + int x = _x; + int y = _y; + dist = 0; + for (;;) { + x += dx; + y += dy; + dist++; + if (x < 0 || x >= _width || y < 0 || y >= _height) { + what = FIELD_SNAKE; + return; + } + if (FIELD(x, y) != FIELD_FREE) { + what = FIELD(x, y); + return; + } + } +} + +void Snake::addFood() +{ + for (int i = 0; i < 10; ++i) { + int x = qrand() % _width; + int y = qrand() % _height; + if (FIELD(x, y) != FIELD_FOOD) { + FIELD(x, y) = FIELD_FOOD; + _widget->update(x * SCALING, y * SCALING, SCALING, SCALING); + break; + } + } +} + +void Snake::paint(QPaintEvent *event) +{ + QPainter p(_widget); + const int width = qMin(_width, (event->rect().x() + event->rect().width() + SCALING - 1) / SCALING); + const int height = qMin(_height, (event->rect().y() + event->rect().height() + SCALING - 1) / SCALING); + for (int y = event->rect().y() / SCALING; y < height; ++y) { + if (y < 0) + continue; + for (int x = event->rect().x() / SCALING; x < width; ++x) { + if (x < 0) + continue; + switch (FIELD(x, y)) { + case FIELD_FOOD: + p.setBrush(Qt::green); + break; + case FIELD_SNAKE: + p.setBrush(Qt::white); + break; + default: + continue; + } + p.drawRect(x * SCALING, y * SCALING, SCALING-1, SCALING-1); + } + } +} diff --git a/src/snake.h b/src/snake.h new file mode 100644 index 0000000..502c53f --- /dev/null +++ b/src/snake.h @@ -0,0 +1,33 @@ +#ifndef _SNAKE_H_ +#define _SNAKE_H_ + +#include +#include + +class QWidget; +class QPaintEvent; + +class Snake +{ +private: + QWidget *_widget; + int *_field; + int _width, _height; + int _x, _y; + int _direction; + int _snakeLen; + QList _snake; + +public: + Snake(QWidget *widget); + + virtual ~Snake(); + + void paint(QPaintEvent *event); + + void addFood(); + + void scanDir(int x, int y, int &what, int &dist); +}; + +#endif -- cgit v1.2.3-55-g7522