summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Rettberg2023-06-09 17:03:44 +0200
committerSimon Rettberg2023-06-09 17:03:44 +0200
commit9c0a36f61cebd4b6587c155d9c46761c5c877da7 (patch)
tree5b65fd7274f65cd75d60997b365e1de014c9f09e
parentTry more random crap to fix layout with larger roomplans (diff)
downloadslxgreeter-9c0a36f61cebd4b6587c155d9c46761c5c877da7.tar.gz
slxgreeter-9c0a36f61cebd4b6587c155d9c46761c5c877da7.tar.xz
slxgreeter-9c0a36f61cebd4b6587c155d9c46761c5c877da7.zip
Improve login screen
-rw-r--r--src/mainwindow.cpp2
-rw-r--r--src/snake.cpp245
-rw-r--r--src/snake.h13
3 files changed, 203 insertions, 57 deletions
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 27d99d1..0ed85b8 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -213,6 +213,7 @@ void MainWindow::mouseDoubleClickEvent(QMouseEvent *)
if (m_Snake == nullptr) {
if (clicks++ > 0) {
m_Snake = new GameCore(this);
+ m_Clock->parentWidget()->hide();
}
} else {
m_Snake->addSnake();
@@ -224,6 +225,7 @@ void MainWindow::keyPressEvent(QKeyEvent *event)
switch (event->key()) {
case Qt::Key_Escape:
if (m_Snake != nullptr) {
+ m_Clock->parentWidget()->show();
delete m_Snake;
m_Snake = nullptr;
}
diff --git a/src/snake.cpp b/src/snake.cpp
index 2ce1a0d..e855250 100644
--- a/src/snake.cpp
+++ b/src/snake.cpp
@@ -1,4 +1,4 @@
-#include "snake.h"
+#include "snake.h"
#include <QWidget>
#include <QPaintEvent>
@@ -16,38 +16,57 @@
#define DIR_RIGHT 3
#define CELL_FREE 0
-#define CELL_WALL 1
+#define CELL_PADDLE_BACKING 1
#define CELL_SNAKE 2
#define CELL_FOOD 3
-#define CELL_BRICK 4
+#define CELL_BREAKOUT_BRICK 4
#define CELL_SNAKEBRICK 5
+#define CELL_PADDLE 6
#define AXIS_X 0
#define AXIS_Y 1
#define FIELD(x,y) _field[(x) + ((y) * _width)]
+struct Paddle;
+
struct Cell
{
int type;
QBrush color;
- Cell(int t, QColor c) : type(t), color(QBrush(c)) {}
+ Paddle *player;
+ Cell(int t, QColor c) : type(t), color(QBrush(c)), player(nullptr) {}
bool isFood() const { return type == CELL_FOOD; }
- bool willKill() const { return type == CELL_WALL || type == CELL_SNAKE || type == CELL_SNAKEBRICK; }
+ bool willKill() const { return type == CELL_PADDLE_BACKING | type == CELL_PADDLE || type == CELL_SNAKE || type == CELL_SNAKEBRICK; }
bool isFree() const { return type == CELL_FREE; }
- bool isBrick() const { return type == CELL_BRICK || type == CELL_SNAKEBRICK; }
- bool canSpawnFood() const { return type == CELL_SNAKE || type == CELL_FREE || type == CELL_BRICK; }
+ bool isPaddleFree() const { return type == CELL_FREE || type == CELL_SNAKEBRICK || type == CELL_BREAKOUT_BRICK || type == CELL_FOOD; }
+ bool isBrick() const { return type == CELL_BREAKOUT_BRICK || type == CELL_SNAKEBRICK; }
+ bool canSpawnFood() const { return type == CELL_SNAKE || type == CELL_FREE || type == CELL_BREAKOUT_BRICK; }
bool ballWillDestroy() const { return isFood() || isBrick(); }
};
+static const Cell empty(CELL_FREE, QColor());
+static const Cell snakebrick(CELL_SNAKEBRICK, QColor::fromRgb(200, 200, 200));
+static Cell breakoutCenterBrick(CELL_BREAKOUT_BRICK, QColor::fromRgb(255, 255, 255));
+static const Cell food[] = {
+ Cell(CELL_FOOD, QColor::fromRgb(0, 255, 0)),
+ Cell(CELL_FOOD, QColor::fromRgb(0, 200, 0)),
+ Cell(CELL_FOOD, QColor::fromRgb(0, 160, 0)),
+ Cell(CELL_FOOD, QColor::fromRgb(0, 120, 0)),
+};
+
+struct Paddle;
+
struct Ball
{
int x, y;
int dx, dy;
const Cell *cell;
QPoint gridPos;
+ Paddle *lastPlayer;
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))) {}
+ cell(new Cell(CELL_PADDLE_BACKING, QColor::fromHsv(qrand() % 360, 32 + qrand() % 64, 32 + qrand() % 64))),
+ lastPlayer(nullptr) {}
virtual ~Ball() { delete cell; }
};
@@ -56,9 +75,11 @@ struct Paddle
int x, y;
int axis;
int size;
- const Cell *cell;
+ Cell *cell;
+ Cell *dell;
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))) {
+ cell(new Cell(CELL_PADDLE, QColor::fromHsv(qrand() % 360, 192 + qrand() % 64, 192 + qrand() % 64))),
+ dell(nullptr) {
for (int i = 0; i < size; ++i) {
if (axis == AXIS_X) {
field->setField(x + i, y, cell);
@@ -67,17 +88,35 @@ struct Paddle
}
}
}
-};
-
-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)),
- Cell(CELL_FOOD, QColor::fromRgb(0, 160, 0)),
- Cell(CELL_FOOD, QColor::fromRgb(0, 120, 0)),
+ bool shrink(GameCore *field) {
+ if (size <= 0)
+ return false;
+ size--;
+ if (axis == AXIS_X) {
+ field->setField(x + size, y, &empty);
+ } else {
+ field->setField(x, y + size, &empty);
+ }
+ return true;
+ }
+ bool grow(GameCore *field) {
+ if (axis == AXIS_X) {
+ if (x < 0 || x + size >= field->width())
+ return false;
+ if (field->field(x + size, y)->isFree()) {
+ field->setField(x + size, y, cell);
+ }
+ } else {
+ if (y < 0 || y + size >= field->height())
+ return false;
+ if (field->field(x, y + size)->isFree()) {
+ field->setField(x, y + size, cell);
+ }
+ }
+ size++;
+ return true;
+ }
+ virtual ~Paddle() { delete cell; delete dell; }
};
class Snake
@@ -102,6 +141,7 @@ GameCore::GameCore(QWidget *widget)
: _widget(widget),
_deaths(0),
_lastMeal(QDateTime::currentMSecsSinceEpoch()),
+ _lastPaddle(QDateTime::currentMSecsSinceEpoch()),
_field(nullptr)
{
qsrand((uint)_lastMeal);
@@ -109,27 +149,31 @@ GameCore::GameCore(QWidget *widget)
_height = widget->height() / SCALING;
if (_width <= 0 || _height <= 0)
return;
- initField();
+ int cellCount = _width * _height;
+ _field = (const Cell**)calloc(cellCount, sizeof(*_field));
+ for (int i = 0; i < cellCount; ++i) {
+ _field[i] = &empty;
+ }
// 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;
- }
+ // Assign players to cells
+ for (int i = 0; i < _paddles.size(); ++i) {
+ _paddles[i]->dell = new Cell(CELL_PADDLE_BACKING, _paddles[i]->cell->color.color().darker(250));
+ _paddles[i]->cell->player = _paddles[i];
+ _paddles[i]->dell->player = _paddles[i];
}
+ drawPaddleBorders();
+ addBreakoutBlocks();
qDebug() << "Field:" << _width << _height;
addFood();
_t = new QTimer(widget);
_t->start(15);
// GAME
- QTimer::connect(_t, &QTimer::timeout, [this]() {
+ QTimer::connect(_t, &QTimer::timeout, [this, cellCount]() {
//
static int tick = 0;
++tick;
@@ -205,7 +249,16 @@ GameCore::GameCore(QWidget *widget)
setField(p.x(), p.y(), &snakebrick);
}
}
- addFood();
+ int cnt = 0;
+ for (int i = 0; i < cellCount; ++i) {
+ if (_field[i]->isFood()) {
+ if (++cnt > 5)
+ break;
+ }
+ }
+ if (cnt <= 5) {
+ addFood();
+ }
} else {
snake->len += 5;
}
@@ -219,11 +272,17 @@ GameCore::GameCore(QWidget *widget)
_lastMeal = QDateTime::currentMSecsSinceEpoch();
addFood();
}
+ // Spawn more balls?
+ if (_lastPaddle + 60000 < QDateTime::currentMSecsSinceEpoch()) {
+ qDebug() << "No ball action!";
+ _lastPaddle = QDateTime::currentMSecsSinceEpoch();
+ addBall();
+ }
}
//
// Balls
Ball *bbottom = nullptr, *btop = nullptr, *bleft = nullptr, *bright = nullptr;
- for ( Ball* ball : _balls) {
+ 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;
@@ -242,9 +301,11 @@ GameCore::GameCore(QWidget *widget)
ny = _height * SCALING - 1;
ball->dy = -qAbs(ball->dy);
}
- // Collision
+ // Collision check
const QPoint noo(nx / SCALING, ny / SCALING);
- if (old != noo && !FIELD(noo.x(), noo.y())->isFree()) {
+ const Cell *newCell = FIELD(noo.x(), noo.y());
+ if (old != noo && !newCell->isFree()) {
+ // Yes, new cell occupied, see what should happen
bool one = false;
if (FIELD(old.x(), noo.y()) == ball->cell || FIELD(old.x(), noo.y())->isFree()) {
one = true;
@@ -266,13 +327,27 @@ GameCore::GameCore(QWidget *widget)
ball->dx = -ball->dx;
ball->dy = -ball->dy;
}
+ auto *p = newCell->player;
+ if (p != nullptr) {
+ // Collision with player-cell: either paddle, or its backing wall
+ if (newCell->type == CELL_PADDLE_BACKING) {
+ p->shrink(this);
+ ball->lastPlayer = nullptr;
+ checkPongGameOver();
+ } else {
+ _lastPaddle = QDateTime::currentMSecsSinceEpoch();
+ ball->lastPlayer = p;
+ }
+ }
// 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
+ if (newCell->ballWillDestroy()) {
+ if (newCell->isFood()) {
+ if (ball->lastPlayer != nullptr) {
+ ball->lastPlayer->grow(this);
+ }
addFood();
}
- if (FIELD(noo.x(), noo.y())->isBrick()) {
+ if (newCell->isBrick()) {
for (int y = -1; y <= 1; ++y) {
for (int x = -1; x <= 1; ++x) {
if (FIELD(noo.x() + x, noo.y() + y)->isBrick()) {
@@ -285,7 +360,7 @@ GameCore::GameCore(QWidget *widget)
}
}
} else {
- // Free movevemnt
+ // No collision, free movement
ball->gridPos = noo;
ball->x = nx;
ball->y = ny;
@@ -312,6 +387,8 @@ GameCore::GameCore(QWidget *widget)
// Paddles
if (bbottom != nullptr) {
for (Paddle *paddle : _paddles) {
+ if (paddle->size <= 0)
+ continue;
if (paddle->axis == AXIS_X) {
bool left = false, right = false;
Ball *check;
@@ -331,7 +408,7 @@ GameCore::GameCore(QWidget *widget)
right = true;
}
if (left) {
- if (FIELD(paddle->x - 1, paddle->y)->isFree()) {
+ if (FIELD(paddle->x - 1, paddle->y)->isPaddleFree()) {
paddle->x--;
setField(paddle->x, paddle->y, paddle->cell);
if (FIELD(paddle->x + paddle->size, paddle->y) == paddle->cell) {
@@ -339,7 +416,7 @@ GameCore::GameCore(QWidget *widget)
}
}
} else if (right) {
- if (FIELD(paddle->x + paddle->size, paddle->y)->isFree()) {
+ if (FIELD(paddle->x + paddle->size, paddle->y)->isPaddleFree()) {
setField(paddle->x + paddle->size, paddle->y, paddle->cell);
if (FIELD(paddle->x, paddle->y) == paddle->cell) {
setField(paddle->x, paddle->y, &empty);
@@ -367,7 +444,7 @@ GameCore::GameCore(QWidget *widget)
bottom = true;
}
if (top) {
- if (FIELD(paddle->x, paddle->y - 1)->isFree()) {
+ if (FIELD(paddle->x, paddle->y - 1)->isPaddleFree()) {
paddle->y--;
setField(paddle->x, paddle->y, paddle->cell);
if (FIELD(paddle->x, paddle->y + paddle->size) == paddle->cell) {
@@ -375,7 +452,7 @@ GameCore::GameCore(QWidget *widget)
}
}
} else if (bottom) {
- if (FIELD(paddle->x, paddle->y + paddle->size)->isFree()) {
+ if (FIELD(paddle->x, paddle->y + paddle->size)->isPaddleFree()) {
setField(paddle->x, paddle->y + paddle->size, paddle->cell);
if (FIELD(paddle->x, paddle->y) == paddle->cell) {
setField(paddle->x, paddle->y, &empty);
@@ -391,6 +468,9 @@ GameCore::GameCore(QWidget *widget)
GameCore::~GameCore()
{
+ for (Paddle *p: _paddles) {
+ delete p;
+ }
free(_field);
if(_t->isActive()) {
_t->stop();
@@ -408,7 +488,7 @@ void GameCore::scanDir(Snake *snake, int dx, int dy, const Cell* &what, int &dis
y += dy;
dist++;
if (x < 0 || x >= _width || y < 0 || y >= _height) {
- what = &wall;
+ what = &snakebrick;
return;
}
if (FIELD(x, y)->willKill() || FIELD(x, y)->isFood()) {
@@ -436,27 +516,80 @@ void GameCore::addSnake()
}
}
-void GameCore::initField()
+void GameCore::addBall()
{
- if (_field == nullptr) {
- _field = (const Cell**)calloc(_width * _height, sizeof(*_field));
+ for (int i = 0; i < 100; ++i) {
+ int x = qrand() % _width;
+ int y = qrand() % _height;
+ if (FIELD(x, y)->isFree()) {
+ qDebug() << "Adding Ball at" << x << y;
+ Ball *b = new Ball(x * SCALING, y * SCALING);
+ if (b == nullptr) {
+ qDebug() << "NULLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL";
+ }
+ _balls.append(b);
+ break;
+ }
}
- for (int i = 0; i < _width; ++i) {
- FIELD(i, 0) = &wall;
- FIELD(i, _height - 1) = &wall;
+}
+
+void GameCore::drawPaddleBorders()
+{
+ // 0.. = bottom, top, right, left
+ for (int i = 1; i < _width - 1; ++i) {
+ FIELD(i, 0) = _paddles[1]->dell;
+ FIELD(i, _height - 1) = _paddles[0]->dell;
}
- for (int i = 0; i < _height; ++i) {
- FIELD(0, i) = &wall;
- FIELD(_width - 1, i) = &wall;
+ for (int i = 1; i < _height - 1; ++i) {
+ FIELD(0, i) = _paddles[3]->dell;
+ FIELD(_width - 1, i) = _paddles[2]->dell;
}
- for (int y = 1; y < _height - 1; ++y) {
- for (int x = 1; x < _width - 1; ++x) {
- FIELD(x, y) = &empty;
+ _widget->update();
+}
+
+void GameCore::addBreakoutBlocks()
+{
+ for (int y = 15; y < _height - 16; y += 3) {
+ for (int x = 15; x < _width - 16; x += 3) {
+ if (FIELD(x, y)->isPaddleFree()) {
+ FIELD(x, y) = &breakoutCenterBrick;
+ }
+ if (FIELD(x + 1, y)->isPaddleFree()) {
+ FIELD(x + 1, y) = &breakoutCenterBrick;
+ }
+ if (FIELD(x, y + 1)->isPaddleFree()) {
+ FIELD(x, y + 1) = &breakoutCenterBrick;
+ }
+ if (FIELD(x + 1, y + 1)->isPaddleFree()) {
+ FIELD(x + 1, y + 1) = &breakoutCenterBrick;
+ }
}
}
_widget->update();
}
+void GameCore::checkPongGameOver()
+{
+ int cnt = 0;
+ Paddle *last = nullptr;
+ for (Paddle *p : _paddles) {
+ if (p->size > 0) {
+ cnt++;
+ last = p;
+ }
+ }
+ if (cnt == 1) {
+ // Winrar
+ breakoutCenterBrick.color = QBrush(last->cell->color.color().lighter(250));
+ for (Paddle *p : _paddles) {
+ while (p->size < 5 && p->grow(this)) {
+ // Nothing
+ }
+ }
+ addBreakoutBlocks();
+ }
+}
+
void GameCore::pauseAndResume()
{
if(_t->isActive()) {
diff --git a/src/snake.h b/src/snake.h
index 3adc301..538a944 100644
--- a/src/snake.h
+++ b/src/snake.h
@@ -25,6 +25,7 @@ private:
QList<Paddle*> _paddles;
int _deaths;
qint64 _lastMeal;
+ qint64 _lastPaddle;
const Cell **_field;
public:
@@ -33,6 +34,10 @@ public:
}
void setField(int x, int y, const Cell *val);
+ int width() const { return _width; }
+
+ int height() const { return _height; }
+
GameCore(QWidget *widget);
virtual ~GameCore();
@@ -45,7 +50,13 @@ public:
void addSnake();
- void initField();
+ void addBall();
+
+ void drawPaddleBorders();
+
+ void addBreakoutBlocks();
+
+ void checkPongGameOver();
void pauseAndResume();
};