Improvements and updates
Updates related to the QGraphicsView usage. Implemented game logic. Code improvements.
This commit is contained in:
parent
90880143bd
commit
35d1b8f382
|
@ -2,13 +2,27 @@
|
|||
#include "snake.h"
|
||||
#include "ui_snake.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QGraphicsView>
|
||||
#include <QGraphicsScene>
|
||||
|
||||
Snake:: Snake(const QPalette& style, QWidget* parent ) :
|
||||
|
||||
Snake:: Snake(const QPalette& style, const QFont& term_font, QWidget* parent ) :
|
||||
QWidget(parent),
|
||||
ui(new Ui::Snake)
|
||||
{
|
||||
this->ui->setupUi(this);
|
||||
|
||||
this->setPalette( style );
|
||||
QFont font = QFont( term_font );
|
||||
font.setPointSize( 64 );
|
||||
this->ui->button_Play->setFont( font );
|
||||
|
||||
this->field_scene = new QGraphicsScene( this );
|
||||
this->field_scene->setSceneRect( 0,0, 512, 512 );
|
||||
this->field_scene->setBackgroundBrush( Qt::black );
|
||||
// add the scene to the view
|
||||
this->ui->view_Field->setScene( this->field_scene );
|
||||
|
||||
// initialize an empty field
|
||||
for (int x=0; x<16; x++) {
|
||||
|
@ -20,28 +34,26 @@ Snake:: Snake(const QPalette& style, QWidget* parent ) :
|
|||
// snake initial position
|
||||
const unsigned int head_x = (rand()%4)+6;
|
||||
const unsigned int head_y = (rand()%4)+6;
|
||||
if ( (head_x < 0 || head_x > 15)
|
||||
|| (head_y < 0 || head_y > 15) ) {
|
||||
if ( head_x > 15 || head_y > 15 ) {
|
||||
// should be unreachable
|
||||
throw("Unexpected initial position: ("+std::to_string(head_x)+","+std::to_string(head_y)+")");
|
||||
}
|
||||
this->field[ head_x ][ head_y ] = Tile::SNAKE;
|
||||
|
||||
// snake initial direction
|
||||
Direction head_d;
|
||||
const int rand_d = rand()%4;
|
||||
switch ( rand_d ) {
|
||||
case 0:
|
||||
head_d = Direction::UP;
|
||||
this->head_direction = Direction::UP;
|
||||
break;
|
||||
case 1:
|
||||
head_d = Direction::DOWN;
|
||||
this->head_direction = Direction::DOWN;
|
||||
break;
|
||||
case 2:
|
||||
head_d = Direction::LEFT;
|
||||
this->head_direction = Direction::LEFT;
|
||||
break;
|
||||
case 3:
|
||||
head_d = Direction::RIGHT;
|
||||
this->head_direction = Direction::RIGHT;
|
||||
break;
|
||||
default:
|
||||
// should be unreachable
|
||||
|
@ -49,51 +61,489 @@ Snake:: Snake(const QPalette& style, QWidget* parent ) :
|
|||
}
|
||||
|
||||
// build the body with a head
|
||||
this->snake_body.push_back(
|
||||
{ head_x, head_y, head_d, head_d, true }
|
||||
this->snake.push_back(
|
||||
{ head_x, head_y,
|
||||
this->head_direction, this->head_direction,
|
||||
new QGraphicsPixmapItem( this->img_snakeHead ),
|
||||
true }
|
||||
);
|
||||
this->field_scene->addItem( this->snake.front().image );
|
||||
this->snake.front().update( head_x, head_y, this->head_direction );
|
||||
// a body part
|
||||
this->increaseSnakeBody();
|
||||
// and a tail
|
||||
this->increaseSnakeBody();
|
||||
// a snake is born
|
||||
// et voila! a snake is born
|
||||
|
||||
// now put some food on the field for it to eat
|
||||
this->food = Food{ 0, 0, new QGraphicsPixmapItem( this->img_food ) };
|
||||
this->field_scene->addItem( this->food.image );
|
||||
this->spawnFood();
|
||||
}
|
||||
|
||||
Snake::~Snake()
|
||||
{
|
||||
delete ui;
|
||||
delete this->ui;
|
||||
delete this->field_scene;
|
||||
delete this->game_loop;
|
||||
}
|
||||
|
||||
|
||||
void Snake::keyPressEvent( QKeyEvent* event )
|
||||
{
|
||||
// move only if not moved already
|
||||
if ( ! this->lock_movements ) {
|
||||
// get the key pressed
|
||||
const int& key = event->key();
|
||||
// update direction if needed
|
||||
switch (key) {
|
||||
case Qt::Key_Up:
|
||||
case Qt::Key_W:
|
||||
if ( this->head_direction != Direction::DOWN ) {
|
||||
this->head_direction = Direction::UP;
|
||||
this->lock_movements = true;
|
||||
}
|
||||
break;
|
||||
case Qt::Key_Down:
|
||||
case Qt::Key_S:
|
||||
if ( this->head_direction != Direction::UP ) {
|
||||
this->head_direction = Direction::DOWN;
|
||||
this->lock_movements = true;
|
||||
}
|
||||
break;
|
||||
case Qt::Key_Left:
|
||||
case Qt::Key_A:
|
||||
if ( this->head_direction != Direction::RIGHT ) {
|
||||
this->head_direction = Direction::LEFT;
|
||||
this->lock_movements = true;
|
||||
}
|
||||
break;
|
||||
case Qt::Key_Right:
|
||||
case Qt::Key_D:
|
||||
if ( this->head_direction != Direction::LEFT ) {
|
||||
this->head_direction = Direction::RIGHT;
|
||||
this->lock_movements = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////
|
||||
//// MENU ////
|
||||
void Snake::on_button_Play_clicked()
|
||||
{
|
||||
// switch to game board
|
||||
this->ui->stackedWidget_GameDisplay->setCurrentIndex( 1 );
|
||||
// start playing
|
||||
this->game_loop = new QTimer(this);
|
||||
connect(this->game_loop, SIGNAL(timeout()), this, SLOT(processGameLogic()));
|
||||
this->game_loop->start(200);
|
||||
this->lock_movements = false;
|
||||
this->playing = true;
|
||||
}
|
||||
|
||||
|
||||
//////////////
|
||||
//// GAME ////
|
||||
void Snake::processGameLogic()
|
||||
{
|
||||
this->updateSnakePosition();
|
||||
if ( game_over ) {
|
||||
this->lock_movements = true;
|
||||
this->game_loop->stop();
|
||||
this->playing = false;
|
||||
QMessageBox::about(
|
||||
this,
|
||||
Snake::tr("Game Over"),
|
||||
this->game_over_msg );
|
||||
}/* else {
|
||||
//this->update();
|
||||
//this->repaint();
|
||||
}*/
|
||||
this->lock_movements = false;
|
||||
}
|
||||
|
||||
|
||||
void Snake::increaseGameScore()
|
||||
{
|
||||
this->game_score ++;
|
||||
this->ui->lcd_Score->setDigitCount( std::to_string(this->game_score).size() );
|
||||
this->ui->lcd_Score->display( this->game_score );
|
||||
}
|
||||
|
||||
|
||||
void Snake::spawnFood()
|
||||
{
|
||||
// pick a new random position
|
||||
unsigned int x, y;
|
||||
while (true) {
|
||||
x = rand() % 16;
|
||||
y = rand() % 16;
|
||||
// check it's actually inside the field
|
||||
if ( x < 16 && y < 16 ) {
|
||||
// check the tile is empty
|
||||
if ( this->field[x][y] == Tile::EMPTY ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove the old food from the field
|
||||
this->field[this->food.x][this->food.y] = Tile::EMPTY;
|
||||
// add the new food to the field and update the position
|
||||
this->field[x][y] = Tile::FOOD;
|
||||
this->food.update( x, y );
|
||||
|
||||
// randomly rotate the image
|
||||
int rand_ = rand()%4;
|
||||
switch (rand_) {
|
||||
case 1:
|
||||
this->food.image->setPixmap(
|
||||
this->food.image->pixmap().transformed(
|
||||
QTransform().rotate( 90.0 ) ) );
|
||||
break;
|
||||
case 2:
|
||||
this->food.image->setPixmap(
|
||||
this->food.image->pixmap().transformed(
|
||||
QTransform().rotate( 180.0 ) ) );
|
||||
break;
|
||||
case 3:
|
||||
this->food.image->setPixmap(
|
||||
this->food.image->pixmap().transformed(
|
||||
QTransform().rotate( -90.0 ) ) );
|
||||
break;
|
||||
default:
|
||||
// do not rotate
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Snake::updateSnakePosition( const bool& dry )
|
||||
{
|
||||
size_t i = 0,
|
||||
max_i = this->snake.size()-1;
|
||||
unsigned int new_x, prev_x, new_y, prev_y;
|
||||
Direction new_direction, prev_direction, prev_body_d;
|
||||
for ( BodyPart& bp : this->snake ) {
|
||||
if ( ! dry ) {
|
||||
// future position
|
||||
if ( bp.head ) {
|
||||
// head doesn't follow any other part of the body
|
||||
switch ( this->head_direction ) {
|
||||
case Direction::UP:
|
||||
new_y = bp.y - 1;
|
||||
new_x = bp.x;
|
||||
break;
|
||||
case Direction::DOWN:
|
||||
new_y = bp.y + 1;
|
||||
new_x = bp.x;
|
||||
break;
|
||||
case Direction::LEFT:
|
||||
new_x = bp.x - 1;
|
||||
new_y = bp.y;
|
||||
break;
|
||||
case Direction::RIGHT:
|
||||
new_x = bp.x + 1;
|
||||
new_y = bp.y;
|
||||
break;
|
||||
default:
|
||||
// should be unreachable
|
||||
throw("Unexpected direction: "+std::to_string(bp.direction));
|
||||
}
|
||||
new_direction = this->head_direction;
|
||||
} else {
|
||||
// follow the previous part of the body
|
||||
new_x = prev_x;
|
||||
new_y = prev_y;
|
||||
new_direction = prev_direction;
|
||||
}
|
||||
// update for the next part
|
||||
prev_x = bp.x;
|
||||
prev_y = bp.y;
|
||||
prev_direction = bp.direction;
|
||||
|
||||
// if this is the head, check for a possible collision
|
||||
if ( bp.head ) {
|
||||
this->checkCollision( new_x, new_y );
|
||||
}
|
||||
|
||||
// update the body-part position
|
||||
bp.update( new_x, new_y, new_direction );
|
||||
// and the field
|
||||
if ( i == 0 ) {
|
||||
// head
|
||||
this->field[ new_x ][ new_y ] = Tile::SNAKE;
|
||||
} else if ( i == max_i ) {
|
||||
// tail
|
||||
this->field[ prev_x ][ prev_y ] = Tile::EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
// finally set the image to be shown
|
||||
switch ( bp.direction ) {
|
||||
|
||||
case Direction::UP:
|
||||
if ( i == 0 ) {
|
||||
bp.image->setPixmap(
|
||||
this->img_snakeHead );
|
||||
} else if ( i == max_i ) {
|
||||
switch ( prev_body_d ) {
|
||||
case Direction::UP:
|
||||
bp.image->setPixmap(
|
||||
this->img_snakeTail );
|
||||
break;
|
||||
case Direction::LEFT:
|
||||
bp.image->setPixmap(
|
||||
this->img_snakeTail.transformed(
|
||||
QTransform().rotate( -90.0 ) ) );
|
||||
break;
|
||||
case Direction::RIGHT:
|
||||
bp.image->setPixmap(
|
||||
this->img_snakeTail.transformed(
|
||||
QTransform().rotate( 90.0 ) ) );
|
||||
break;
|
||||
default:
|
||||
// should be unreachable
|
||||
throw("Unexpected direction: "+std::to_string(prev_body_d));
|
||||
}
|
||||
} else {
|
||||
switch ( prev_body_d ) {
|
||||
case Direction::UP:
|
||||
bp.image->setPixmap(
|
||||
this->img_snakeBody );
|
||||
break;
|
||||
case Direction::LEFT:
|
||||
bp.image->setPixmap(
|
||||
this->img_snakeCurve.transformed(
|
||||
QTransform().rotate( 90.0 ) ) );
|
||||
break;
|
||||
case Direction::RIGHT:
|
||||
bp.image->setPixmap(
|
||||
this->img_snakeCurve );
|
||||
break;
|
||||
default:
|
||||
// should be unreachable
|
||||
throw("Unexpected direction: "+std::to_string(prev_body_d));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Direction::DOWN:
|
||||
if ( i == 0 ) {
|
||||
bp.image->setPixmap(
|
||||
this->img_snakeHead.transformed(
|
||||
QTransform().rotate( 180.0 ) ) );
|
||||
} else if ( i == max_i ) {
|
||||
switch ( prev_body_d ) {
|
||||
case Direction::DOWN:
|
||||
bp.image->setPixmap(
|
||||
this->img_snakeTail.transformed(
|
||||
QTransform().rotate( 180.0 ) ) );
|
||||
break;
|
||||
case Direction::LEFT:
|
||||
bp.image->setPixmap(
|
||||
this->img_snakeTail.transformed(
|
||||
QTransform().rotate( -90.0 ) ) );
|
||||
break;
|
||||
case Direction::RIGHT:
|
||||
bp.image->setPixmap(
|
||||
this->img_snakeTail.transformed(
|
||||
QTransform().rotate( 90.0 ) ) );
|
||||
break;
|
||||
default:
|
||||
// should be unreachable
|
||||
throw("Unexpected direction: "+std::to_string(prev_body_d));
|
||||
}
|
||||
} else {
|
||||
switch ( prev_body_d ) {
|
||||
case Direction::DOWN:
|
||||
bp.image->setPixmap(
|
||||
this->img_snakeBody );
|
||||
break;
|
||||
case Direction::LEFT:
|
||||
bp.image->setPixmap(
|
||||
this->img_snakeCurve.transformed(
|
||||
QTransform().rotate( 180.0 ) ) );
|
||||
break;
|
||||
case Direction::RIGHT:
|
||||
bp.image->setPixmap(
|
||||
this->img_snakeCurve.transformed(
|
||||
QTransform().rotate( -90.0 ) ) );
|
||||
break;
|
||||
default:
|
||||
// should be unreachable
|
||||
throw("Unexpected direction: "+std::to_string(prev_body_d));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Direction::LEFT:
|
||||
if ( i == 0 ) {
|
||||
bp.image->setPixmap(
|
||||
this->img_snakeHead.transformed(
|
||||
QTransform().rotate( -90.0 ) ) );
|
||||
} else if ( i == max_i ) {
|
||||
switch ( prev_body_d ) {
|
||||
case Direction::LEFT:
|
||||
bp.image->setPixmap(
|
||||
this->img_snakeTail.transformed(
|
||||
QTransform().rotate( -90.0 ) ) );
|
||||
break;
|
||||
case Direction::UP:
|
||||
bp.image->setPixmap(
|
||||
this->img_snakeTail );
|
||||
break;
|
||||
case Direction::DOWN:
|
||||
bp.image->setPixmap(
|
||||
this->img_snakeTail.transformed(
|
||||
QTransform().rotate( 180.0 ) ) );
|
||||
break;
|
||||
default:
|
||||
// should be unreachable
|
||||
throw("Unexpected direction: "+std::to_string(prev_body_d));
|
||||
}
|
||||
} else {
|
||||
switch ( prev_body_d ) {
|
||||
case Direction::LEFT:
|
||||
bp.image->setPixmap(
|
||||
this->img_snakeBody.transformed(
|
||||
QTransform().rotate( -90.0 ) ) );
|
||||
break;
|
||||
case Direction::UP:
|
||||
bp.image->setPixmap(
|
||||
this->img_snakeCurve.transformed(
|
||||
QTransform().rotate( -90.0 ) ) );
|
||||
break;
|
||||
case Direction::DOWN:
|
||||
bp.image->setPixmap(
|
||||
this->img_snakeCurve );
|
||||
break;
|
||||
default:
|
||||
// should be unreachable
|
||||
throw("Unexpected direction: "+std::to_string(prev_body_d));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Direction::RIGHT:
|
||||
if ( i == 0 ) {
|
||||
bp.image->setPixmap(
|
||||
this->img_snakeHead.transformed(
|
||||
QTransform().rotate( 90.0 ) ) );
|
||||
} else if ( i == max_i ) {
|
||||
switch ( prev_body_d ) {
|
||||
case Direction::RIGHT:
|
||||
bp.image->setPixmap(
|
||||
this->img_snakeTail.transformed(
|
||||
QTransform().rotate( 90.0 ) ) );
|
||||
break;
|
||||
case Direction::UP:
|
||||
bp.image->setPixmap(
|
||||
this->img_snakeTail );
|
||||
break;
|
||||
case Direction::DOWN:
|
||||
bp.image->setPixmap(
|
||||
this->img_snakeTail.transformed(
|
||||
QTransform().rotate( 180.0 ) ) );
|
||||
break;
|
||||
default:
|
||||
// should be unreachable
|
||||
throw("Unexpected direction: "+std::to_string(prev_body_d));
|
||||
}
|
||||
} else {
|
||||
switch ( prev_body_d ) {
|
||||
case Direction::RIGHT:
|
||||
bp.image->setPixmap(
|
||||
this->img_snakeBody.transformed(
|
||||
QTransform().rotate( 90.0 ) ) );
|
||||
break;
|
||||
case Direction::UP:
|
||||
bp.image->setPixmap(
|
||||
this->img_snakeCurve.transformed(
|
||||
QTransform().rotate( 180.0 ) ) );
|
||||
break;
|
||||
case Direction::DOWN:
|
||||
bp.image->setPixmap(
|
||||
this->img_snakeCurve.transformed(
|
||||
QTransform().rotate( 90.0 ) ) );
|
||||
break;
|
||||
default:
|
||||
// should be unreachable
|
||||
throw("Unexpected direction: "+std::to_string(prev_body_d));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// should be unreachable
|
||||
throw("Unexpected direction: "+std::to_string(bp.direction));
|
||||
}
|
||||
prev_body_d = bp.direction;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Snake::checkCollision( const unsigned int& x, const unsigned int& y )
|
||||
{
|
||||
// check the upcoming movement
|
||||
if ( x > 15 || y > 15 ) {
|
||||
// collision with the field limits
|
||||
this->game_over = true;
|
||||
this->game_over_msg = Snake::tr("You fell in the water!");
|
||||
|
||||
} else if ( this->field[x][y] == Tile::SNAKE ) {
|
||||
// collision with another part of the snake
|
||||
this->game_over = true;
|
||||
this->game_over_msg = Snake::tr("You ate yourself!");
|
||||
|
||||
} else if ( this->field[x][y] == Tile::FOOD ) {
|
||||
// will eat
|
||||
if ( this->snake.size() < this->MAX_SNAKE_LENGTH ) {
|
||||
// below max size, increase the size
|
||||
this->increaseSnakeBody();
|
||||
}
|
||||
// increase the score
|
||||
this->increaseGameScore();
|
||||
// spawn food in a new position
|
||||
this->spawnFood();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Snake::increaseSnakeBody()
|
||||
{
|
||||
// build from the tail
|
||||
const BodyPart& tail = this->snake_body.back();
|
||||
BodyPart& tail = this->snake.back();
|
||||
unsigned int x = tail.x;
|
||||
unsigned int y = tail.y;
|
||||
Direction d = tail.direction;
|
||||
Direction d = tail.prev_direction;
|
||||
Direction ld = tail.prev_direction;
|
||||
// set the new body-part position
|
||||
bool done = false;
|
||||
while (done) {
|
||||
while (!done) {
|
||||
switch ( d ) {
|
||||
case Direction::UP:
|
||||
y ++;
|
||||
if ( y >= 16 ) { y--; d=ld; } // out of field limit
|
||||
if ( y > 15 ) { y--; d=ld; } // out of field limit
|
||||
else { done=true; }
|
||||
break;
|
||||
case Direction::DOWN:
|
||||
y --;
|
||||
if ( y < 0 ) { y++; d=ld; }
|
||||
if ( y > 15 ) { y++; d=ld; }
|
||||
else { done=true; }
|
||||
break;
|
||||
case Direction::LEFT:
|
||||
x --;
|
||||
if ( x < 0 ) { x++; d=ld; }
|
||||
x ++;
|
||||
if ( x > 15 ) { x--; d=ld; }
|
||||
else { done=true; }
|
||||
break;
|
||||
case Direction::RIGHT:
|
||||
x ++;
|
||||
if ( x >= 16 ) { x--; d=ld; }
|
||||
x --;
|
||||
if ( x > 15 ) { x++; d=ld; }
|
||||
else { done=true; }
|
||||
break;
|
||||
default:
|
||||
|
@ -111,16 +561,24 @@ void Snake::increaseSnakeBody()
|
|||
Direction directions[3];
|
||||
switch ( d ) {
|
||||
case Direction::UP:
|
||||
directions[0]=Direction::DOWN;directions[1]=Direction::LEFT;directions[2]=Direction::RIGHT;
|
||||
directions[0]=Direction::DOWN;
|
||||
directions[1]=Direction::LEFT;
|
||||
directions[2]=Direction::RIGHT;
|
||||
break;
|
||||
case Direction::DOWN:
|
||||
directions[0]=Direction::UP;directions[1]=Direction::RIGHT;directions[2]=Direction::LEFT;
|
||||
directions[0]=Direction::UP;
|
||||
directions[1]=Direction::RIGHT;
|
||||
directions[2]=Direction::LEFT;
|
||||
break;
|
||||
case Direction::LEFT:
|
||||
directions[0]=Direction::RIGHT;directions[1]=Direction::DOWN;directions[2]=Direction::UP;
|
||||
directions[0]=Direction::RIGHT;
|
||||
directions[1]=Direction::DOWN;
|
||||
directions[2]=Direction::UP;
|
||||
break;
|
||||
case Direction::RIGHT:
|
||||
directions[0]=Direction::LEFT;directions[1]=Direction::UP;directions[2]=Direction::DOWN;
|
||||
directions[0]=Direction::LEFT;
|
||||
directions[1]=Direction::UP;
|
||||
directions[2]=Direction::DOWN;
|
||||
break;
|
||||
default:
|
||||
// should be unreachable
|
||||
|
@ -130,27 +588,27 @@ void Snake::increaseSnakeBody()
|
|||
for ( const auto& dir : directions ) {
|
||||
switch ( dir ) {
|
||||
case Direction::UP:
|
||||
y ++;
|
||||
if ( y >= 16 || this->field[x][y] != EMPTY )
|
||||
y ++; // inverse
|
||||
if ( y > 15 || this->field[x][y] != EMPTY )
|
||||
{ y--; d=ld=dir; }
|
||||
else { done=true; }
|
||||
break;
|
||||
case Direction::DOWN:
|
||||
y --;
|
||||
if ( y < 0 || this->field[x][y] != EMPTY )
|
||||
if ( y > 15 || this->field[x][y] != EMPTY )
|
||||
{ y++; d=ld=dir; }
|
||||
else { done=true; }
|
||||
break;
|
||||
case Direction::LEFT:
|
||||
x --;
|
||||
if ( x < 0 || this->field[x][y] != EMPTY )
|
||||
{ x++; d=ld=dir; }
|
||||
x ++;
|
||||
if ( x > 15 || this->field[x][y] != EMPTY )
|
||||
{ x--; d=ld=dir; }
|
||||
else { done=true; }
|
||||
break;
|
||||
case Direction::RIGHT:
|
||||
x ++;
|
||||
if ( x >= 16 || this->field[x][y] != EMPTY )
|
||||
{ x--; d=ld=dir; }
|
||||
x --;
|
||||
if ( x > 15 || this->field[x][y] != EMPTY )
|
||||
{ x++; d=ld=dir; }
|
||||
else { done=true; }
|
||||
break;
|
||||
default:
|
||||
|
@ -161,22 +619,17 @@ void Snake::increaseSnakeBody()
|
|||
}
|
||||
if ( done ) {
|
||||
// a valid position has been found, append a new body-part
|
||||
this->snake_body.push_back(
|
||||
{ x, y, d, ld }
|
||||
this->snake.push_back(
|
||||
{ x, y,
|
||||
d, ld,
|
||||
new QGraphicsPixmapItem( this->img_snakeTail ) }
|
||||
);
|
||||
this->snake.back().update( x, y, d );
|
||||
this->field_scene->addItem( this->snake.back().image );
|
||||
this->updateSnakePosition( true );
|
||||
}/* else {
|
||||
// no suitable position found, can't grow
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
void Snake::increaseScore()
|
||||
{
|
||||
this->game_score ++;
|
||||
this->ui->lcd_Score->setDigitCount( std::to_string(this->game_score).size() );
|
||||
this->ui->lcd_Score->display( this->game_score );
|
||||
// snake grows
|
||||
if ( this->snake_body.size() < this->MAX_SNAKE_LENGTH ) {
|
||||
this->increaseSnakeBody();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
#ifndef SNAKE_H
|
||||
#define SNAKE_H
|
||||
|
||||
#include <QTimer>
|
||||
#include <QWidget>
|
||||
#include <QKeyEvent>
|
||||
|
||||
#include <QGraphicsScene>
|
||||
#include <QGraphicsPixmapItem>
|
||||
|
||||
|
||||
namespace Ui {
|
||||
class Snake;
|
||||
|
@ -12,12 +18,37 @@ class Snake : public QWidget
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Snake( const QPalette& style, QWidget* parent=nullptr );
|
||||
explicit Snake( const QPalette& style, const QFont& term_font, QWidget* parent=nullptr );
|
||||
~Snake();
|
||||
|
||||
private slots:
|
||||
|
||||
void on_button_Play_clicked();
|
||||
|
||||
void processGameLogic();
|
||||
|
||||
private:
|
||||
Ui::Snake *ui;
|
||||
|
||||
void keyPressEvent( QKeyEvent* event ) override;
|
||||
bool lock_movements = true;
|
||||
|
||||
bool playing = false;
|
||||
QTimer* game_loop = new QTimer();
|
||||
bool game_over = false;
|
||||
QString game_over_msg;
|
||||
|
||||
// graphics
|
||||
QGraphicsScene* field_scene;
|
||||
|
||||
QPixmap img_food = QPixmap(":/games/games/food.png");
|
||||
|
||||
QPixmap img_snakeHead = QPixmap(":/games/games/head.png");
|
||||
QPixmap img_snakeTail = QPixmap(":/games/games/tail.png");
|
||||
QPixmap img_snakeBody = QPixmap(":/games/games/body_s.png");
|
||||
QPixmap img_snakeCurve = QPixmap(":/games/games/body_c.png");
|
||||
|
||||
|
||||
// snake
|
||||
const unsigned int MAX_SNAKE_LENGTH = 64;
|
||||
|
||||
|
@ -28,27 +59,54 @@ private:
|
|||
RIGHT
|
||||
};
|
||||
|
||||
Direction head_direction;
|
||||
|
||||
struct BodyPart {
|
||||
unsigned int x;
|
||||
unsigned int y;
|
||||
Direction direction;
|
||||
Direction prev_direction;
|
||||
QGraphicsPixmapItem* image;
|
||||
const bool head=false;
|
||||
const bool& isHead() {
|
||||
return this->head;
|
||||
}
|
||||
void updatePosition( unsigned int& new_x, unsigned int& new_y, Direction& new_direction ) {
|
||||
/*bool tail=true;
|
||||
void tail2body () {
|
||||
this->tail = false;
|
||||
}*/
|
||||
void update( const unsigned int& new_x, const unsigned int& new_y, const Direction& new_direction ) {
|
||||
this->x = new_x;
|
||||
this->y = new_y;
|
||||
this->image->setOffset( new_x*32, new_y*32 );
|
||||
this->prev_direction = this->direction;
|
||||
this->direction = new_direction;
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<BodyPart> snake_body;
|
||||
std::vector<BodyPart> snake;
|
||||
|
||||
void increaseSnakeBody();
|
||||
|
||||
void updateSnakePosition( const bool& dry=false );
|
||||
|
||||
void checkCollision( const unsigned int& x, const unsigned int& y );
|
||||
|
||||
|
||||
// food
|
||||
struct Food {
|
||||
unsigned int x;
|
||||
unsigned int y;
|
||||
QGraphicsPixmapItem* image;
|
||||
void update( const unsigned int& new_x, const unsigned int& new_y ) {
|
||||
this->x = new_x;
|
||||
this->y = new_y;
|
||||
this->image->setOffset( new_x*32, new_y*32 );
|
||||
}
|
||||
};
|
||||
|
||||
Food food;
|
||||
|
||||
void spawnFood();
|
||||
|
||||
|
||||
// field
|
||||
enum Tile{
|
||||
EMPTY,
|
||||
|
@ -58,9 +116,11 @@ private:
|
|||
|
||||
Tile field[16][16];
|
||||
|
||||
|
||||
// score
|
||||
int game_score = 0;
|
||||
|
||||
void increaseScore();
|
||||
void increaseGameScore();
|
||||
};
|
||||
|
||||
#endif // SNAKE_H
|
||||
|
|
Loading…
Reference in New Issue