From 5c92e0612ec7ae4ea329fa18792b94fcb5908cfd Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Sat, 25 May 2019 17:48:41 +0200 Subject: Add news panel to the right of the login form By pointing the new setting news-html-file to a file containing QTextEdit-compatible html formatted text, you can have a news panel show up on the login screen. --- src/mainwindow.cpp | 50 +++++- src/mainwindow.h | 8 +- src/settings.h | 1 + src/snake.cpp | 442 ++++++++++++++++++++++++++++++++++++++++------------- src/snake.h | 23 ++- 5 files changed, 402 insertions(+), 122 deletions(-) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 9c23c58..5bc38b9 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -49,6 +49,16 @@ MainWindow::MainWindow(bool primary, int screen, const QRect &screenRect, QWidge // display login dialog only in the main screen + /* + * Everything is layed out manually here, since I don't know how to represent the size constraints + * and interactions of everything using layout classes. You're welcome to improve this, but I double + * dare you to not break any combination of having/not having certain logos or elements displayed. + */ + + int newsY = 100; + int newsX = screenRect.width() / 2; + int newsBottom = screenRect.height(); + int spaceY = screenRect.height() / 2; if (showLoginForm()) { @@ -72,6 +82,7 @@ MainWindow::MainWindow(bool primary, int screen, const QRect &screenRect, QWidge int centerX = screenRect.width()/2 + screenRect.x(); int centerY = screenRect.height()/2 + screenRect.y(); QCursor::setPos(centerX, centerY); + newsX = m_LoginForm->geometry().right() + 5; } // Banner @@ -91,6 +102,7 @@ MainWindow::MainWindow(bool primary, int screen, const QRect &screenRect, QWidge yoff = 100; } banner->setGeometry((screenRect.width() - sh.width()) / 2, yoff / 2, sh.width(), sh.height()); + newsY = banner->geometry().bottom() + 10; } } int ls = (spaceY > 500 ? 500 : spaceY); @@ -100,12 +112,22 @@ MainWindow::MainWindow(bool primary, int screen, const QRect &screenRect, QWidge QSize logoSize = createLogo(logoRect); QRect distroRect(QPoint(screenRect.width() - ls, screenRect.height() - ls), QSize(ls, ls)); QSize distroSize = createDistro(distroRect); + if (distroSize.height() > 0) { + newsBottom -= distroSize.height() - 10; + } if (showLoginForm()) { + // Log window QRect lwSize(QPoint(logoSize.width(), screenRect.height() * 3/4), QPoint(screenRect.width() - distroSize.width(), screenRect.height())); lwSize.adjust(10, 10, -10, -10); - createLogWindow(lwSize); + if (createLogWindow(lwSize)) { + newsBottom = lwSize.top(); + } } createClock(); + + // News widget + QRect newsSize(QPoint(newsX, newsY), QPoint(screenRect.width() - 10, newsBottom - 10)); + createNewsWindow(newsSize); } MainWindow::~MainWindow() @@ -123,7 +145,7 @@ void MainWindow::paintEvent(QPaintEvent *event) void MainWindow::mouseDoubleClickEvent(QMouseEvent *) { if (m_Snake == nullptr) { - m_Snake = new Snake(this); + m_Snake = new GameCore(this); } else { m_Snake->addSnake(); } @@ -189,14 +211,14 @@ QSize MainWindow::createDistro(const QRect &max) return virtualSize; } -void MainWindow::createLogWindow(const QRect& geom) +bool MainWindow::createLogWindow(const QRect& geom) { QString path = Settings::logMessageFile(); if (path.isEmpty()) - return; + return false; QFile f(path); if (f.size() == 0 || !f.open(QFile::ReadOnly)) - return; + return false; m_messages = new QTextEdit(this); m_messages->setGeometry(geom); int ps = geom.height() / 20; @@ -223,6 +245,24 @@ void MainWindow::createLogWindow(const QRect& geom) } m_messages->setReadOnly(true); m_messages->setStyleSheet("border:none; background:rgba(255,255,255,.33); border-radius:5px"); + return true; +} + +void MainWindow::createNewsWindow(const QRect &size) +{ + if (size.width() < 100 || size.height() < 100) + return; + QString path = Settings::newsHtmlFile(); + if (path.isEmpty()) + return; + QFile f(path); + if (f.size() == 0 || !f.open(QFile::ReadOnly)) + return; + QTextEdit *news = new QTextEdit(this); + news->setReadOnly(true); + news->setStyleSheet("border:none; background:rgba(255,255,255,.33); border-radius:5px"); + news->setHtml(QString::fromUtf8(f.readAll())); + news->setGeometry(size); } void MainWindow::createClock() diff --git a/src/mainwindow.h b/src/mainwindow.h index 02db75e..ec153b7 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -23,7 +23,7 @@ namespace Ui { class QTextEdit; -class Snake; +class GameCore; class MainWindow : public QWidget { @@ -41,7 +41,9 @@ public: QSize createDistro(const QRect &max); - void createLogWindow(const QRect& geom); + bool createLogWindow(const QRect& geom); + + void createNewsWindow(const QRect &size); void createClock(); @@ -70,7 +72,7 @@ private: QImage m_background; QTextEdit *m_messages; QLabel *m_Clock; - Snake *m_Snake; + GameCore *m_Snake; }; #endif // MAINWINDOW_H diff --git a/src/settings.h b/src/settings.h index 420558c..97c8c28 100644 --- a/src/settings.h +++ b/src/settings.h @@ -37,6 +37,7 @@ public: static QString bottomLeftLogoDir() { return s_settings->value("greeter-bottom-left-logo-path").toString(); } static QStringList gradientColors() { return s_settings->value("greeter-background-gradient").toString().split(QRegExp("\\s"), QString::SkipEmptyParts); } static QString logMessageFile() { return s_settings->value("greeter-message-file").toString(); } + static QString newsHtmlFile() { return s_settings->value("news-html-file").toString(); } static QString autoLoginCheckCmd() { return s_settings->value("auto-login-check-cmd").toString(); } static QString clockStyle() { return s_settings->value("clock-text-style").toString(); } static QString clockBackgroundStyle() { return s_settings->value("clock-background-style").toString(); } diff --git a/src/snake.cpp b/src/snake.cpp index 79ced0d..9c3c4d0 100644 --- a/src/snake.cpp +++ b/src/snake.cpp @@ -19,6 +19,13 @@ #define CELL_WALL 1 #define CELL_SNAKE 2 #define CELL_FOOD 3 +#define CELL_BRICK 4 +#define CELL_SNAKEBRICK 5 + +#define AXIS_X 0 +#define AXIS_Y 1 + +#define FIELD(x,y) _field[(x) + ((y) * _width)] struct Cell { @@ -26,13 +33,46 @@ struct Cell QBrush color; Cell(int t, QColor c) : type(t), color(QBrush(c)) {} bool isFood() const { return type == CELL_FOOD; } - bool willKill() const { return type == CELL_WALL || type == CELL_SNAKE; } + bool willKill() const { return type == CELL_WALL || type == CELL_SNAKE || type == CELL_SNAKEBRICK; } bool isFree() const { return type == CELL_FREE; } - bool isWall() const { return type == CELL_WALL; } + bool isBrick() const { return type == CELL_BRICK || type == CELL_SNAKEBRICK; } + bool canSpawnFood() const { return type == CELL_SNAKE || type == CELL_FREE || type == CELL_BRICK; } + bool ballWillDestroy() const { return isFood() || isBrick(); } +}; + +struct Ball +{ + int x, y; + int dx, dy; + const Cell *cell; + QPoint gridPos; + Ball(int startX, int startY) : x(startX), y(startY), dx(qrand() % 4 + 1), dy(qrand() % 4 + 1), + cell(new Cell(CELL_WALL, QColor::fromHsv(qrand() % 360, 32 + qrand() % 64, 32 + qrand() % 64))) {} + virtual ~Ball() { delete cell; } +}; + +struct Paddle +{ + int x, y; + int axis; + int size; + const Cell *cell; + Paddle(int startX, int startY, GameCore *field, int ax) : x(startX), y(startY), axis(ax), size(5), + cell(new Cell(CELL_WALL, QColor::fromHsv(qrand() % 360, 192 + qrand() % 64, 192 + qrand() % 64))) { + for (int i = 0; i < size; ++i) { + if (axis == AXIS_X) { + field->setField(x + i, y, cell); + } else { + field->setField(x, y + i, cell); + } + } + } }; const Cell empty(CELL_FREE, QColor()); const Cell wall(CELL_WALL, QColor::fromRgb(80, 80, 90)); +const Cell snakebrick(CELL_SNAKEBRICK, QColor::fromRgb(200, 200, 200)); +const Cell brick(CELL_BRICK, QColor::fromRgb(255, 255, 255)); const Cell food[] = { Cell(CELL_FOOD, QColor::fromRgb(0, 255, 0)), Cell(CELL_FOOD, QColor::fromRgb(0, 200, 0)), @@ -40,141 +80,324 @@ const Cell food[] = { Cell(CELL_FOOD, QColor::fromRgb(0, 120, 0)), }; -#define FIELD(x,y) _field[(x) + ((y) * _width)] - -class RealSnake +class Snake { public: - int _x, _y; - int _direction; - int _snakeLen; - QList _snake; + int x, y; + int direction; + int len; + QList parts; Cell *cell; - RealSnake(int sx, int sy) : _x(sx), _y(sy), _direction(DIR_UP), _snakeLen(5), _snake(), + Snake(int sx, int sy) : x(sx), y(sy), direction(DIR_UP), len(5), parts(), cell(new Cell(CELL_SNAKE, QColor::fromHsv(qrand() % 360, 128 + qrand() % 128, 128 + qrand() % 128))) {} - virtual ~RealSnake() { delete cell; } + virtual ~Snake() { delete cell; } }; -Snake::Snake(QWidget *widget) +void GameCore::setField(int x, int y, const Cell *val) { + _field[x + _width * y] = val; + _widget->update(x * SCALING, y * SCALING, SCALING, SCALING); +} + +GameCore::GameCore(QWidget *widget) : _widget(widget), - _field(nullptr), _deaths(0), - _lastMeal(QDateTime::currentMSecsSinceEpoch()) + _lastMeal(QDateTime::currentMSecsSinceEpoch()), + _field(nullptr) { + qsrand((uint)_lastMeal); _width = widget->width() / SCALING; _height = widget->height() / SCALING; if (_width <= 0 || _height <= 0) return; initField(); + // Should be either 4 player pong or two player + tetris + // Bricks in the center also only make sense without tetris + _paddles.append(new Paddle(1, _height - 2, this, AXIS_X)); + _paddles.append(new Paddle(1, 1, this, AXIS_X)); + _paddles.append(new Paddle(_width - 2, 1, this, AXIS_Y)); + _paddles.append(new Paddle(1, 1, this, AXIS_Y)); + for (int y = 15; y < _height - 16; y += 3) { + for (int x = 15; x < _width - 16; x += 3) { + FIELD(x, y) = &brick; + FIELD(x + 1, y) = &brick; + FIELD(x, y + 1) = &brick; + FIELD(x + 1, y + 1) = &brick; + } + } qDebug() << "Field:" << _width << _height; addFood(); QTimer *t = new QTimer(widget); - t->start(100); - // Game logic + t->start(15); + // GAME QTimer::connect(t, &QTimer::timeout, [this]() { - for (RealSnake *snake : _snakes) { - // AI - const Cell* what[4]; - int dist[4]; - int best = 0; - scanDir(snake, 0, -1, what[DIR_UP], dist[DIR_UP]); - scanDir(snake, 0, 1, what[DIR_DOWN], dist[DIR_DOWN]); - scanDir(snake, -1, 0, what[DIR_LEFT], dist[DIR_LEFT]); - scanDir(snake, 1, 0, what[DIR_RIGHT], dist[DIR_RIGHT]); - for (int i = 1; i < 4; ++i) { - if (what[i]->isFood()) { - if (!what[best]->isFood() || dist[best] > dist[i]) { + // + static int tick = 0; + ++tick; + // SNAKE + if (tick % 6 == 0) { + for (Snake *snake : _snakes) { + // AI + const Cell* what[4]; + int dist[4]; + int best = 0; + scanDir(snake, 0, -1, what[DIR_UP], dist[DIR_UP]); + scanDir(snake, 0, 1, what[DIR_DOWN], dist[DIR_DOWN]); + scanDir(snake, -1, 0, what[DIR_LEFT], dist[DIR_LEFT]); + scanDir(snake, 1, 0, what[DIR_RIGHT], dist[DIR_RIGHT]); + for (int i = 1; i < 4; ++i) { + if (what[i]->isFood()) { + if (!what[best]->isFood() || dist[best] > dist[i]) { + best = i; + } + } else if (!what[best]->isFood() && (dist[i] > dist[best] || (dist[i] > 10 && qrand() % (4 * (4 - i)) == 0))) { best = i; } - } else if (!what[best]->isFood() && (dist[i] > dist[best] || (dist[i] > 10 && qrand() % (4 * (4 - i)) == 0))) { - best = i; - } - } - if (what[best]->isFood()) { - snake->_direction = best; - } else if (dist[snake->_direction] <= 1 || qrand() % 20 == 0) { - snake->_direction = best; - } - // Move - switch (snake->_direction) { - case DIR_UP: - snake->_y--; break; - case DIR_DOWN: - snake->_y++; break; - case DIR_LEFT: - snake->_x--; break; - case DIR_RIGHT: - snake->_x++; break; - } - if (snake->_x < 0 || snake->_x >= _width || snake->_y < 0 || snake->_y >= _height || - FIELD(snake->_x, snake->_y)->willKill()) { - // Snek ded - qDebug() << "DEATH"; - _snakes.removeAll(snake); - for (const QPoint &p : snake->_snake) { - if (FIELD(p.x(), p.y())->isFood()) - continue; - FIELD(p.x(), p.y()) = &wall; - _widget->update(p.x() * SCALING, p.y() * SCALING, SCALING, SCALING); } - delete snake; - if (_snakes.isEmpty()) { - initField(); - addSnake(); - addFood(); + if (what[best]->isFood()) { + snake->direction = best; + } else if (dist[snake->direction] <= 1 || qrand() % 20 == 0) { + snake->direction = best; } - return; // Skip rest of list for this tick since we removed a snake from the list while iterating - } - // Remove tail from field if snake reached desired length - if (snake->_snake.size() >= snake->_snakeLen) { - const QPoint &p = snake->_snake.front(); - if (FIELD(p.x(), p.y()) == snake->cell) { - FIELD(p.x(), p.y()) = ∅ - _widget->update(p.x() * SCALING, p.y() * SCALING, SCALING, SCALING); + // Move + switch (snake->direction) { + case DIR_UP: + snake->y--; break; + case DIR_DOWN: + snake->y++; break; + case DIR_LEFT: + snake->x--; break; + case DIR_RIGHT: + snake->x++; break; } - snake->_snake.pop_front(); - } - // Eat - if (FIELD(snake->_x, snake->_y)->isFood()) { - _lastMeal = QDateTime::currentMSecsSinceEpoch(); - if (qrand() % snake->_snakeLen > 40) { - // Snake break! - snake->_snakeLen = 10; - while (snake->_snake.size() > snake->_snakeLen) { - const QPoint &p = snake->_snake.front(); + if (snake->x < 0 || snake->x >= _width || snake->y < 0 || snake->y >= _height || + FIELD(snake->x, snake->y)->willKill()) { + // Snek ded + _snakes.removeAll(snake); + for (const QPoint &p : snake->parts) { if (FIELD(p.x(), p.y())->isFood()) continue; - FIELD(p.x(), p.y()) = &wall; - _widget->update(p.x() * SCALING, p.y() * SCALING, SCALING, SCALING); - snake->_snake.pop_front(); + setField(p.x(), p.y(), &snakebrick); + } + delete snake; + if (_snakes.isEmpty()) { + addSnake(); + } + break; // Skip rest of list for this tick since we removed a snake from the list while iterating + } + // Remove tail from field if snake reached desired length + if (snake->parts.size() >= snake->len) { + const QPoint &p = snake->parts.front(); + if (FIELD(p.x(), p.y()) == snake->cell) { + setField(p.x(), p.y(), &empty); + } + snake->parts.pop_front(); + } + // Eat + if (FIELD(snake->x, snake->y)->isFood()) { + _lastMeal = QDateTime::currentMSecsSinceEpoch(); + if (qrand() % snake->len > 40) { + // Snake break! + snake->len = 10; + while (snake->parts.size() > snake->len) { + const QPoint &p = snake->parts.front(); + if (FIELD(p.x(), p.y())->isFood()) + continue; + setField(p.x(), p.y(), &snakebrick); + snake->parts.pop_front(); + } + addFood(); + } else { + snake->len += 5; } addFood(); - } else { - snake->_snakeLen += 5; } + setField(snake->x, snake->y, snake->cell); + snake->parts.append(QPoint(snake->x, snake->y)); + } + // If no food was picked up within a minute, spawn more + if (QDateTime::currentMSecsSinceEpoch() - _lastMeal > 60000) { + _lastMeal = QDateTime::currentMSecsSinceEpoch(); addFood(); } - FIELD(snake->_x, snake->_y) = snake->cell; - snake->_snake.append(QPoint(snake->_x, snake->_y)); - _widget->update(snake->_x * SCALING, snake->_y * SCALING, SCALING, SCALING); } - // If no food was picked up within a minute, spawn more - if (QDateTime::currentMSecsSinceEpoch() - _lastMeal > 60000) { - _lastMeal = QDateTime::currentMSecsSinceEpoch(); - addFood(); + // + // Balls + Ball *bbottom = nullptr, *btop = nullptr, *bleft = nullptr, *bright = nullptr; + for ( Ball* ball : _balls) { + const QPoint old(ball->x / SCALING, ball->y / SCALING); + int nx = ball->x + ball->dx; + int ny = ball->y + ball->dy; + // Safety + if (nx < 0) { + nx = 0; + ball->dx = qAbs(ball->dx); + } else if (nx >= _width * SCALING) { + nx = _width * SCALING - 1; + ball->dx = -qAbs(ball->dx); + } + if (ny < 0) { + ny = 0; + ball->dy = qAbs(ball->dy); + } else if (ny >= _height * SCALING) { + ny = _height * SCALING - 1; + ball->dy = -qAbs(ball->dy); + } + // Collision + const QPoint noo(nx / SCALING, ny / SCALING); + if (old != noo && !FIELD(noo.x(), noo.y())->isFree()) { + bool one = false; + if (FIELD(old.x(), noo.y()) == ball->cell || FIELD(old.x(), noo.y())->isFree()) { + one = true; + if (old.x() > noo.x()) { + ball->dx = qAbs(ball->dx); + } else if (old.x() < noo.x()) { + ball->dx = -qAbs(ball->dx); + } + } + if (FIELD(noo.x(), old.y()) == ball->cell || FIELD(noo.x(), old.y())->isFree()) { + one = true; + if (old.y() > noo.y()) { + ball->dy = qAbs(ball->dy); + } else if (old.y() < noo.y()) { + ball->dy = -qAbs(ball->dy); + } + } + if (!one) { + ball->dx = -ball->dx; + ball->dy = -ball->dy; + } + // Destroy cell? + if (FIELD(noo.x(), noo.y())->ballWillDestroy()) { + if (FIELD(noo.x(), noo.y())->isFood()) { + // TODO: Make paddle that last touched the ball bigger + addFood(); + } + if (FIELD(noo.x(), noo.y())->isBrick()) { + for (int y = -1; y <= 1; ++y) { + for (int x = -1; x <= 1; ++x) { + if (FIELD(noo.x() + x, noo.y() + y)->isBrick()) { + setField(noo.x() + x, noo.y() + y, &empty); + } + } + } + } else { + setField(noo.x(), noo.y(), &empty); + } + } + } else { + // Free movevemnt + ball->gridPos = noo; + ball->x = nx; + ball->y = ny; + if (old != noo) { + if (FIELD(old.x(), old.y()) == ball->cell) { + setField(old.x(), old.y(), &empty); + } + setField(noo.x(), noo.y(), ball->cell); + } + } + if (bbottom == nullptr || (ball->dy > 0 && bbottom->y < ball->y)) { + bbottom = ball; + } + if (btop == nullptr || (ball->dy < 0 && btop->y > ball->y)) { + btop = ball; + } + if (bright == nullptr || (ball->dx > 0 && bright->x < ball->x)) { + bright = ball; + } + if (bleft == nullptr || (ball->dx < 0 && bleft->x > ball->x)) { + bleft = ball; + } + } + // Paddles + if (bbottom != nullptr) { + for (Paddle *paddle : _paddles) { + if (paddle->axis == AXIS_X) { + bool left = false, right = false; + Ball *check; + // Paddle moves along the X axis + if (paddle->y < 10) { + // Paddle is at top + check = btop; + } else { + // Paddle at bottom + check = bbottom; + } + if (paddle->x > 0 && check->gridPos.x() < paddle->x + paddle->size / 2) { + // Move left + left = true; + } else if (paddle->x + paddle->size < _width && check->gridPos.x() > paddle->x + paddle->size / 2) { + // Move right + right = true; + } + if (left) { + if (FIELD(paddle->x - 1, paddle->y)->isFree()) { + paddle->x--; + setField(paddle->x, paddle->y, paddle->cell); + if (FIELD(paddle->x + paddle->size, paddle->y) == paddle->cell) { + setField(paddle->x + paddle->size, paddle->y, &empty); + } + } + } else if (right) { + if (FIELD(paddle->x + paddle->size, paddle->y)->isFree()) { + setField(paddle->x + paddle->size, paddle->y, paddle->cell); + if (FIELD(paddle->x, paddle->y) == paddle->cell) { + setField(paddle->x, paddle->y, &empty); + } + paddle->x++; + } + } + } else { + // Paddle moves along the Y axis + bool top = false, bottom = false; + Ball *check; + // Paddle moves along the y ayis + if (paddle->x < 10) { + // Paddle is at top + check = bleft; + } else { + // Paddle at bottom + check = bright; + } + if (paddle->y > 0 && check->gridPos.y() < paddle->y + paddle->size / 2) { + // Move top + top = true; + } else if (paddle->y + paddle->size < _height && check->gridPos.y() > paddle->y + paddle->size / 2) { + // Move bottom + bottom = true; + } + if (top) { + if (FIELD(paddle->x, paddle->y - 1)->isFree()) { + paddle->y--; + setField(paddle->x, paddle->y, paddle->cell); + if (FIELD(paddle->x, paddle->y + paddle->size) == paddle->cell) { + setField(paddle->x, paddle->y + paddle->size, &empty); + } + } + } else if (bottom) { + if (FIELD(paddle->x, paddle->y + paddle->size)->isFree()) { + setField(paddle->x, paddle->y + paddle->size, paddle->cell); + if (FIELD(paddle->x, paddle->y) == paddle->cell) { + setField(paddle->x, paddle->y, &empty); + } + paddle->y++; + } + } + } // Done with movement logic + } // End loop over paddles } }); } -Snake::~Snake() +GameCore::~GameCore() { free(_field); } -void Snake::scanDir(RealSnake *snake, int dx, int dy, const Cell* &what, int &dist) +void GameCore::scanDir(Snake *snake, int dx, int dy, const Cell* &what, int &dist) { - int x = snake->_x; - int y = snake->_y; + int x = snake->x; + int y = snake->y; dist = 0; for (;;) { x += dx; @@ -184,26 +407,32 @@ void Snake::scanDir(RealSnake *snake, int dx, int dy, const Cell* &what, int &di what = &wall; return; } - if (!FIELD(x, y)->isFree()) { + if (FIELD(x, y)->willKill() || FIELD(x, y)->isFood()) { what = FIELD(x, y); return; } } } -void Snake::addSnake() +void GameCore::addSnake() { - for (int i = 0; i < 10; ++i) { + for (int i = 0; i < 100; ++i) { int x = qrand() % _width; int y = qrand() % _height; if (FIELD(x, y)->isFree()) { - _snakes.append(new RealSnake(x, y)); + if (qrand() % 2 == 0) { + qDebug() << "Adding Snake at" << x << y; + _snakes.append(new Snake(x, y)); + } else { + qDebug() << "Adding Ball at" << x << y; + _balls.append(new Ball(x * SCALING, y * SCALING)); + } break; } } } -void Snake::initField() +void GameCore::initField() { if (_field == nullptr) { _field = (const Cell**)calloc(_width * _height, sizeof(*_field)); @@ -224,20 +453,19 @@ void Snake::initField() _widget->update(); } -void Snake::addFood() +void GameCore::addFood() { for (int i = 0; i < 10; ++i) { int x = qrand() % _width; int y = qrand() % _height; - if (!FIELD(x, y)->isWall()) { - FIELD(x, y) = &food[qrand() % (sizeof(food) / sizeof(*food))]; - _widget->update(x * SCALING, y * SCALING, SCALING, SCALING); + if (FIELD(x, y)->canSpawnFood()) { + setField(x, y, &food[qrand() % (sizeof(food) / sizeof(*food))]); break; } } } -void Snake::paint(QPaintEvent *event) +void GameCore::paint(QPaintEvent *event) { QPainter p(_widget); const int width = qMin(_width, (event->rect().x() + event->rect().width() + SCALING - 1) / SCALING); diff --git a/src/snake.h b/src/snake.h index 9377575..dfa58cc 100644 --- a/src/snake.h +++ b/src/snake.h @@ -7,30 +7,39 @@ class QWidget; class QPaintEvent; -class RealSnake; +class Snake; struct Cell; +struct Ball; +struct Paddle; -class Snake +class GameCore { private: QWidget *_widget; - const Cell **_field; int _width, _height; - QList _snakes; + QList _snakes; + QList _balls; + QList _paddles; int _deaths; qint64 _lastMeal; + const Cell **_field; public: - Snake(QWidget *widget); + const Cell *field(int x, int y) const { + return _field[x + _width * y]; + } + void setField(int x, int y, const Cell *val); + + GameCore(QWidget *widget); - virtual ~Snake(); + virtual ~GameCore(); void paint(QPaintEvent *event); void addFood(); - void scanDir(RealSnake *snake, int x, int y, const Cell* &what, int &dist); + void scanDir(Snake *snake, int x, int y, const Cell* &what, int &dist); void addSnake(); -- cgit v1.2.3-55-g7522