summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Rettberg2019-05-25 17:48:41 +0200
committerSimon Rettberg2019-05-25 17:48:41 +0200
commit5c92e0612ec7ae4ea329fa18792b94fcb5908cfd (patch)
tree5998ee5decde2afc0c20adefb011bc07c3bcee81
parentImprove rendering even more (diff)
downloadslxgreeter-5c92e0612ec7ae4ea329fa18792b94fcb5908cfd.tar.gz
slxgreeter-5c92e0612ec7ae4ea329fa18792b94fcb5908cfd.tar.xz
slxgreeter-5c92e0612ec7ae4ea329fa18792b94fcb5908cfd.zip
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.
-rw-r--r--src/mainwindow.cpp50
-rw-r--r--src/mainwindow.h8
-rw-r--r--src/settings.h1
-rw-r--r--src/snake.cpp442
-rw-r--r--src/snake.h23
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<QPoint> _snake;
+ int x, y;
+ int direction;
+ int len;
+ QList<QPoint> 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()) = &empty;
- _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<RealSnake*> _snakes;
+ QList<Snake*> _snakes;
+ QList<Ball*> _balls;
+ QList<Paddle*> _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();