diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "qloggingcategory": "cpp" + } +} \ No newline at end of file diff --git a/backgroundselector.cpp b/backgroundselector.cpp --- a/backgroundselector.cpp +++ b/backgroundselector.cpp @@ -19,15 +19,13 @@ * Boston, MA 02110-1301, USA. */ -#include "backgroundselector.h" -#include "ui_backgroundselector.h" - #include #include +#include #include "renderer.h" - -#include +#include "backgroundselector.h" +#include "ui_backgroundselector.h" BackgroundSelector::BackgroundSelector(QWidget* parent, KConfigSkeleton* config) : QWidget(parent), @@ -76,14 +74,9 @@ void BackgroundSelector::useRandomBackgroundPicturesChanged(bool toggled) { if (toggled) - { - enableSettings(true); previewBackgroundPicture(); - } - else - { - enableSettings(false); - } + + enableSettings(toggled); } void BackgroundSelector::enableSettings(bool enable) diff --git a/ball.h b/ball.h --- a/ball.h +++ b/ball.h @@ -43,21 +43,25 @@ * Constructor */ KBounceBall( KBounceRenderer* renderer, KBounceBoard* board ); + /** * Destructor */ ~KBounceBall(); /** * Changes ball's state when collisions have been detected * Called once per frame before advance() + * @param collision list of objects collided */ void collide( const KBounceCollision& collision ); + /** * Performs move calculations * This method is called once per frame - */ + */ void goForward(); + /** * Updates ball position and pixmap. * This method is called once per frame. @@ -69,61 +73,76 @@ * @see relativePos() */ QRectF ballBoundingRect() const; + /* * Returns ball's bounding rect expected in next frame * used by colision test */ QRectF nextBoundingRect() const; + /** * Returns ball's position in board coordinate system. * Relative board's coordinates are indepentent of actual GameWidget size. */ QPointF relativePos(); + /** * Sets ball's position in board coordinate system. + * @param x position on x axis + * @param y position on y axis * @see relativePos() */ void setRelativePos( qreal x, qreal y ); + /** * Sets ball's position in board coordinate system + * @param vx velocity on x axis + * @param vy velocity on y axis */ void setVelocity( qreal vX, qreal vY ); + /** * Returns ball's velocity in board coordinate system */ KBounceVector velocity() const; - /** * Sets width and height of ball. + * @param tileSize new tile size */ void resize( const QSize& tileSize ); + /** * Rechecks the number of frames of ball animation and sets new pixmaps. * This method is useful when changing game theme. */ void resetPixmaps(); + /** * Sets a random ball's frame */ void setRandomFrame(); protected: KBounceRenderer* m_renderer; KBounceBoard* m_board; + /** * Time after emiting previous sound. If the value is too small, * ball will not emit hit sound. */ int m_soundDelay; + /** * Size of a ball in GameWidget depentant coordinate system */ QSize m_size; + /** * Number of frames of ball's animation. */ int m_framesNum; + qreal m_xPos; qreal m_yPos; KBounceVector m_velocity; diff --git a/ball.cpp b/ball.cpp --- a/ball.cpp +++ b/ball.cpp @@ -16,34 +16,41 @@ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ - -#include "ball.h" - -#include - #include +#include "ball.h" #include "board.h" #include "renderer.h" #include "debug.h" +#include + const int KBounceBall::BALL_ANIM_DELAY = 50; const qreal KBounceBall::BALL_RELATIVE_SIZE = 0.8; KBounceBall::KBounceBall( KBounceRenderer* renderer, KBounceBoard* board ) - : KGameRenderedItem(renderer,QLatin1String(""), board ), m_renderer( renderer ), m_board( board ), - m_soundDelay( 0 ), m_size( QSize( 16, 16 ) ), m_framesNum( 0 ), m_xPos( 0 ), m_yPos( 0 ) + : KGameRenderedItem(renderer,QLatin1String(""), board ), + m_renderer( renderer ), + m_board( board ), + m_soundDelay( 0 ), + m_size( QSize( 16, 16 ) ), + m_framesNum( 0 ), + m_xPos( 0 ), + m_yPos( 0 ) { setSpriteKey(QStringLiteral("ball")); resetPixmaps(); m_nextBoundingRect.setSize( QSizeF( BALL_RELATIVE_SIZE, BALL_RELATIVE_SIZE ) ); } - KBounceBall::~KBounceBall() { } +/** + * Performs move calculations + * This method is called once per frame + */ void KBounceBall::goForward() { if ( m_reflectX ) @@ -65,6 +72,11 @@ m_nextBoundingRect.moveTo( m_xPos + m_velocity.x, m_yPos + m_velocity.y ); } +/** + * Changes ball's state when collisions have been detected + * Called once per frame before advance() + * @param collision list of objects collided + */ void KBounceBall::collide( const KBounceCollision& collision ) { foreach ( const KBounceHit &hit, collision ) @@ -83,12 +95,20 @@ } } +/** + * Updates ball position and pixmap. + * This method is called once per frame. + */ void KBounceBall::update() { setFrame( frame()+1 ); setPos( m_board->mapPosition( QPointF( m_xPos, m_yPos ) ) ); } +/** + * Sets width and height of ball. + * @param tileSize new tile size + */ void KBounceBall::resize( const QSize& tileSize ) { qCDebug(KBOUNCE_LOG) << "New size:" << tileSize; @@ -99,50 +119,82 @@ setPos( m_board->mapPosition( QPointF( m_xPos, m_yPos ) ) ); } +/** + * Rechecks the number of frames of ball animation and sets new pixmaps. + * This method is useful when changing game theme. + */ void KBounceBall::resetPixmaps() { m_framesNum = frameCount(); setFrame( 1 ); } +/** + * Sets a random ball's frame + */ void KBounceBall::setRandomFrame() { int frame = 1; if ( m_framesNum > 1 ) - { frame = KRandom::random() % m_framesNum; - } + setFrame( frame ); } +/* + * Returns ball's bounding rect in board coordinate system + * @see relativePos() + */ QRectF KBounceBall::ballBoundingRect() const { return QRectF( m_xPos, m_yPos, BALL_RELATIVE_SIZE, BALL_RELATIVE_SIZE ); } +/* + * Returns ball's bounding rect expected in next frame + * used by colision test + */ QRectF KBounceBall::nextBoundingRect() const { return m_nextBoundingRect; } +/** + * Returns ball's position in board coordinate system. + * Relative board's coordinates are indepentent of actual GameWidget size. + */ QPointF KBounceBall::relativePos() { return QPointF( m_xPos, m_yPos ); } +/** + * Sets ball's position in board coordinate system. + * @param x position on x axis + * @param y position on y axis + * @see relativePos() + */ void KBounceBall::setRelativePos( qreal x, qreal y ) { m_xPos = x; m_yPos = y; setPos( m_board->mapPosition( QPointF( m_xPos, m_yPos ) ) ); } +/** + * Sets ball's position in board coordinate system + * @param vx velocity on x axis + * @param vy velocity on y axis + */ void KBounceBall::setVelocity( qreal vX, qreal vY ) { m_velocity.x = vX; m_velocity.y = vY; } +/** + * Returns ball's velocity in board coordinate system + */ KBounceVector KBounceBall::velocity() const { return KBounceVector( m_velocity.x, m_velocity.y ); diff --git a/board.h b/board.h --- a/board.h +++ b/board.h @@ -30,7 +30,6 @@ #define TILE_NUM_H 20 #define TILE_NUM_W 32 - class KBounceBall; class KBounceWall; @@ -41,57 +40,190 @@ public: enum TileType{ Empty, Free, Border, Wall, Temp }; - explicit KBounceBoard( KBounceRenderer *renderer ); + /** + * Constructor to set game board configurations + * @see board.cpp + */ + explicit KBounceBoard(KBounceRenderer *renderer); + + /** + * KbounceBoard destructor + * @see board.cpp + */ ~KBounceBoard(); + /** + * Paint walls on board + * @param background canvas context + * @return canvas painted + * @see board.cpp + */ QPixmap applyWallsOn(const QPixmap &background) const; - void resize( QSize& size ); - void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) Q_DECL_OVERRIDE {} - void newLevel( int level ); - void setPaused( bool ); - - void buildWall( const QPointF& pos, bool vertical ); + /** + * Resize the board and their components + * @param size new size + * @see board.cpp + */ + void resize(QSize& size); + void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) Q_DECL_OVERRIDE {} + /** + * Set variables to start a new level + * @param level new level + * @see board.cpp + */ + void newLevel(int level); + + /** + * Pause the timer + * @param flag "T" to pause "F" to unpause + * @see board.cpp + */ + void setPaused(bool); + + /** + * Build a wall + * @param pos mouse position + * @param vertical wall orientation + * @see board.cpp + */ + void buildWall(const QPointF& pos, bool vertical); + + /** + * Get ball ammount + * @return ball ammount + * @see board.cpp + */ int balls(); + + /** + * Get filled percentage + * @return filled percentage + * @see board.cpp + */ int filled(); - KBounceCollision checkCollision( void* object, const QRectF& rect, int type ); - KBounceCollision checkCollisionTiles( const QRectF& rect ); + /** + * Check for collisions on all objects + * @see board.cpp + */ void checkCollisions(); - QPoint mapPosition( const QPointF& pos ) const; - QRectF boundingRect() const Q_DECL_OVERRIDE; - + /** + * Set ball velocity + * @param vel new velocity + * @see board.cpp + */ void setBallVelocity(qreal velocity); + + /** + * Set wall velocity + * @param vel new velocity + * @see board.cpp + */ void setWallVelocity(qreal velocity); + + /** + * Get map tile position + * @param pos mouse position + * @return tile position + * @see board.cpp + */ + QPoint mapPosition(const QPointF& pos) const; + + /** + * Get tile template + * @return tile template + * @see board.cpp + */ + QRectF boundingRect() const Q_DECL_OVERRIDE; + + /** + * Check object collision + * @param object Object to be checked + * @param rect tile rectangle + * @param type object type + * @return collision result + * @see board.cpp + */ + KBounceCollision checkCollision(void* object, const QRectF& rect, int type); + + /** + * Check for collision to get bounce "normal" + * @param rect tile rectangle + * @return collision result + * @see board.cpp + */ + KBounceCollision checkCollisionTiles(const QRectF& rect); + signals: - void ballsChanged( int balls ); - void fillChanged( int fill ); + /** + * Signal to update balls ammount + * @see board.cpp + */ + void ballsChanged(int balls); + + /** + * Signal to update fill percentage + * @see board.cpp + */ + void fillChanged(int fill); + + /** + * Signal to update a wall death + * @see board.cpp + */ void wallDied(); protected slots: + + /** + * Event to apply tick changes + * @see board.cpp + */ void tick(); - void wallFinished( int x1, int y1, int x2, int y2 ); + + /** + * Insert wall and paint them + * @param x1 initial x position + * @param y1 initial x position + * @param x2 final y position + * @param y2 final y position + * @see board.cpp + */ + void wallFinished(int x1, int y1, int x2, int y2); private: + + /** + * Clear the board + * @see board.cpp + */ void clear(); - void fill( int x, int y ); + + /** + * Fill the tile + * @param x position x + * @param y position y + * @see board.cpp + */ + void fill(int x, int y); KBounceRenderer* m_renderer; TileType m_tiles[TILE_NUM_W][TILE_NUM_H]; QSize m_tileSize; - int m_filled; - QList m_balls; - QList m_walls; + QList m_list_balls; + QList m_list_walls; QTimer* m_clock; - qreal m_ballVelocity; qreal m_wallVelocity; + + int m_filled; }; #endif // BOARD_H diff --git a/board.cpp b/board.cpp --- a/board.cpp +++ b/board.cpp @@ -16,8 +16,6 @@ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "board.h" - #include #include @@ -28,32 +26,49 @@ #include "gameobject.h" #include "wall.h" #include "debug.h" +#include "board.h" #include #define DIR_UP 0 #define DIR_RIGHT 1 #define DIR_DOWN 2 #define DIR_LEFT 3 - -KBounceBoard::KBounceBoard( KBounceRenderer* renderer ) +/** + * KBounceBoard class + * + * Constructor to set game board configurations + * @param parent Superclass parameter + * @see board.h + */ +KBounceBoard::KBounceBoard(KBounceRenderer* renderer) : QGraphicsObject() - , m_renderer( renderer ) + , m_renderer(renderer) // Set initial renderer value { - m_clock = new QTimer( this ); - m_clock->setInterval( GAME_DELAY ); + // Create timer and set it interval + m_clock = new QTimer(this); + m_clock->setInterval(GAME_DELAY); + + // Add game rule "timeout" connect(m_clock, &QTimer::timeout, this, &KBounceBoard::tick); - m_walls.append( new KBounceWall( KBounceWall::Up, m_renderer, this ) ); - m_walls.append( new KBounceWall( KBounceWall::Right, m_renderer, this ) ); - m_walls.append( new KBounceWall( KBounceWall::Down, m_renderer, this ) ); - m_walls.append( new KBounceWall( KBounceWall::Left, m_renderer, this ) ); - foreach( KBounceWall* wall, m_walls ) + // Add the 4 initial walls (border) to the walls list + m_list_walls.append(new KBounceWall( KBounceWall::Up, m_renderer, this )); + m_list_walls.append(new KBounceWall( KBounceWall::Right, m_renderer, this )); + m_list_walls.append(new KBounceWall( KBounceWall::Down, m_renderer, this )); + m_list_walls.append(new KBounceWall( KBounceWall::Left, m_renderer, this )); + + foreach(KBounceWall* wall, m_list_walls) { + // Hide the wall wall->hide(); - connect( wall, &KBounceWall::died, this, &KBounceBoard::wallDied ); - connect( wall, &KBounceWall::finished, this, &KBounceBoard::wallFinished ); + + // Set game rule "wall died" + connect(wall, &KBounceWall::died, this, &KBounceBoard::wallDied); + + // Set game rule "wall finished" + connect(wall, &KBounceWall::finished, this, &KBounceBoard::wallFinished); } clear(); @@ -63,223 +78,314 @@ m_wallVelocity = 0.125; } + +/** + * KbounceBoard destructor + * @see board.h + */ KBounceBoard::~KBounceBoard() { - qDeleteAll( m_balls ); - qDeleteAll( m_walls ); + qDeleteAll(m_list_balls); + qDeleteAll(m_list_walls); } -void KBounceBoard::resize( QSize& size ) +/** + * Resize the board and their components + * @param size new size + * @see board.h + */ +void KBounceBoard::resize(QSize& size) { //Pause the clock to prevent ticks during resize ... bool alreadyPaused = false; + if (!m_clock->isActive()) - { - // ... but only when we are not already paused - alreadyPaused = true; - } + alreadyPaused = true; // ... but only when we are not already paused else - { setPaused(true); - } - int minTileSize; - if ( TILE_NUM_H * size.width() - TILE_NUM_W * size.height() > 0 ) { - minTileSize = size.height() / TILE_NUM_H; - } else { - minTileSize = size.width() / TILE_NUM_W; - } + // Calculate minimum tile size + int sizeFactor = (TILE_NUM_H * size.width()) - (TILE_NUM_W * size.height()); + int minTileSize = sizeFactor > 0 ? size.height() / TILE_NUM_H : size.width() / TILE_NUM_W; - m_tileSize = QSize( minTileSize, minTileSize ); + // Create new tile size + m_tileSize = QSize(minTileSize, minTileSize); - foreach( KBounceBall* ball, m_balls ) { - ball->resize( m_tileSize ); + // Resize each ball + foreach(KBounceBall* ball, m_list_balls) { + ball->resize(m_tileSize); } - foreach( KBounceWall* wall, m_walls ) { - wall->resize( m_tileSize ); + // Resize each wall + foreach(KBounceWall* wall, m_list_walls) { + wall->resize(m_tileSize); } - size.setWidth( minTileSize * TILE_NUM_W ); - size.setHeight( minTileSize * TILE_NUM_H ); + // Set new board size + size.setWidth(minTileSize * TILE_NUM_W); + size.setHeight(minTileSize * TILE_NUM_H); + + // Unpause the board if (!alreadyPaused) - { setPaused(false); - } } -void KBounceBoard::newLevel( int level ) +/** + * Set variables to start a new level + * @param level new level + * @see board.h + */ +void KBounceBoard::newLevel(int level) { + // Stop the timer m_clock->stop(); + + // Clear the board clear(); - emit fillChanged( m_filled ); - while ( m_balls.count() > level + 1 ) + // Emit signal to apply filled reset + emit fillChanged(m_filled); + + // "if the board have more balls than necessary, remove the last one" + while (m_list_balls.count() > level + 1) { - delete m_balls.back(); - m_balls.removeLast(); + delete m_list_balls.back(); + m_list_balls.removeLast(); } - while ( m_balls.count() < level + 1) + + // "if the board are lack of balls, add a new one" + while (m_list_balls.count() < level + 1) { - KBounceBall* ball = new KBounceBall( m_renderer, this ); - ball->resize( m_tileSize ); - m_balls.append( ball ); + KBounceBall* ball = new KBounceBall(m_renderer, this); + ball->resize(m_tileSize); + m_list_balls.append(ball); } - foreach( KBounceBall* ball, m_balls ) + + // Set the position and velocity for each ball + foreach(KBounceBall* ball, m_list_balls) { - ball->setRelativePos( 4 + KRandom::random() % ( TILE_NUM_W - 8 ), - 4 + KRandom::random() % ( TILE_NUM_H - 8 ) ); - ball->setVelocity( ((KRandom::random() & 1)*2-1)*m_ballVelocity, - ((KRandom::random() & 1)*2-1)*m_ballVelocity ); + // Get random position + qreal random_x_pos = 4 + KRandom::random() % ( TILE_NUM_W - 8 ); + qreal random_y_pos = 4 + KRandom::random() % ( TILE_NUM_H - 8 ); + + // Set random positon + ball->setRelativePos(random_x_pos ,random_y_pos); + + // Get random velocity + qreal random_x_vel = ((KRandom::random() & 1)*2 - 1) * m_ballVelocity; + qreal random_y_vel = ((KRandom::random() & 1)*2 - 1)* m_ballVelocity; + + // Set random velocity + ball->setVelocity(random_x_vel ,random_y_vel); + ball->setRandomFrame(); + + // Show the ball ball->show(); } - emit ballsChanged( level + 1 ); - foreach( KBounceWall* wall, m_walls ) + // Emit signal to apply level changes + emit ballsChanged(level + 1); + + // Set velocity for each wall, and hide them + foreach(KBounceWall* wall, m_list_walls) { wall->setWallVelocity(m_wallVelocity); wall->hide(); } } -void KBounceBoard::setPaused( bool val ) +/** + * Pause the timer + * @param flag "T" to pause "F" to unpause + * @see board.h + */ +void KBounceBoard::setPaused(bool flag) { - if ( val ) + if (flag) m_clock->stop(); else m_clock->start(); } +/** + * Set ball velocity + * @param vel new velocity + * @see board.h + */ void KBounceBoard::setBallVelocity(qreal vel) { m_ballVelocity = vel; } +/** + * Set wall velocity + * @param vel new velocity + * @see board.h + */ void KBounceBoard::setWallVelocity(qreal vel) { m_wallVelocity = vel; } -void KBounceBoard::buildWall( const QPointF& pos, bool vertical ) +/** + * Build a wall + * @param pos mouse position + * @param vertical wall orientation + * @see board.h + */ +void KBounceBoard::buildWall(const QPointF& pos, bool vertical) { - QPointF unmapped( pos.x() - x(), pos.y() - y()); + QPointF unmapped(pos.x() - x(), pos.y() - y()); int x = static_cast( unmapped.x() / m_tileSize.width() ); int y = static_cast( unmapped.y() / m_tileSize.height() ); - if ( x < 0 || x >= TILE_NUM_W ) + if (x < 0 || x >= TILE_NUM_W) { qCDebug(KBOUNCE_LOG) << "Wall x position out of board."; return; } - if ( y < 0 || y >= TILE_NUM_H ) + + if (y < 0 || y >= TILE_NUM_H) { qCDebug(KBOUNCE_LOG) << "Wall y position out of board."; return; } - if ( m_tiles[x][y] != Free ) + + if (m_tiles[x][y] != Free) { qCDebug(KBOUNCE_LOG) << "Wall could not be build in a field which is not free."; return; } - if ( !vertical ) + // Set wall orientation based position + int direction_1, direction_2; + + if(vertical) { - m_walls[DIR_LEFT]->build( x, y ); - m_walls[DIR_RIGHT]->build( x, y ); + direction_1 = DIR_UP; + direction_2 = DIR_DOWN; } - else + else { - m_walls[DIR_UP]->build( x, y ); - m_walls[DIR_DOWN]->build( x, y ); + direction_1 = DIR_LEFT; + direction_2 = DIR_RIGHT; } + + // Build two oposite walls + m_list_walls[direction_1]->build(x, y); + m_list_walls[direction_2]->build(x, y); } +/** + * Get ball ammount + * @return ball ammount + * @see board.h + */ int KBounceBoard::balls() { - return m_balls.count(); + return m_list_balls.count(); } +/** + * Get filled percentage + * @return filled percentage + * @see board.h + */ int KBounceBoard::filled() { return m_filled; } -KBounceCollision KBounceBoard::checkCollision( void* object, const QRectF& rect, int type ) +/** + * Check object collision + * @param object Object to be checked + * @param rect tile rectangle + * @param type object type + * @return collision result + * @see board.h + */ +KBounceCollision KBounceBoard::checkCollision(void* object, const QRectF& rect, int type) { + // Create collision variables KBounceCollision result; + bool collisionCondition; - if ( (type & TILE) != 0 ) - { - result += checkCollisionTiles( rect ); - } + // Check for walls in a rectangular area + if ((type & TILE) != 0) + result += checkCollisionTiles(rect); - if ( (type & WALL) != 0 ) - { - foreach( KBounceWall* wall, m_walls ) + // Check for collision on top of the wall + if ((type & WALL) != 0) + foreach(KBounceWall* wall, m_list_walls) { - if ( object != wall ) + collisionCondition = (object != wall) && wall->isVisible() && rect.intersects(wall->nextBoundingRect()); + if (collisionCondition) { - if ( wall->isVisible() && rect.intersects( wall->nextBoundingRect() ) ) - { - KBounceHit hit; - hit.type = WALL; - hit.boundingRect = wall->nextBoundingRect(); - hit.normal = KBounceVector::normal( rect, hit.boundingRect ); - result += hit; - } + KBounceHit hit; + hit.type = WALL; + hit.boundingRect = wall->nextBoundingRect(); + hit.normal = KBounceVector::normal(rect, hit.boundingRect); + result += hit; } } - } - if ( (type & BALL) != 0 ) - { - foreach( KBounceBall* ball, m_balls ) + // Check for collision on a unfinished wall + if ((type & BALL) != 0) + foreach(KBounceBall* ball, m_list_balls) { - if ( object != ball ) + collisionCondition = (object != ball) && rect.intersects(ball->nextBoundingRect()); + if (collisionCondition) { - if ( rect.intersects( ball->nextBoundingRect() ) ) - { - KBounceHit hit; - hit.type = BALL; - hit.boundingRect = ball->nextBoundingRect(); - hit.normal = KBounceVector::normal( rect, hit.boundingRect ); - result += hit; - } + KBounceHit hit; + hit.type = BALL; + hit.boundingRect = ball->nextBoundingRect(); + hit.normal = KBounceVector::normal(rect, hit.boundingRect); + result += hit; } } - } return result; } -KBounceCollision KBounceBoard::checkCollisionTiles( const QRectF& rect) +/** + * Check for collision to get bounce "normal" + * @param rect tile rectangle + * @return collision result + * @see board.h + */ +KBounceCollision KBounceBoard::checkCollisionTiles(const QRectF& rect) { - KBounceVector normal( 0, 0 ); + KBounceVector normal(0, 0); // This small constant is added to each of the coordinates to // avoid positive collision test result when tested rect lies // on the edge of non-free space qreal D = 0.01; + // Check for bounce top left QPointF p = rect.topLeft(); int ul = m_tiles[static_cast( p.x() + D )][static_cast( p.y() + D )]; - if ( ul != Free ) normal += KBounceVector( 1, 1 ); + if (ul != Free) normal += KBounceVector(1, 1); + // Check for bounce top right p = rect.topRight(); int ur = m_tiles[static_cast( p.x() - D )][static_cast( p.y() + D )]; - if ( ur != Free) normal += KBounceVector( -1, 1 ); + if (ur != Free) normal += KBounceVector(-1, 1); + // Check for bounce bottom right p = rect.bottomRight(); int lr = m_tiles[static_cast( p.x() - D )][static_cast( p.y() - D )]; - if ( lr != Free ) normal += KBounceVector( -1, -1 ); + if (lr != Free) normal += KBounceVector(-1, -1); + // Check for bounce bottom left p = rect.bottomLeft(); int ll = m_tiles[static_cast( p.x() + D )][static_cast( p.y() - D )]; - if ( ll != Free ) normal += KBounceVector( 1, -1 ); + if (ll != Free) normal += KBounceVector(1, -1); + // Add collision entity KBounceCollision collision; - if ( (ul != Free ) || ( ur != Free ) || ( lr != Free ) || ( ll != Free ) ) + if ((ul != Free) || (ur != Free) || (lr != Free) || (ll != Free)) { KBounceHit hit; hit.type = TILE; @@ -289,153 +395,238 @@ return collision; } +/** + * Check for collisions on all objects + * @see board.h + */ void KBounceBoard::checkCollisions() { - foreach( KBounceWall* wall, m_walls ) + // Collision for walls + foreach(KBounceWall* wall, m_list_walls) { QRectF rect = wall->nextBoundingRect(); KBounceCollision collision; - collision = checkCollision( wall, rect, ALL ); - wall->collide( collision ); + collision = checkCollision(wall, rect, ALL); + wall->collide(collision); } - foreach( KBounceBall* ball, m_balls ) + + // Collision for balls + foreach(KBounceBall* ball, m_list_balls) { QRectF rect = ball->nextBoundingRect(); KBounceCollision collision; - collision = checkCollision( ball, rect, ALL ); - ball->collide( collision ); + collision = checkCollision(ball, rect, ALL); + ball->collide(collision); } } -QPoint KBounceBoard::mapPosition( const QPointF& pos ) const +/** + * Get map tile position + * @param pos mouse position + * @return tile position + * @see board.h + */ +QPoint KBounceBoard::mapPosition(const QPointF& pos) const { - return QPoint( static_cast( m_tileSize.width() * pos.x() ), - static_cast( m_tileSize.height() * pos.y() ) ); + return QPoint( + static_cast( m_tileSize.width() * pos.x()), + static_cast( m_tileSize.height() * pos.y()) + ); } +/** + * Get tile template + * @return tile template + * @see board.h + */ QRectF KBounceBoard::boundingRect() const { - return QRectF( x(), y(), - TILE_NUM_W * m_tileSize.width(), - TILE_NUM_H * m_tileSize.height() ); + return QRectF( + x(), y(), + TILE_NUM_W * m_tileSize.width(), + TILE_NUM_H * m_tileSize.height() + ); } +/** + * Event to apply tick changes + * @see board.h + */ void KBounceBoard::tick() { + // Check all collisions checkCollisions(); - foreach( KBounceBall* ball, m_balls ) + // Move and update the balls + foreach(KBounceBall* ball, m_list_balls) { ball->goForward(); - } - foreach( KBounceWall* wall, m_walls ) - { - wall->goForward(); - } - - foreach( KBounceBall* ball, m_balls ) - { ball->update(); } - foreach( KBounceWall* wall, m_walls ) + // Move and update the walls + foreach(KBounceWall* wall, m_list_walls) { + wall->goForward(); wall->update(); } } +/** + * Paint walls on board + * @param background canvas context + * @return canvas painted + * @see board.h + */ QPixmap KBounceBoard::applyWallsOn(const QPixmap &background) const { if (m_tileSize.isEmpty()) return background; + // Get grid and wall images QPixmap walledBackground = background; const QPixmap gridTile = m_renderer->spritePixmap(QStringLiteral("gridTile"), m_tileSize); const QPixmap wallTile = m_renderer->spritePixmap(QStringLiteral("wallTile"), m_tileSize); + + // Create painter QPainter p(&walledBackground); - for (int i = 0; i < TILE_NUM_W; ++i) { - for (int j = 0; j < TILE_NUM_H; ++j) { - switch (m_tiles[i][j]) { + + for (int i = 0; i < TILE_NUM_W; ++i) + { + for (int j = 0; j < TILE_NUM_H; ++j) + { + + // Calculate pixmap values + int pixmap_x = x() + i * m_tileSize.width(); + int pixmap_y = y() + j * m_tileSize.height(); + + switch (m_tiles[i][j]) + { + // Draw grid tile case Free: - p.drawPixmap(x() + i * m_tileSize.width(), y() + j * m_tileSize.height(), gridTile); + p.drawPixmap(pixmap_x, pixmap_y, gridTile); break; case Border: case Wall: - p.drawPixmap(x() + i * m_tileSize.width(), y() + j * m_tileSize.height(), wallTile); + // Draw wall tile + p.drawPixmap(pixmap_x, pixmap_y, wallTile); break; default: break; } } } + + // Return new painted background return walledBackground; } -void KBounceBoard::wallFinished( int x1, int y1, int x2, int y2 ) +/** + * Insert wall and paint them + * @param x1 initial x position + * @param y1 initial x position + * @param x2 final y position + * @param y2 final y position + * @see board.h + */ +void KBounceBoard::wallFinished(int x1, int y1, int x2, int y2) { - for ( int x = x1; x < x2; x++ ) - for ( int y = y1; y < y2; y++ ) + // Insert walls + for (int x = x1; x < x2; x++) + for (int y = y1; y < y2; y++) m_tiles[x][y] = Wall; - foreach ( KBounceBall* ball, m_balls ) + // Fill walls + foreach (KBounceBall* ball, m_list_balls) { int x1 = static_cast( ball->ballBoundingRect().x() ); int y1 = static_cast( ball->ballBoundingRect().y() ); int x2 = static_cast( ball->ballBoundingRect().right() ); int y2 = static_cast( ball->ballBoundingRect().bottom() ); - // try to fill from all edges - // this way we can avoid most precision-related issues + + // try to fill from all edges, this way we can avoid most precision-related issues fill(x1, y1); fill(x1, y2); fill(x2, y1); fill(x2, y2); } - for ( int x = 0; x < TILE_NUM_W; x++ ) - for ( int y = 0; y < TILE_NUM_H; y++ ) - if ( m_tiles[x][y] == Free ) - m_tiles[x][y] = Wall; - for ( int x = 0; x < TILE_NUM_W; x++ ) - for ( int y = 0; y < TILE_NUM_H; y++ ) - if ( m_tiles[x][y] == Temp ) - m_tiles[x][y] = Free; - int filled = 0; - for ( int i = 1; i < TILE_NUM_W - 1; i++ ) - for ( int j = 1; j < TILE_NUM_H - 1; j++ ) - if ( m_tiles[i][j] == Wall ) - filled++; - m_filled = filled * 100 / ( ( TILE_NUM_W - 2 ) * ( TILE_NUM_H - 2 ) ); - scene()->setBackgroundBrush(applyWallsOn(m_renderer->renderBackground())); + for (int i = 0; i < TILE_NUM_W; i++) + for (int j = 0; j < TILE_NUM_H; j++) { + + // Validade wall interval + bool inside_i = (i > 0) && (i < TILE_NUM_W - 1); + bool inside_j = (j > 0) && (j < TILE_NUM_H - 1); + + // Convert free to wall + if (m_tiles[i][j] == Free) + m_tiles[i][j] = Wall; + + // Convert temp to free + if (m_tiles[i][j] == Temp) + m_tiles[i][j] = Free; + + // Count wall as filled if inside the board + if (m_tiles[i][j] == Wall && inside_i && inside_j) + filled++; + } + + // Calculate filled percentage + m_filled = filled * 100 / ((TILE_NUM_W - 2) * (TILE_NUM_H - 2)); - emit fillChanged( m_filled ); + // Render wall background + scene()->setBackgroundBrush( + applyWallsOn(m_renderer->renderBackground()) + ); + + // Emit signal to apply filled percentage + emit fillChanged(m_filled); } +/** + * Clear the board + * @see board.h + */ void KBounceBoard::clear() { - for ( int i = 0; i < TILE_NUM_W; i++ ) - m_tiles[i][0] = m_tiles[i][TILE_NUM_H-1] = Border; - for ( int j = 0; j < TILE_NUM_H; j++ ) - m_tiles[0][j] = m_tiles[TILE_NUM_W-1][j] = Border; - for ( int i = 1; i < TILE_NUM_W - 1; i++ ) - for ( int j = 1; j < TILE_NUM_H -1; j++ ) - m_tiles[i][j] = Free; + for (int i = 0; i < TILE_NUM_W; i++) + for (int j = 0; j < TILE_NUM_H; j++) { + + // Validade wall interval + bool inside_i = (i > 0) && (i < TILE_NUM_W - 1); + bool inside_j = (j > 0) && (j < TILE_NUM_H - 1); + + // Update to free or border + m_tiles[i][j] = (inside_i && inside_j) ? Free : Border; + } + + // Reset filled percentage m_filled = 0; } -void KBounceBoard::fill( int x, int y ) +/** + * Fill the tile + * @param x position x + * @param y position y + * @see board.h + */ +void KBounceBoard::fill(int x, int y) { - if ( m_tiles[x][y] != Free ) + // "Stop if you found something" + if (m_tiles[x][y] != Free) return; + m_tiles[x][y] = Temp; - if ( y > 0 ) fill( x, y - 1 ); - if ( x < TILE_NUM_W - 1 ) fill ( x + 1, y ); - if ( y < TILE_NUM_H - 1 ) fill ( x, y + 1 ); - if ( x > 0 ) fill ( x - 1, y ); + // Fill the tile + if (y > 0) fill(x, y - 1); + if (x < TILE_NUM_W - 1) fill(x + 1, y); + if (y < TILE_NUM_H - 1) fill(x, y + 1); + if (x > 0) fill(x - 1, y); } diff --git a/gameobject.h b/gameobject.h --- a/gameobject.h +++ b/gameobject.h @@ -70,14 +70,17 @@ * Type of hitter */ KBounceObjectType type; + /* * Bounding rect of hitter */ QRectF boundingRect; + /* * Velocity of hiter */ KBounceVector velocity; + /* * Vector perpendicular to object's being hitted surface in * the area of intersection with hitter diff --git a/gameobject.cpp b/gameobject.cpp --- a/gameobject.cpp +++ b/gameobject.cpp @@ -21,18 +21,24 @@ #include "gameobject.h" -KBounceVector KBounceVector::normal( const QRectF& rect1, const QRectF& rect2 ) +/** + * GameObject class + * + * Constructor to calculate game object normal + * @see gameobject.h + */ +KBounceVector KBounceVector::normal(const QRectF& rect1,const QRectF& rect2) { - KBounceVector normal( 0, 0 ); + KBounceVector normal(0, 0); - if ( rect1.bottom() > rect2.top() && rect1.bottom() < rect2.bottom() ) - normal += KBounceVector( 0, -1 ); - if ( rect1.top() < rect2.bottom() && rect1.top() > rect2.top() ) - normal += KBounceVector( 0, 1 ); - if ( rect1.right() < rect2.right() && rect1.right() > rect2.left() ) - normal += KBounceVector( 1, 0 ); - if ( rect1.left() > rect2.left() && rect1.left() < rect2.right() ) - normal += KBounceVector( -1, 0 ); + if (rect1.bottom() > rect2.top() && rect1.bottom() < rect2.bottom()) + normal += KBounceVector(0, -1); + if (rect1.top() < rect2.bottom() && rect1.top() > rect2.top()) + normal += KBounceVector(0, 1); + if (rect1.right() < rect2.right() && rect1.right() > rect2.left()) + normal += KBounceVector(1, 0); + if (rect1.left() > rect2.left() && rect1.left() < rect2.right()) + normal += KBounceVector(-1, 0); return normal; } diff --git a/gamewidget.h b/gamewidget.h --- a/gamewidget.h +++ b/gamewidget.h @@ -40,66 +40,203 @@ public: enum State { BeforeFirstGame, Running, BetweenLevels, Paused, Suspended, GameOver }; - explicit KBounceGameWidget( QWidget* parent = 0 ); + /** + * Constructor to set game widget configurations + * @see gamewidget.cpp + */ + explicit KBounceGameWidget(QWidget* parent = 0); + + /** + * KBounceGameWidget destructor + * @see gamewidget.cpp + */ ~KBounceGameWidget(); - int level(); - int score(); - KBounceGameWidget::State state() const { return m_state; } - KBounceRenderer* renderer() { return &m_renderer; } - + /** + * Get current game level + * @return current game level + * @see gamewidget.cpp + */ + int getLevel(); + + /** + * Get current game score + * @return current game score + * @see gamewidget.cpp + */ + int getScore(); + + /** + * Get current game state + * @return current game state + * @see gamewidget.cpp + */ + KBounceGameWidget::State state() const { return kBounceGameWidget_state; } + + /** + * Get current game renderer + * @return current game renderer + * @see gamewidget.cpp + */ + KBounceRenderer* renderer() { return &kBounceGameWidget_renderer; } + + /** + * ? + * @see gamewidget.cpp + */ QSize minimumSizeHint() const Q_DECL_OVERRIDE; public slots: + /** + * Set variables to close the game + * @see gamewidget.cpp + */ void closeGame(); + + /** + * Start a new game + * @see gamewidget.cpp + */ void newGame(); - void setPaused( bool ); + + /** + * Set state to pause the game + * @param flag pause flag + * @see gamewidget.cpp + */ + void setPaused(bool); + + /** + * Event to apply background settings + * @see gamewidget.cpp + */ void settingsChanged(); - void setSuspended( bool ); + + /** + * Set state to suspend the game + * @param flag suspend flag + * @see gamewidget.cpp + */ + void setSuspended(bool); void levelChanged(); signals: void gameOver(); - void levelChanged( int level ); - void scoreChanged( int score ); - void filledChanged( int filled ); - void livesChanged( int lives ); - void timeChanged( int time ); - void stateChanged( KBounceGameWidget::State state ); + + /** + * Event to apply level changes + * @see gamewidget.cpp + */ + void levelChanged(int level); + void scoreChanged(int score); + void filledChanged(int filled); + void livesChanged(int lives); + void timeChanged(int time); + void stateChanged(KBounceGameWidget::State state); protected slots: - void onFillChanged( int filled ); - void onLivesChanged( int lives ); + + /** + * Event to apply onFill changes + * @param fill current game filled percentage + * @see gamewidget.cpp + */ + void onFillChanged(int filled); + + /** + * Event to apply live changes + * @param lives current game lives + * @see gamewidget.cpp + */ + void onLivesChanged(int lives); + + /** + * Event to apply "die on wall" rule + * @see gamewidget.cpp + */ void onWallDied(); + + /** + * Event to apply tick changes + * @see gamewidget.cpp + */ void tick(); protected: - void resizeEvent( QResizeEvent* event ) Q_DECL_OVERRIDE; - void mouseReleaseEvent( QMouseEvent* event ) Q_DECL_OVERRIDE; + + /** + * XmlGui "resize" event + * @param *ev Event context + * @see gamewidget.cpp + */ + void resizeEvent(QResizeEvent* event) Q_DECL_OVERRIDE; + + /** + * XmlGui "mouse release" event + * @param *ev Event context + * @see gamewidget.cpp + */ + void mouseReleaseEvent(QMouseEvent* event) Q_DECL_OVERRIDE; + + /** + * XmlGui "focus out" event + * @param *ev Event context + * @see gamewidget.cpp + */ void focusOutEvent(QFocusEvent *event) Q_DECL_OVERRIDE; + + /** + * Set variables to close the level + * @see gamewidget.cpp + */ void closeLevel(); + + /** + * Start a new level + * @see gamewidget.cpp + */ void newLevel(); - void updateCursor(); - void redraw(); - void setGameDifficulty(const KgDifficultyLevel *); - KBounceRenderer m_renderer; + /** + * Update game difficulty and apply their respective rules + * @param difficulty new difficulty + * @see gamewidget.cpp + */ + void setGameDifficulty(const KgDifficultyLevel *); + + /** + * Update cursor image + * @see gamewidget.cpp + */ + void updateCursor(); - QTimer* m_clock; - KBounceBoard* m_board; - State m_state; - int m_bonus; - int m_level; - int m_score; - int m_lives; - int m_time; + /** + * Set variables to redraw the game board + * @see gamewidget.cpp + */ + void redraw(); - QGraphicsPixmapItem* m_overlay; + /** + * Generate overlay message box + * @see gamewidget.cpp + */ void generateOverlay(); - bool m_vertical; - QGraphicsScene m_scene; - KgSound m_soundTimeout; + KBounceRenderer kBounceGameWidget_renderer; + KBounceBoard* kBounceGameWidget_board; + KgSound kBounceGameWidget_soundTimeout; + + QGraphicsPixmapItem* kBounceGameWidget_overlay; + QGraphicsScene kBounceGameWidget_scene; + QTimer* kBounceGameWidget_clock; + State kBounceGameWidget_state; + + int kBounceGameWidget_bonus; + int kBounceGameWidget_level; + int kBounceGameWidget_score; + int kBounceGameWidget_lives; + int kBounceGameWidget_time; + bool kBounceGameWidget_vertical; }; #endif diff --git a/gamewidget.cpp b/gamewidget.cpp --- a/gamewidget.cpp +++ b/gamewidget.cpp @@ -16,11 +16,6 @@ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "gamewidget.h" -#include "settings.h" -#include "wall.h" -#include "debug.h" - #include #include #include @@ -30,440 +25,731 @@ #include #include +#include "gamewidget.h" +#include "settings.h" +#include "wall.h" +#include "debug.h" + static const int MIN_MARGIN = 50; static const int GAME_TIME_DELAY = 1000; static const int MIN_FILL_PERCENT = 75; static const int POINTS_FOR_LIFE = 15; static const int TICKS_PER_SECOND = 1000 / GAME_TIME_DELAY; +/** + * KBounceGameWidget class + * + * Constructor to set game widget configurations + * @param parent Superclass parameter + * @see gamewidget.h + */ KBounceGameWidget::KBounceGameWidget( QWidget* parent ) : QGraphicsView( parent ) - , m_state( BeforeFirstGame ) - , m_bonus( 0 ) - , m_level( 0 ) - , m_lives( 0 ) - , m_time( 0 ) - , m_vertical( false ) - , m_soundTimeout( QStandardPaths::locate( QStandardPaths::AppDataLocation, QStringLiteral("sounds/timeout.wav") ) ) + , kBounceGameWidget_state( BeforeFirstGame ) // set initial game state + , kBounceGameWidget_bonus( 0 ) // set initial bonus value + , kBounceGameWidget_level( 0 ) // set initial level value + , kBounceGameWidget_lives( 0 ) // set initial lives value + , kBounceGameWidget_time( 0 ) // set initial time value + , kBounceGameWidget_vertical( false ) // set initial orientation flag + , kBounceGameWidget_soundTimeout( QStandardPaths::locate( QStandardPaths::AppDataLocation, QStringLiteral("sounds/timeout.wav") ) ) // set timout sound asset { - m_board = new KBounceBoard( &m_renderer ); - connect(m_board, &KBounceBoard::fillChanged, this, &KBounceGameWidget::onFillChanged); - connect(m_board, &KBounceBoard::wallDied, this, &KBounceGameWidget::onWallDied); + + // Create game board (Game rules) + kBounceGameWidget_board = new KBounceBoard(&kBounceGameWidget_renderer); + + // Add game rule "fill board" + connect(kBounceGameWidget_board, &KBounceBoard::fillChanged, this, &KBounceGameWidget::onFillChanged); + + // Add game rule "die on wall" + connect(kBounceGameWidget_board, &KBounceBoard::wallDied, this, &KBounceGameWidget::onWallDied); + + // Create and hide overlay message box + kBounceGameWidget_overlay = new QGraphicsPixmapItem(); + kBounceGameWidget_overlay->hide(); + + // Create game timer + kBounceGameWidget_clock = new QTimer(this); + + // Set timer interval between ticks + kBounceGameWidget_clock->setInterval(GAME_TIME_DELAY); - m_overlay = new QGraphicsPixmapItem(); - m_overlay->hide(); + // Add game rule "timeout" + connect(kBounceGameWidget_clock, &QTimer::timeout, this, &KBounceGameWidget::tick); - m_clock = new QTimer( this ); - m_clock->setInterval( GAME_TIME_DELAY ); - connect(m_clock, &QTimer::timeout, this, &KBounceGameWidget::tick); + // Add game rule about lives connect(this, &KBounceGameWidget::livesChanged, this, &KBounceGameWidget::onLivesChanged); - setMouseTracking( true ); + // ? + setMouseTracking(true); - connect(m_renderer.themeProvider(), &KgThemeProvider::currentThemeChanged, + // Add theme controller on settings + connect(kBounceGameWidget_renderer.themeProvider(), &KgThemeProvider::currentThemeChanged, this, &KBounceGameWidget::settingsChanged); - m_scene.addItem( m_board ); - m_scene.addItem( m_overlay ); - setScene( &m_scene ); + // Add game board + kBounceGameWidget_scene.addItem(kBounceGameWidget_board); + + // Add overlay message box + kBounceGameWidget_scene.addItem(kBounceGameWidget_overlay); + + // Set game scene + setScene(&kBounceGameWidget_scene); } +/** + * KBounceGameWidget destructor + * @see gamewidget.h + */ KBounceGameWidget::~KBounceGameWidget() { - delete m_board; - delete m_overlay; + delete kBounceGameWidget_board; + delete kBounceGameWidget_overlay; } -int KBounceGameWidget::level() +/** + * Get current game level + * @return current game level + * @see gamewidget.h + */ +int KBounceGameWidget::getLevel() { - return m_level; + return kBounceGameWidget_level; } -int KBounceGameWidget::score() +/** + * Get current game score + * @return current game score + * @see gamewidget.h + */ +int KBounceGameWidget::getScore() { - qCDebug(KBOUNCE_LOG) << "Score:" << m_score; - return m_score; + qCDebug(KBOUNCE_LOG) << "Score:" << kBounceGameWidget_score; + return kBounceGameWidget_score; } +/** + * ? + * @see gamewidget.h + */ QSize KBounceGameWidget::minimumSizeHint() const { - return QSize( 576, 384 ); + return QSize(576, 384); } +/** + * Set variables to close the game + * @see gamewidget.h + */ void KBounceGameWidget::closeGame() { - if ( m_state != BeforeFirstGame && m_state != GameOver ) + if (kBounceGameWidget_state != BeforeFirstGame && kBounceGameWidget_state != GameOver) { - m_clock->stop(); - m_board->setPaused( true ); - m_state = GameOver; - emit stateChanged( m_state ); + // Stop the timer + kBounceGameWidget_clock->stop(); + + // Pause balls on board movement + kBounceGameWidget_board->setPaused(true); + + // Set game over state + kBounceGameWidget_state = GameOver; + + // Emit signals to apply state + emit stateChanged(kBounceGameWidget_state); emit gameOver(); - Kg::difficulty()->setGameRunning( false ); + // Stop game + Kg::difficulty()->setGameRunning(false); + + // Redraw the game board redraw(); } } +/** + * Start a new game + * @see gamewidget.h + */ void KBounceGameWidget::newGame() { + // Close previous game closeGame(); - m_level = 1; - m_score = 0; - emit levelChanged( m_level ); - emit scoreChanged( m_score ); + // Set initial game variables + kBounceGameWidget_level = 1; + kBounceGameWidget_score = 0; - Kg::difficulty()->setGameRunning( true ); + // Emit signals to apply level and score + emit levelChanged(kBounceGameWidget_level); + emit scoreChanged(kBounceGameWidget_score); + + // Start game + Kg::difficulty()->setGameRunning(true); + + // Start a new level newLevel(); } -void KBounceGameWidget::setPaused( bool val ) +/** + * Set state to pause the game + * @param flag pause flag + * @see gamewidget.h + */ +void KBounceGameWidget::setPaused(bool flag) { - if ( m_state == Paused && val == false ) + if ( kBounceGameWidget_state == Paused && !flag) { - m_clock->start(); - m_board->setPaused( false ); - m_state = Running; - emit stateChanged( m_state ); + // Start the timer + kBounceGameWidget_clock->start(); + + // Unpause game board + kBounceGameWidget_board->setPaused(false); + + // Update state + kBounceGameWidget_state = Running; + + // Emit signal to apply state + emit stateChanged(kBounceGameWidget_state); } - else if ( m_state == Running && val == true ) + else if (kBounceGameWidget_state == Running && flag) { - m_clock->stop(); - m_board->setPaused( true ); - m_state = Paused; - emit stateChanged( m_state ); + // Stop the timer + kBounceGameWidget_clock->stop(); + + // Pause game board + kBounceGameWidget_board->setPaused(true); + + // Update state + kBounceGameWidget_state = Paused; + + // Emit signal to apply state + emit stateChanged(kBounceGameWidget_state); } + // Redraw the game board redraw(); } -void KBounceGameWidget::setSuspended( bool val ) +/** + * Set state to suspend the game + * @param flag suspend flag + * @see gamewidget.h + */ +void KBounceGameWidget::setSuspended(bool flag) { - if ( m_state == Suspended && val == false ) + if (kBounceGameWidget_state == Suspended && !flag) { - m_clock->start(); - m_board->setPaused( false ); - m_state = Running; - emit stateChanged( m_state ); + // Start the timer + kBounceGameWidget_clock->start(); + + // Unpause game board + kBounceGameWidget_board->setPaused(false); + + // Update state + kBounceGameWidget_state = Running; + + // Emit signal to apply state + emit stateChanged(kBounceGameWidget_state); } - if ( m_state == Running && val == true ) + if (kBounceGameWidget_state == Running && flag) { - m_clock->stop(); - m_board->setPaused( true ); - m_state = Suspended; - emit stateChanged( m_state ); + // Stop the timer + kBounceGameWidget_clock->stop(); + + // Pause game board + kBounceGameWidget_board->setPaused(true); + + // Update state + kBounceGameWidget_state = Suspended; + + // Emit signal to apply state + emit stateChanged(kBounceGameWidget_state); } + + // Redraw the game board redraw(); } +/** + * Event to apply background settings + * @see gamewidget.h + */ void KBounceGameWidget::settingsChanged() { qCDebug(KBOUNCE_LOG) << "Settings changed"; if (KBounceSettings::useRandomBackgroundPictures()) - { - m_renderer.setCustomBackgroundPath(KBounceSettings::backgroundPicturePath()); - } + kBounceGameWidget_renderer.setCustomBackgroundPath(KBounceSettings::backgroundPicturePath()); else - { - m_renderer.setCustomBackgroundPath(QString()); - } + kBounceGameWidget_renderer.setCustomBackgroundPath(QString()); + + // Redraw the game board redraw(); } -void KBounceGameWidget::setGameDifficulty( const KgDifficultyLevel * difficulty ) +/** + * Update game difficulty and apply their respective rules + * @param difficulty new difficulty + * @see gamewidget.h + */ +void KBounceGameWidget::setGameDifficulty(const KgDifficultyLevel * difficulty) { - switch ( difficulty->hardness() ) { + switch (difficulty->hardness()) + { + + // Apply configuratons for difficulty "Easy" case KgDifficultyLevel::Easy: - m_board->setBallVelocity(0.100); - m_board->setWallVelocity(0.250); + // Ball velocity + kBounceGameWidget_board->setBallVelocity(0.100); + + // Wall velocity + kBounceGameWidget_board->setWallVelocity(0.250); break; + + // Apply configuratons for difficulty "Medium" case KgDifficultyLevel::Medium: - m_board->setWallVelocity(0.125); - m_board->setBallVelocity(0.125); + // Ball velocity + kBounceGameWidget_board->setWallVelocity(0.125); + + // Wall velocity + kBounceGameWidget_board->setBallVelocity(0.125); break; + + // Apply configuratons for difficulty "Hard" case KgDifficultyLevel::Hard: - m_board->setWallVelocity(0.100); - m_board->setBallVelocity(0.250); + // Ball velocity + kBounceGameWidget_board->setBallVelocity(0.250); + + // Wall velocity + kBounceGameWidget_board->setWallVelocity(0.100); break; } } +/** + * Event to apply level changes + * @see gamewidget.h + */ void KBounceGameWidget::levelChanged() { - setGameDifficulty( Kg::difficulty()->currentLevel() ); + // Set game difficulty + setGameDifficulty(Kg::difficulty()->currentLevel()); - if ( m_state == Running || m_state == Paused ) + // Start new game board + if (kBounceGameWidget_state == Running || kBounceGameWidget_state == Paused) newGame(); } -void KBounceGameWidget::onFillChanged( int fill ) +/** + * Event to apply onFill changes + * @param fill current game filled percentage + * @see gamewidget.h + */ +void KBounceGameWidget::onFillChanged(int fill) { - emit filledChanged( fill ); - if ( fill >= MIN_FILL_PERCENT ) + // Emit signal to apply filled percentage + emit filledChanged(fill); + if (fill >= MIN_FILL_PERCENT) { + // Close previous level closeLevel(); - m_level++; - emit levelChanged( m_level ); + + // Update game level + kBounceGameWidget_level++; + + // Emit signal to apply game level + emit levelChanged(kBounceGameWidget_level); + + // Update game state + kBounceGameWidget_state = BetweenLevels; - m_state = BetweenLevels; - emit stateChanged( m_state ); + // Emit signal to apply state + emit stateChanged(kBounceGameWidget_state); + // Redraw the game board redraw(); } } +/** + * Event to apply "die on wall" rule + * @see gamewidget.h + */ void KBounceGameWidget::onWallDied() { - if ( m_lives <= 1 ) - { - closeGame(); - } + if (kBounceGameWidget_lives <= 1) + closeGame(); // Close curent game else { - m_lives--; - emit livesChanged( m_lives ); + // Update lives + kBounceGameWidget_lives--; + + // Emit signal to apply lives + emit livesChanged(kBounceGameWidget_lives); } } +/** + * Event to apply live changes + * @param lives current game lives + * @see gamewidget.h + */ void KBounceGameWidget::onLivesChanged(int lives) { - if ( lives < ( m_level + 1 ) - && KBounceSettings::playSounds() ) - { - m_soundTimeout.start(); - } + // Play timeout sound after lives changes + if (lives < (kBounceGameWidget_level + 1) && KBounceSettings::playSounds()) + kBounceGameWidget_soundTimeout.start(); } - +/** + * Event to apply tick changes + * @see gamewidget.h + */ void KBounceGameWidget::tick() { + // Set initial ticks value static int ticks = TICKS_PER_SECOND; + + // Update ticks ticks--; - if ( ticks <= 0 ) + + if (ticks <= 0) { - emit timeChanged( --m_time ); - if ( m_time == 0 ) - { - closeGame(); - } + // Emit signal to apply time changes + emit timeChanged(--kBounceGameWidget_time); + + if (kBounceGameWidget_time == 0) + closeGame(); // Close curent game + + // Restart ticks value ticks = TICKS_PER_SECOND; } } -void KBounceGameWidget::resizeEvent( QResizeEvent* ev ) +/** + * XmlGui "resize" event + * @param *ev Event context + * @see gamewidget.h + */ +void KBounceGameWidget::resizeEvent(QResizeEvent* ev) { qCDebug(KBOUNCE_LOG) << "Size" << ev->size(); - m_renderer.setBackgroundSize( ev->size() ); + // Update background size + kBounceGameWidget_renderer.setBackgroundSize(ev->size()); - QRectF rect( 0, 0, ev->size().width(), ev->size().height() ); - m_scene.setSceneRect( rect ); + // Update central wiget size + QRectF rect(0, 0, ev->size().width(), ev->size().height()); + kBounceGameWidget_scene.setSceneRect(rect); - QSize boardSize( sceneRect().width() - MIN_MARGIN, - sceneRect().height() - MIN_MARGIN ); - m_board->resize( boardSize ); + // Update game board size + QSize boardSize(sceneRect().width() - MIN_MARGIN, sceneRect().height() - MIN_MARGIN); + kBounceGameWidget_board->resize(boardSize); - qreal x = ( sceneRect().width() - m_board->boundingRect().width() ) / 2; - qreal y = ( sceneRect().height() - m_board->boundingRect().height() ) / 2; - m_board->setPos( x, y ); + qreal x = (sceneRect().width() - kBounceGameWidget_board->boundingRect().width()) / 2; + qreal y = (sceneRect().height() - kBounceGameWidget_board->boundingRect().height()) / 2; + kBounceGameWidget_board->setPos(x, y); + // Redraw the game board redraw(); } -void KBounceGameWidget::mouseReleaseEvent( QMouseEvent* event ) +/** + * XmlGui "mouse release" event + * @param *ev Event context + * @see gamewidget.h + */ +void KBounceGameWidget::mouseReleaseEvent(QMouseEvent* event) { - if ( event->button() & Qt::RightButton ) + // Release right button + if (event->button() & Qt::RightButton) { - m_vertical = !m_vertical; + kBounceGameWidget_vertical = !kBounceGameWidget_vertical; + // Update cursor image updateCursor(); } - if ( event->button() & Qt::LeftButton ) + // Release left button + if (event->button() & Qt::LeftButton) { - if ( m_state == Running ) + switch (kBounceGameWidget_state) { - m_board->buildWall( mapToScene( event->pos() ), m_vertical ); - } - else if ( m_state == Paused ) - { - setPaused( false ); - } - else if ( m_state == BetweenLevels ) - { - newLevel(); - } - else if ( m_state == BeforeFirstGame || m_state == GameOver ) - { - newGame(); + // Build wall if running + case Running: + kBounceGameWidget_board->buildWall(mapToScene( event->pos() ), kBounceGameWidget_vertical); + break; + + // Unpause game if paused + case Paused: + setPaused(false); + break; + + // Create a new level if is between levels + case BetweenLevels: + newLevel(); + break; + + // Create a new game if is before the first game or in a game over + case BeforeFirstGame: + case GameOver: + newGame(); + break; } } } - +/** + * Set variables to close the level + * @see gamewidget.h + */ void KBounceGameWidget::closeLevel() { - m_bonus = 0; - if ( m_board->filled() >= MIN_FILL_PERCENT ) - { - m_bonus = ( m_board->filled() - MIN_FILL_PERCENT ) * 2 * ( m_level + 5 ); - } - m_score += m_bonus; - m_score += POINTS_FOR_LIFE * m_lives; - emit scoreChanged( m_score ); + // Apply bonus score rule + kBounceGameWidget_bonus = 0; + if (kBounceGameWidget_board->filled() >= MIN_FILL_PERCENT) + kBounceGameWidget_bonus = (kBounceGameWidget_board->filled() - MIN_FILL_PERCENT) * 2 * (kBounceGameWidget_level + 5); + + // Add bonus score + kBounceGameWidget_score += kBounceGameWidget_bonus; + + // Add life score + kBounceGameWidget_score += POINTS_FOR_LIFE * kBounceGameWidget_lives; + + // Emit signal to apply score + emit scoreChanged(kBounceGameWidget_score); - m_clock->stop(); - m_board->setPaused( true ); + // Stop timer + kBounceGameWidget_clock->stop(); + + // Pause the game + kBounceGameWidget_board->setPaused(true); } +/** + * Start a new level + * @see gamewidget.h + */ void KBounceGameWidget::newLevel() { - m_state = Running; - emit stateChanged( m_state ); + // Update game state + kBounceGameWidget_state = Running; + + // Emit signal to apply state + emit stateChanged(kBounceGameWidget_state); - m_clock->start(); - m_board->newLevel( m_level ); - m_board->setPaused( false ); + // Start the timer + kBounceGameWidget_clock->start(); - m_bonus = 0; - m_lives = m_level + 1; - m_time = 30 * ( m_level + 2 ); - emit livesChanged( m_lives ); - emit timeChanged( m_time ); + // Set initial level + kBounceGameWidget_board->newLevel(kBounceGameWidget_level); + // Unpause the game + kBounceGameWidget_board->setPaused(false); + + // Update game variables (bonus, lives and time) + kBounceGameWidget_bonus = 0; + kBounceGameWidget_lives = kBounceGameWidget_level + 1; + kBounceGameWidget_time = 30 * (kBounceGameWidget_level + 2); + + // Emit signals to apply game variables (lives and time) + emit livesChanged(kBounceGameWidget_lives); + emit timeChanged(kBounceGameWidget_time); + + // Load a random background if (KBounceSettings::useRandomBackgroundPictures()) - m_renderer.loadNewBackgroundPixmap(); + kBounceGameWidget_renderer.loadNewBackgroundPixmap(); + // Redraw the game board redraw(); } - +/** + * Set variables to redraw the game board + * @see gamewidget.h + */ void KBounceGameWidget::redraw() { - if ( size().isEmpty() ) + if (size().isEmpty()) return; - switch ( m_state ) + switch (kBounceGameWidget_state) { + // Actions to redraw before first game case BeforeFirstGame: - m_board->hide(); + // Hide game board + kBounceGameWidget_board->hide(); + + // Generate and show message overlay generateOverlay(); - m_overlay->show(); + kBounceGameWidget_overlay->show(); break; + + // Actions to redraw while running case Running: - m_board->show(); - m_overlay->hide(); + // Show game board + kBounceGameWidget_board->show(); + + // Hide message overlay + kBounceGameWidget_overlay->hide(); break; + + // Default redraw actions default: - m_board->show(); + // Show game board + kBounceGameWidget_board->show(); + + // Generate and show message overlay generateOverlay(); - m_overlay->show(); + kBounceGameWidget_overlay->show(); break; } + // Update cursor image updateCursor(); + + // Load wall sprites KBounceWall::loadSprites(); - m_scene.setBackgroundBrush( m_board->applyWallsOn(m_renderer.renderBackground()) ); + + // Set initial background + kBounceGameWidget_scene.setBackgroundBrush( kBounceGameWidget_board->applyWallsOn(kBounceGameWidget_renderer.renderBackground()) ); + update(); } +/** + * Generate overlay message box + * @see gamewidget.h + */ void KBounceGameWidget::generateOverlay() { - if ( size().isEmpty() ) + if (size().isEmpty()) return; - int itemWidth = qRound( 0.8 * size().width() ); - int itemHeight = qRound( 0.6 * size().height() ); - - QSize backgroundSize( itemWidth,itemHeight ); + // Set width and height + int itemWidth = qRound(0.8 * size().width()); + int itemHeight = qRound(0.6 * size().height()); - QPixmap px( backgroundSize ); - px.fill( Qt::transparent ); + // Create background canvas + QSize backgroundSize(itemWidth, itemHeight); - QPainter p( &px ); + // Create bitmap from background canvas + QPixmap px(backgroundSize); + px.fill(Qt::transparent); - p.setPen( Qt::transparent ); - p.setRenderHint(QPainter::Antialiasing ); + // Set properties to overlay + QPainter p(&px); + p.setPen(Qt::transparent); + p.setRenderHint(QPainter::Antialiasing); - if ( m_renderer.spriteExists(QStringLiteral("overlayBackground")) ) + // Render background canvas image + if ( kBounceGameWidget_renderer.spriteExists(QStringLiteral("overlayBackground")) ) { - QPixmap themeBackgound = m_renderer.spritePixmap(QStringLiteral("overlayBackground"),backgroundSize); - p.setCompositionMode( QPainter::CompositionMode_Source ); - p.drawPixmap( p.viewport(), themeBackgound ); - p.setCompositionMode( QPainter::CompositionMode_DestinationIn ); + // Render by file + QPixmap themeBackgound = kBounceGameWidget_renderer.spritePixmap(QStringLiteral("overlayBackground"),backgroundSize); + p.setCompositionMode(QPainter::CompositionMode_Source); + p.drawPixmap(p.viewport(), themeBackgound); + p.setCompositionMode(QPainter::CompositionMode_DestinationIn); p.fillRect(px.rect(), QColor( 0, 0, 0, 160 )); - p.setCompositionMode( QPainter::CompositionMode_SourceOver ); + p.setCompositionMode(QPainter::CompositionMode_SourceOver); } else { - p.setBrush( QBrush( QColor( 188, 202, 222, 155 ) ) ); - p.drawRoundRect( 0, 0, itemWidth, itemHeight, 25 ); + // Render by pure color + p.setBrush(QBrush( QColor(188, 202, 222, 155) )); + + // PS.: WARNING deprecated method (use drawRoundedRect) + p.drawRoundRect(0, 0, itemWidth, itemHeight, 25); } + // Initialize overlay text QString text; - switch( m_state ) + + switch(kBounceGameWidget_state) { + // Set text on "before first game" state case BeforeFirstGame: text = i18n( "Welcome to KBounce.\n Click to start a game" ); break; + + // Set text on "paused" state case Paused: text = i18n( "Paused\n Click to resume" ); break; + + // Set text on "between levels" state case BetweenLevels: text = i18n( "You have successfully cleared more than %1% of the board\n", MIN_FILL_PERCENT ) + - i18n( "%1 points: %2 points per remaining life\n", m_lives * POINTS_FOR_LIFE, POINTS_FOR_LIFE ) + - i18n( "%1 points: Bonus\n", m_bonus ) + - i18n( "%1 points: Total score for this level\n", m_bonus + m_lives * POINTS_FOR_LIFE ) + - i18n( "On to level %1. Remember you get %2 lives this time!", m_level, m_level + 1 ); + i18n( "%1 points: %2 points per remaining life\n", kBounceGameWidget_lives * POINTS_FOR_LIFE, POINTS_FOR_LIFE ) + + i18n( "%1 points: Bonus\n", kBounceGameWidget_bonus ) + + i18n( "%1 points: Total score for this level\n", kBounceGameWidget_bonus + kBounceGameWidget_lives * POINTS_FOR_LIFE ) + + i18n( "On to level %1. Remember you get %2 lives this time!", kBounceGameWidget_level, kBounceGameWidget_level + 1 ); break; + + // Set text on "game over" state case GameOver: text = i18n( "Game over.\n Click to start a game" ); break; + + // Set text on another state default: text = QString(); } + // Set text font properties QFont font; - font.setPointSize( 28 ); - p.setFont( font ); - int textWidth = p.boundingRect( p.viewport(), Qt::AlignCenter | Qt::AlignVCenter, text ).width(); + font.setPointSize(28); + p.setFont(font); + int textWidth = p.boundingRect(p.viewport(), Qt::AlignCenter | Qt::AlignVCenter, text).width(); int fontSize = 28; - while ( ( textWidth > itemWidth * 0.95 ) && fontSize > 1 ) + + // Adjust font size based on message size + while ( (textWidth > itemWidth * 0.95) && fontSize > 1) { fontSize--; - font.setPointSize( fontSize ); - p.setFont( font ); - textWidth = p.boundingRect( p.viewport(), Qt::AlignCenter | Qt::AlignVCenter, text ).width(); + font.setPointSize(fontSize); + p.setFont(font); + textWidth = p.boundingRect(p.viewport(), Qt::AlignCenter | Qt::AlignVCenter, text).width(); } - KColorScheme kcs = KColorScheme( QPalette::Normal, KColorScheme::Window ); - p.setPen( kcs.foreground(KColorScheme::NormalText).color()); - p.drawText( p.viewport(), Qt::AlignCenter | Qt::AlignVCenter, text ); + + // Set text color scheme + KColorScheme kcs = KColorScheme(QPalette::Normal, KColorScheme::Window); + p.setPen(kcs.foreground(KColorScheme::NormalText).color()); + p.drawText(p.viewport(), Qt::AlignCenter | Qt::AlignVCenter, text); p.end(); - m_overlay->setPixmap( px ); + // Apply overlay properties + kBounceGameWidget_overlay->setPixmap(px); + + // Get overlay position + QPointF pos( + (sceneRect().width() - itemWidth) / 2, + (sceneRect().height() - itemHeight) / 2 + ); - QPointF pos( ( sceneRect().width() - itemWidth) / 2, - ( sceneRect().height() - itemHeight) / 2 ); - m_overlay->setPos( pos ); + // Apply overlay position + kBounceGameWidget_overlay->setPos(pos); } +/** + * XmlGui "focus out" event + * @param *ev Event context + * @see gamewidget.h + */ void KBounceGameWidget::focusOutEvent(QFocusEvent *event) { + // Pause game if not on focus if (event->reason() == Qt::ActiveWindowFocusReason) - { - setPaused( true ); - } + setPaused(true); } +/** + * Update cursor image + * @see gamewidget.h + */ void KBounceGameWidget::updateCursor() { - if ( m_state == Running ) - setCursor( m_vertical ? Qt::SizeVerCursor : Qt::SizeHorCursor ); + if (kBounceGameWidget_state == Running) + setCursor(kBounceGameWidget_vertical ? Qt::SizeVerCursor : Qt::SizeHorCursor); else unsetCursor(); -} - - - +} \ No newline at end of file diff --git a/main.cpp b/main.cpp --- a/main.cpp +++ b/main.cpp @@ -16,8 +16,6 @@ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "mainwindow.h" - #include #include #include @@ -27,67 +25,106 @@ #include #include +#include "mainwindow.h" #include "debug.h" +/// Enable terminal logging Q_LOGGING_CATEGORY(KBOUNCE_LOG, "log_kbounce") +/// Set description on tab "about" static const char description[] = I18N_NOOP("KDE Bounce Ball Game"); + +/// Set copyleft on tab "about" static const char copyleft[] = I18N_NOOP("(c) 2000-2005, Stefan Schimanski\n(c) 2007, Tomasz Boczkowski"); +/** + * Main function + * + * Start the game + * + * @param argc Number or command line parameters + * @param **argv Command line parameters as a string array + * @return Final game status + */ int main(int argc, char **argv) { + // Create Qt application QApplication app(argc, argv); + Kdelibs4ConfigMigrator migrate(QStringLiteral("kbounce")); migrate.setConfigFiles(QStringList() << QStringLiteral("kbouncerc")); migrate.setUiFiles(QStringList() << QStringLiteral("kbounceui.rc")); migrate.migrate(); + + // Set application domain KLocalizedString::setApplicationDomain("kbounce"); + + // Set base informations on tab "about" KAboutData aboutData(QStringLiteral("kbounce"), i18n("KBounce"), QStringLiteral("0.11"), i18n(description), KAboutLicense::GPL, i18n(copyleft), QString(), QStringLiteral("http://games.kde.org/kbounce")); + // Add author on tab "about" aboutData.addAuthor(i18n("Stefan Schimanski"), i18n("Original author"), QStringLiteral("schimmi@kde.org")); + // Add author on tab "about" aboutData.addAuthor(i18n("Sandro Sigala"), i18n("Highscore"), QStringLiteral("ssigala@globalnet.it")); + // Add author on tab "about" aboutData.addAuthor(i18n("Benjamin Meyer"), i18n("Contributions"), QStringLiteral("ben+kbounce@meyerhome.net")); + // Add author on tab "about" aboutData.addAuthor(i18n("Tomasz Boczkowski"), i18n("Port to KDE4. Current maintainer"), QStringLiteral("tboczkowski@onet.pl")); + // Add credit on tab "about" aboutData.addCredit(i18n("Dmitry Suzdalev"), i18n("Port to QGraphicsView framework"), QStringLiteral("dimsuz@gmail.com")); + // Add credit on tab "about" aboutData.addCredit(i18n("Andreas Scherf"), i18n("Image Background and Fixes"), QStringLiteral("ascherfy@gmail.com")); + // Add credit on tab "about" + aboutData.addCredit(i18n("Pedro Henrique (Drim)"), + i18n("Code documentation"), + QStringLiteral("pedrohenriquedrim@gmail.com")); + + // Apply informations on tab "about" KAboutData::setApplicationData(aboutData); + + // Set crash handler KCrash::initialize(); + QCommandLineParser parser; aboutData.setupCommandLine(&parser); parser.process(app); aboutData.processCommandLine(&parser); + // Set window icon app.setWindowIcon(QIcon::fromTheme(QStringLiteral("kbounce"))); KDBusService service; + // Window management if (app.isSessionRestored()) RESTORE(KBounceMainWindow) else { - KBounceMainWindow *w = new KBounceMainWindow; - w->show(); + KBounceMainWindow *window = new KBounceMainWindow; + window->show(); } + + // Start Qt application return app.exec(); } diff --git a/mainwindow.h b/mainwindow.h --- a/mainwindow.h +++ b/mainwindow.h @@ -30,49 +30,168 @@ class QStatusBar; class KToggleAction; - +/** + * KbounceMainWindow class + * + * Inherits from KXmlGuiWindow + * @see mainwindow.cpp + * @see gamewidget.h + */ class KBounceMainWindow : public KXmlGuiWindow { Q_OBJECT + public: + /** + * Constructor to set window configurations + * @see mainwindow.cpp + */ KBounceMainWindow(); + + /** + * KbounceMainWindow destructor + * @see mainwindow.cpp + */ ~KBounceMainWindow(); protected slots: + + /** + * Event to start a new game + * @see mainwindow.cpp + */ void newGame(); + + /** + * Event to pause / restart the current game + * @see mainwindow.cpp + */ void pauseGame(); + + /** + * Event to close the game + * @see mainwindow.cpp + */ void closeGame(); + + /** + * Event to run the game over + * @see mainwindow.cpp + */ void gameOverNow(); + + /** + * Extra configurations + * @see mainwindow.cpp + */ void configureSettings(); + + /** + * Read user settings and apply them + * @see mainwindow.cpp + */ void readSettings(); + + /** + * ? + * PS.: Bug 184606 (solved) + * @see mainwindow.cpp + */ void settingsChanged(); - void setSounds( bool val ); + + /** + * Event to set game sounds + * @param isEnable flag to enable / disable game sound + * @see mainwindow.cpp + */ + void setSounds(bool isEnable); + + /** + * Bring up the standard kde high score dialog + * @see mainwindow.cpp + */ void showHighscore(); - void displayLevel( int level ); - void displayScore( int score ); - void displayFilled( int filled ); - void displayLives( int lives ); - void displayTime( int time ); - void gameStateChanged( KBounceGameWidget::State state ); + + /** + * Event to display game level + * @param level level to display + * @see mainwindow.cpp + */ + void displayLevel(int level); + + /** + * Event to display game score + * @param score score to display + * @see mainwindow.cpp + */ + void displayScore(int score); + + /** + * Event to display game filled percentage + * @param percentage to display + * @see mainwindow.cpp + */ + void displayFilled(int filled); + + /** + * Event to display game lives + * @param lives lives to display + * @see mainwindow.cpp + */ + void displayLives(int lives); + + /** + * Event to display game time + * @param time time to display + * @see mainwindow.cpp + */ + void displayTime(int time); + + /** + * Event to control state changes on the game + * @param state Current state + * @see mainwindow.cpp + */ + void gameStateChanged(KBounceGameWidget::State state); + protected: + + /** + * Create the user interface and their respective action events + * @see mainwindow.cpp + */ void initXMLUI(); + + /** + * Add current score to highscore + * @see mainwindow.cpp + */ void highscore(); + /** + * XmlGui "focus out" event + * @param *ev Event context + * @see mainwindow.cpp + */ void focusOutEvent( QFocusEvent * ) Q_DECL_OVERRIDE; - void focusInEvent ( QFocusEvent * ) Q_DECL_OVERRIDE; - - KBounceGameWidget* m_gameWidget; - QStatusBar* m_statusBar; + /** + * XmlGui "focus in" event + * @param *ev Event context + * @see mainwindow.cpp + */ + void focusInEvent ( QFocusEvent * ) Q_DECL_OVERRIDE; - KToggleAction *m_pauseAction, *m_backgroundShowAction, *m_soundAction; - QAction *m_newAction; + KToggleAction *kBounceMainWindow_pauseAction, *kBounceMainWindow_backgroundShowAction, *kBounceMainWindow_soundAction; + KBounceGameWidget* kBounceMainWindow_gameWidget; + QStatusBar* kBounceMainWindow_statusBar; + QAction *kBounceMainWindow_newAction; - QPointer levelLabel = new QLabel; - QPointer scoreLabel = new QLabel; - QPointer filledLabel = new QLabel; - QPointer livesLabel = new QLabel; - QPointer timeLabel = new QLabel; + QPointer kBounceMainWindow_levelLabel = new QLabel; + QPointer kBounceMainWindow_scoreLabel = new QLabel; + QPointer kBounceMainWindow_filledLabel = new QLabel; + QPointer kBounceMainWindow_livesLabel = new QLabel; + QPointer kBounceMainWindow_timeLabel = new QLabel; }; -#endif // KBOUNCE_MAINWINDOW_H +#endif \ No newline at end of file diff --git a/mainwindow.cpp b/mainwindow.cpp --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -16,13 +16,6 @@ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ - -#include "mainwindow.h" -#include "gamewidget.h" -#include "settings.h" -#include "backgroundselector.h" -#include "debug.h" - #include #include #include @@ -36,241 +29,375 @@ #include #include +#include "mainwindow.h" +#include "gamewidget.h" +#include "settings.h" +#include "backgroundselector.h" +#include "debug.h" + +/** + * KbounceMainWindow class + * + * Constructor to set window configurations + * @see mainwindow.h + * @see gamewidget.h + */ KBounceMainWindow::KBounceMainWindow() { //setComponentName(QStringLiteral("kbounce"), i18n("KBounce")); - m_statusBar = statusBar(); - - levelLabel->setText(i18n("Level: %1", QStringLiteral( "XX" ))); - scoreLabel->setText(i18n("Score: %1", QStringLiteral( "XXXXXX" ))); - filledLabel->setText(i18n( "Filled: %1%", QStringLiteral( "XX" ))); - livesLabel->setText(i18n( "Lives: %1", QStringLiteral( "XX" ))); - timeLabel->setText(i18n( "Time: %1", QStringLiteral( "XXX" ))); - - m_statusBar->insertPermanentWidget(0, levelLabel, 1); - m_statusBar->insertPermanentWidget(1, scoreLabel, 1); - m_statusBar->insertPermanentWidget(2, filledLabel, 1); - m_statusBar->insertPermanentWidget(3, livesLabel, 1); - m_statusBar->insertPermanentWidget(4, timeLabel, 1); - - m_gameWidget = new KBounceGameWidget( this ); - connect( m_gameWidget, SIGNAL(levelChanged(int)), this, SLOT(displayLevel(int)) ); - connect( m_gameWidget, &KBounceGameWidget::scoreChanged, this, &KBounceMainWindow::displayScore ); - connect( m_gameWidget, &KBounceGameWidget::livesChanged, this, &KBounceMainWindow::displayLives ); - connect( m_gameWidget, &KBounceGameWidget::filledChanged, this, &KBounceMainWindow::displayFilled ); - connect( m_gameWidget, &KBounceGameWidget::timeChanged, this, &KBounceMainWindow::displayTime ); - connect( m_gameWidget, &KBounceGameWidget::stateChanged, this, &KBounceMainWindow::gameStateChanged ); - //connect( m_gameWidget, SIGNAL(gameOver()), this, SLOT(gameOverNow()) ); - setCentralWidget( m_gameWidget ); - + + // Create widget bar bellow the main window + kBounceMainWindow_statusBar = statusBar(); + + // Set initial text on labels + kBounceMainWindow_levelLabel->setText(i18n("Level: %1", QStringLiteral( "XX" ))); + kBounceMainWindow_scoreLabel->setText(i18n("Score: %1", QStringLiteral( "XXXXXX" ))); + kBounceMainWindow_filledLabel->setText(i18n( "Filled: %1%", QStringLiteral( "XX" ))); + kBounceMainWindow_livesLabel->setText(i18n( "Lives: %1", QStringLiteral( "XX" ))); + kBounceMainWindow_timeLabel->setText(i18n( "Time: %1", QStringLiteral( "XXX" ))); + + // Attach labels on widget bar + kBounceMainWindow_statusBar->insertPermanentWidget(0, kBounceMainWindow_levelLabel, 1); + kBounceMainWindow_statusBar->insertPermanentWidget(1, kBounceMainWindow_scoreLabel, 1); + kBounceMainWindow_statusBar->insertPermanentWidget(2, kBounceMainWindow_filledLabel, 1); + kBounceMainWindow_statusBar->insertPermanentWidget(3, kBounceMainWindow_livesLabel, 1); + kBounceMainWindow_statusBar->insertPermanentWidget(4, kBounceMainWindow_timeLabel, 1); + + // Create game widget + kBounceMainWindow_gameWidget = new KBounceGameWidget( this ); + + // Connect events on game widget bar + connect( kBounceMainWindow_gameWidget, SIGNAL(levelChanged(int)), this, SLOT(displayLevel(int)) ); + connect( kBounceMainWindow_gameWidget, &KBounceGameWidget::scoreChanged, this, &KBounceMainWindow::displayScore ); + connect( kBounceMainWindow_gameWidget, &KBounceGameWidget::livesChanged, this, &KBounceMainWindow::displayLives ); + connect( kBounceMainWindow_gameWidget, &KBounceGameWidget::filledChanged, this, &KBounceMainWindow::displayFilled ); + connect( kBounceMainWindow_gameWidget, &KBounceGameWidget::timeChanged, this, &KBounceMainWindow::displayTime ); + connect( kBounceMainWindow_gameWidget, &KBounceGameWidget::stateChanged, this, &KBounceMainWindow::gameStateChanged ); + //connect( kBounceMainWindow_gameWidget, SIGNAL(gameOver()), this, SLOT(gameOverNow()) ); + + // Display game widget + setCentralWidget(kBounceMainWindow_gameWidget); + + // Start user interface from XML file initXMLUI(); setFocusPolicy(Qt::StrongFocus); setFocus(); + + // Enable game top bar setupGUI(); + // Read user settings readSettings(); } +/** + * KbounceMainWindow destructor + * @see mainwindow.h + */ KBounceMainWindow::~KBounceMainWindow() { } /** - * create the action events create the gui. + * Create the user interface and their respective action events + * @see mainwindow.h */ void KBounceMainWindow::initXMLUI() { - // Game - m_newAction = KStandardGameAction::gameNew(this, SLOT(newGame()), actionCollection()); + // New game UI and action + kBounceMainWindow_newAction = KStandardGameAction::gameNew(this, SLOT(newGame()), actionCollection()); + + // Close game UI and action KStandardGameAction::end(this, SLOT(closeGame()), actionCollection()); - m_pauseAction = KStandardGameAction::pause(this, SLOT(pauseGame()), actionCollection()); + + // Pause game UI and action + kBounceMainWindow_pauseAction = KStandardGameAction::pause(this, SLOT(pauseGame()), actionCollection()); + + // Highscore UI and action KStandardGameAction::highscores(this, SLOT(showHighscore()), actionCollection()); + + // Quit game UI and action KStandardGameAction::quit(this, SLOT(close()), actionCollection()); - // Difficulty + // Game Difficulty UI (from "Easy" to "Hard") Kg::difficulty()->addStandardLevelRange( - KgDifficultyLevel::Easy, KgDifficultyLevel::Hard - ); + KgDifficultyLevel::Easy, KgDifficultyLevel::Hard + ); + + // Enable game difficulty UI KgDifficultyGUI::init(this); - connect(Kg::difficulty(), SIGNAL(currentLevelChanged(const KgDifficultyLevel*)), m_gameWidget, SLOT(levelChanged())); - // Settings - KStandardAction::preferences( this, SLOT(configureSettings()), actionCollection() ); - m_soundAction = new KToggleAction( i18n("&Play Sounds"), this ); - actionCollection()->addAction( QStringLiteral( "toggle_sound" ), m_soundAction ); - connect( m_soundAction, &QAction::triggered, this, &KBounceMainWindow::setSounds ); -} + // Game Difficulty action + connect(Kg::difficulty(), SIGNAL(currentLevelChanged(const KgDifficultyLevel*)), kBounceMainWindow_gameWidget, SLOT(levelChanged())); + + // Game extra settings UI and action (PS.: BUG) + // TODO: Solve the bug that extra settings doesn't show + KStandardAction::preferences(this, SLOT(configureSettings()), actionCollection()); + // Game Sound toggle + kBounceMainWindow_soundAction = new KToggleAction( i18n("&Play Sounds"), this ); + + // Sound toggle UI + actionCollection()->addAction( QStringLiteral( "toggle_sound" ), kBounceMainWindow_soundAction ); + // Sound toggle action + connect( kBounceMainWindow_soundAction, &QAction::triggered, this, &KBounceMainWindow::setSounds ); +} +/** + * Event to start a new game + * @see mainwindow.h + */ void KBounceMainWindow::newGame() { // Check for running game closeGame(); - if ( m_gameWidget->state() == KBounceGameWidget::BeforeFirstGame || m_gameWidget->state() == KBounceGameWidget::GameOver ) - { - m_gameWidget->newGame(); - } + + // Start a new game + if (kBounceMainWindow_gameWidget->state() == KBounceGameWidget::BeforeFirstGame || kBounceMainWindow_gameWidget->state() == KBounceGameWidget::GameOver) + kBounceMainWindow_gameWidget->newGame(); } +/** + * Event to pause / restart the current game + * @see mainwindow.h + */ void KBounceMainWindow::pauseGame() { - if ( m_gameWidget->state() == KBounceGameWidget::Paused ) - { - m_gameWidget->setPaused( false ); - } - else - { - m_gameWidget->setPaused( true ); - } + bool isRunning = (kBounceMainWindow_gameWidget->state() != KBounceGameWidget::Paused); + kBounceMainWindow_gameWidget->setPaused(isRunning); } +/** + * Event to close the game + * @see mainwindow.h + */ void KBounceMainWindow::closeGame() { - if ( m_gameWidget->state() == KBounceGameWidget::BeforeFirstGame || m_gameWidget->state() == KBounceGameWidget::GameOver ) - { + // Before the game start or on game over + if (kBounceMainWindow_gameWidget->state() == KBounceGameWidget::BeforeFirstGame || kBounceMainWindow_gameWidget->state() == KBounceGameWidget::GameOver) return; - } - KBounceGameWidget::State old_state = m_gameWidget->state(); - if ( old_state == KBounceGameWidget::Running ) - m_gameWidget->setPaused( true ); - int ret = KMessageBox::questionYesNo( this, i18n( "Do you really want to close the running game?" ), QString(), KStandardGuiItem::yes(), KStandardGuiItem::cancel() ); - if ( ret == KMessageBox::Yes ) - { - m_gameWidget->closeGame(); - } - else if ( old_state == KBounceGameWidget::Running ) - { - m_gameWidget->setPaused( false ); - } + // Get current game state + KBounceGameWidget::State old_state = kBounceMainWindow_gameWidget->state(); + + if (old_state == KBounceGameWidget::Running) + kBounceMainWindow_gameWidget->setPaused(true); + + // User close game confirmation + int ret = KMessageBox::questionYesNo(this, i18n( "Do you really want to close the running game?" ), QString(), KStandardGuiItem::yes(), KStandardGuiItem::cancel()); + + if (ret == KMessageBox::Yes) + kBounceMainWindow_gameWidget->closeGame(); + else if (old_state == KBounceGameWidget::Running) + kBounceMainWindow_gameWidget->setPaused(false); } +/** + * Event to run the game over + * @see mainwindow.h + */ void KBounceMainWindow::gameOverNow() { - statusBar()->showMessage( i18n("Game over. Click to start a game") ); + // Set game over message + statusBar()->showMessage(i18n("Game over. Click to start a game")); + + // Run highcore rules highscore(); } /** - * Bring up the standard kde high score dialog. + * Bring up the standard kde high score dialog + * @see mainwindow.h */ void KBounceMainWindow::showHighscore() { - KScoreDialog ksdialog( KScoreDialog::Name | KScoreDialog::Score, this ); + KScoreDialog ksdialog(KScoreDialog::Name | KScoreDialog::Score, this ); ksdialog.initFromDifficulty(Kg::difficulty()); ksdialog.exec(); } +/** + * Add current score to highscore + * @see mainwindow.h + */ void KBounceMainWindow::highscore() { - if ( m_gameWidget->score() == 0 ) { + // "You don't have score if you don't beat a stage" + if (kBounceMainWindow_gameWidget->getScore() == 0) return; - } qCDebug(KBOUNCE_LOG); - KScoreDialog ksdialog( KScoreDialog::Name | KScoreDialog::Score | KScoreDialog::Level, this ); + + // Create score dialog + KScoreDialog ksdialog(KScoreDialog::Name | KScoreDialog::Score | KScoreDialog::Level, this); + + // Show score by difficulty (Ps.: BUG) + // TODO: Solve bug that score dialog don't shows "Medium difficulty" ksdialog.initFromDifficulty(Kg::difficulty()); + + // Create and populate score field KScoreDialog::FieldInfo info; - info[KScoreDialog::Score].setNum( m_gameWidget->score() ); - info[KScoreDialog::Level].setNum( m_gameWidget->level() ); - if ( ksdialog.addScore( info ) ) + info[KScoreDialog::Score].setNum(kBounceMainWindow_gameWidget->getScore()); + info[KScoreDialog::Level].setNum(kBounceMainWindow_gameWidget->getLevel()); + + // Add score and show dialog + if (ksdialog.addScore(info)) ksdialog.exec(); } +/** + * Extra configurations + * @see mainwindow.h + */ void KBounceMainWindow::configureSettings() { - if ( KConfigDialog::showDialog( QStringLiteral("settings") ) ) return; + // BUG: Method never called + + if (KConfigDialog::showDialog( QStringLiteral("settings") )) + return; KConfigDialog* dialog = new KConfigDialog( this, QStringLiteral("settings"), KBounceSettings::self()); - dialog->addPage( new KgThemeSelector(m_gameWidget->renderer()->themeProvider(), 0, dialog), i18n( "Theme" ), QStringLiteral("games-config-theme") ); + dialog->addPage( new KgThemeSelector(kBounceMainWindow_gameWidget->renderer()->themeProvider(), 0, dialog), i18n( "Theme" ), QStringLiteral("games-config-theme") ); dialog->addPage( new BackgroundSelector(dialog,KBounceSettings::self() ),i18n("Background"),QStringLiteral("games-config-background")); dialog->show(); connect( dialog, &KConfigDialog::settingsChanged, this, &KBounceMainWindow::settingsChanged ); } +/** + * Read user settings and apply them + * @see mainwindow.h + */ void KBounceMainWindow::readSettings() { - m_soundAction->setChecked( KBounceSettings::playSounds() ); - m_gameWidget->settingsChanged(); + kBounceMainWindow_soundAction->setChecked(KBounceSettings::playSounds()); + kBounceMainWindow_gameWidget->settingsChanged(); } +/** + * ? + * PS.: Bug 184606 (solved) + * @see mainwindow.h + */ void KBounceMainWindow::settingsChanged() { - m_gameWidget->settingsChanged(); - KBounceSettings::self()->save(); // Bug 184606 + kBounceMainWindow_gameWidget->settingsChanged(); + KBounceSettings::self()->save(); } -void KBounceMainWindow::setSounds( bool val ) +/** + * Event to set game sounds + * @param isEnable level to display + * @see mainwindow.h + */ +void KBounceMainWindow::setSounds(bool isEnable) { - KBounceSettings::setPlaySounds( val ); + KBounceSettings::setPlaySounds(isEnable); settingsChanged(); } -void KBounceMainWindow::displayLevel( int level ) +/** + * Event to display game level + * @param level level to display + * @see mainwindow.h + */ +void KBounceMainWindow::displayLevel(int level) { - levelLabel->setText(i18n("Level: %1", level)); + kBounceMainWindow_levelLabel->setText(i18n("Level: %1", level)); } -void KBounceMainWindow::displayScore( int score ) +/** + * Event to display game score + * @param score score to display + * @see mainwindow.h + */ +void KBounceMainWindow::displayScore(int score) { - scoreLabel->setText(i18n("Score: %1", score)); + kBounceMainWindow_scoreLabel->setText(i18n("Score: %1", score)); } -void KBounceMainWindow::displayFilled( int filled ) +/** + * Event to display game filled percentage + * @param percentage to display + * @see mainwindow.h + */ +void KBounceMainWindow::displayFilled(int filled) { - filledLabel->setText(i18n("Filled: %1%", filled)); + kBounceMainWindow_filledLabel->setText(i18n("Filled: %1%", filled)); } -void KBounceMainWindow::displayLives( int lives ) +/** + * Event to display game lives + * @param lives lives to display + * @see mainwindow.h + */ +void KBounceMainWindow::displayLives(int lives) { - livesLabel->setText(i18n("Lives: %1", lives - 1)); + kBounceMainWindow_livesLabel->setText(i18n("Lives: %1", lives - 1)); } -void KBounceMainWindow::displayTime( int time ) +/** + * Event to display game time + * @param time time to display + * @see mainwindow.h + */ +void KBounceMainWindow::displayTime(int time) { - timeLabel->setText(i18n("Time: %1", time)); + kBounceMainWindow_timeLabel->setText(i18n("Time: %1", time)); } -void KBounceMainWindow::gameStateChanged( KBounceGameWidget::State state ) +/** + * Event to control state changes on the game + * @param state Current state + * @see mainwindow.h + */ +void KBounceMainWindow::gameStateChanged(KBounceGameWidget::State state) { - switch ( state ) + switch (state) { case KBounceGameWidget::BeforeFirstGame : - break; case KBounceGameWidget::BetweenLevels : - break; case KBounceGameWidget::Suspended : break; + case KBounceGameWidget::Paused : - m_pauseAction->setChecked( true ); - m_statusBar->clearMessage(); + kBounceMainWindow_pauseAction->setChecked( true ); + kBounceMainWindow_statusBar->clearMessage(); break; + case KBounceGameWidget::Running : - m_pauseAction->setChecked( false ); - m_statusBar->clearMessage(); + kBounceMainWindow_pauseAction->setChecked( false ); + kBounceMainWindow_statusBar->clearMessage(); break; + case KBounceGameWidget::GameOver : - statusBar()->showMessage( i18n("Game over. Click to start a game") ); + statusBar()->showMessage(i18n("Game over. Click to start a game")); highscore(); break; } } -void KBounceMainWindow::focusOutEvent( QFocusEvent *ev ) +/** + * XmlGui "focus out" event + * @param *ev Event context + * @see mainwindow.h + */ +void KBounceMainWindow::focusOutEvent(QFocusEvent *ev) { - if ( m_gameWidget->state() == KBounceGameWidget::Running && - focusWidget() != m_gameWidget ) - { - m_gameWidget->setPaused( true ); - } + if (kBounceMainWindow_gameWidget->state() == KBounceGameWidget::Running && focusWidget() != kBounceMainWindow_gameWidget ) + kBounceMainWindow_gameWidget->setPaused(true); - KXmlGuiWindow::focusOutEvent( ev ); + KXmlGuiWindow::focusOutEvent(ev); } -void KBounceMainWindow::focusInEvent ( QFocusEvent *ev ) +/** + * XmlGui "focus in" event + * @param *ev Event context + * @see mainwindow.h + */ +void KBounceMainWindow::focusInEvent (QFocusEvent *ev) { - //m_board->setSuspended( true ); + //kBounceMainWindow_board->setSuspended( true ); KXmlGuiWindow::focusInEvent( ev ); -} +} \ No newline at end of file diff --git a/renderer.h b/renderer.h --- a/renderer.h +++ b/renderer.h @@ -33,37 +33,52 @@ /** * Class for rendering elements of game SVG to QPixmap */ - class KBounceRenderer : public KGameRenderer { public: + /** * Constructor. * @param fileName path to SVG containing game graphics */ explicit KBounceRenderer(); + /** * Destructor. */ ~KBounceRenderer(); + /** * Sets Background size and invalidates background cache + * @param size new size + * @see render.cpp */ void setBackgroundSize( const QSize& size); + /** * Renders background to QPixmap of size set by setBachgroundSize * Background pixmap is cached (setBackgroundSize() invalidates the cache) + * @see render.cpp */ QPixmap renderBackground(); + /** - * Set s the path were custom background pictures are located. + * Sets the path were custom background pictures are located. + * @see render.cpp */ void setCustomBackgroundPath(const QString &path); + /** * Returns a random pixmap from the custom background path. * If no picture is located in this path the pixmap is null. + * @see render.cpp */ QPixmap getRandomBackgroundPixmap(const QString& path); + + /** + * Load a new background image + * @see render.cpp + */ bool loadNewBackgroundPixmap(); private: diff --git a/renderer.cpp b/renderer.cpp --- a/renderer.cpp +++ b/renderer.cpp @@ -39,37 +39,52 @@ return prov; } +/** + * Constructor. + * @param fileName path to SVG containing game graphics + */ KBounceRenderer::KBounceRenderer() : KGameRenderer(provider()), m_backgroundSize( QSize( 0, 0 ) ), m_useRandomBackgrounds(false) { } +/** + * Destructor. + */ KBounceRenderer::~KBounceRenderer() { } +/** + * Set s the path were custom background pictures are located. + * @see render.h + */ void KBounceRenderer::setCustomBackgroundPath(const QString& path) { m_useRandomBackgrounds = !path.isEmpty(); m_customBackgroundPath = path; m_cachedBackground = QPixmap(); } +/** + * Sets Background size and invalidates background cache + * @see render.h + */ void KBounceRenderer::setBackgroundSize( const QSize& size ) { - if (size != m_backgroundSize ) + if (size != m_backgroundSize) { m_backgroundSize = size; - if ( m_useRandomBackgrounds && !m_cachedBackground.isNull() ) - { + if (m_useRandomBackgrounds && !m_cachedBackground.isNull()) m_cachedBackground = m_randomBackground.scaled(m_backgroundSize,Qt::IgnoreAspectRatio); - } else - { - m_cachedBackground = QPixmap(); - } + m_cachedBackground = QPixmap(); } } +/** + * Load a new background image + * @see render.h + */ bool KBounceRenderer::loadNewBackgroundPixmap() { bool backgroundFound = false; @@ -85,24 +100,32 @@ return backgroundFound; } - +/** + * Renders background to QPixmap of size set by setBachgroundSize + * Background pixmap is cached (setBackgroundSize() invalidates the cache) + * @see render.h + */ QPixmap KBounceRenderer::renderBackground() { if (m_cachedBackground.isNull() && !m_backgroundSize.isNull()) { //This is a dirty fix to the qt's m_svgRenderer.render() method that //leaves an garbage-filled border of a pixmap qCDebug(KBOUNCE_LOG) << "Rendering the background. Size:" << m_backgroundSize; if ( m_useRandomBackgrounds && loadNewBackgroundPixmap() ) - { return m_cachedBackground; - } + // If no valid backgound pixmap found use the original from theme ... m_cachedBackground = spritePixmap( QStringLiteral("background"), m_backgroundSize ); } return m_cachedBackground; } +/** + * Returns a random pixmap from the custom background path. + * If no picture is located in this path the pixmap is null. + * @see render.h + */ QPixmap KBounceRenderer::getRandomBackgroundPixmap(const QString& path) { // list directory @@ -118,19 +141,16 @@ // return random pixmap uint pos = KRandom::random() % dir.count(); if ( pos < dir.count() ) - { filename = dir.absoluteFilePath( dir[pos] ); - } if (!filename.isEmpty() && QFile(filename).exists()) - { return QPixmap(filename); - } - else return QPixmap(); - } - else if ( dir.count() == 1 ) - { - return QPixmap( dir.absoluteFilePath(dir[0]) ); + else + return QPixmap(); } - else return QPixmap(); + else + if ( dir.count() == 1 ) + return QPixmap( dir.absoluteFilePath(dir[0]) ); + else + return QPixmap(); } diff --git a/wall.h b/wall.h --- a/wall.h +++ b/wall.h @@ -51,73 +51,93 @@ * in the same time */ KBounceWall( Direction dir, KBounceRenderer* renderer, KBounceBoard* board ); + + /** + * KBounceWall destructor + * @see wall.cpp + */ ~KBounceWall(); /** * Changes object's state when collisions have been detected * Called once per frame before advance() and update() + * @see wall.cpp */ void collide( KBounceCollision collision ); + /** * Performs various movement and state calculations non-related * to collision responses. Also updates m_boundingRect and * m_nextBoundingRect. This method is called once per frame * after collide() and before update() + * @see wall.cpp */ void goForward(); + /** * Updates object's pixmap and position on screen * Called once per frame after update() + * @see wall.cpp */ void update(); /** * Starts building wall beginning from tile specified by x and y * The direction has been specified in constructor + * @see wall.cpp */ - void build( int x, int y ); + void build(int x, int y); + /** * Returns the bounding rect that is expected for wall to * have in next frame. Collision in KBounceBoard are based on * the result of this method + * @see wall.cpp */ QRectF nextBoundingRect() const; /** * Changes on-screen dimensions of the wall. * Calculations are based on tile size, that is the on-screen * size of board's tile + * @see wall.cpp */ void resize( const QSize& tileSize ); /** * Set the wall velocity for wall filling speed. + * @param velocity new wall velocity + * @see wall.cpp */ void setWallVelocity(qreal velocity); /** * Load all sprites for top, down, left and right walls as well as for * the vertical and horizontal semi transparent bars drawn before a wall is * built. + * @see wall.cpp */ void static loadSprites(); signals: void finished( int left, int top, int right, int bottom ); void died(); private: + /** * Returns true if rect2 intersects the edge at the end of wall * e.g for wall extending in direction Up this will be the upper * edge. */ bool safeEdgeHit( const QRectF& rect2 ) const; + /** * Helper function replacing emiting long finished signal * It also hides the wall and plays corresponding sound * If ¶m shorten is true the wall will be one unit in * direction ¶m dir shorter than normal + * @see wall.cpp */ void finish( bool shorten = false, Direction dir = Up); diff --git a/wall.cpp b/wall.cpp --- a/wall.cpp +++ b/wall.cpp @@ -16,110 +16,144 @@ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "wall.h" - -#include - - #include #include #include "board.h" #include "renderer.h" #include "settings.h" +#include "wall.h" + +#include QSize KBounceWall::s_tileSize; KBounceRenderer * KBounceWall::m_renderer = NULL; KBounceWall::Sprites * KBounceWall::s_sprites = NULL; - -KBounceWall::KBounceWall( Direction dir, KBounceRenderer* renderer, KBounceBoard* board ) +/** + * KBounceWall class + * + * Constructor to set game wall configurations + * @param dir wall direction + * @param renderer object renderer + * @param board game board + * @see wall.h + */ +KBounceWall::KBounceWall(Direction dir, KBounceRenderer* renderer, KBounceBoard* board) : KGameRenderedItem( renderer,QLatin1String(""),board ) - , m_board( board ) - , m_dir( dir ) - , m_soundWallstart( QStandardPaths::locate( QStandardPaths::AppDataLocation, QStringLiteral("sounds/wallstart.wav") ) ) - , m_soundReflect( QStandardPaths::locate( QStandardPaths::AppDataLocation, QStringLiteral("sounds/reflect.wav") ) ) + , m_board( board ) // Set game board + , m_dir( dir ) // Set game direction + , m_soundWallstart( QStandardPaths::locate( QStandardPaths::AppDataLocation, QStringLiteral("sounds/wallstart.wav") )) // Set wall start sound asset + , m_soundReflect( QStandardPaths::locate( QStandardPaths::AppDataLocation, QStringLiteral("sounds/reflect.wav") )) // Set wall reflect sound asset { // The wall velocity would initialised on every new level. m_wallVelocity = 0.0; - if (!s_sprites) { + // Set sprite + if (!s_sprites) s_sprites = new Sprites; - } - if (!m_renderer) { + // Set renderer + if (!m_renderer) m_renderer = renderer; - } } +/** + * KBounceWall destructor + * @see wall.h + */ KBounceWall::~KBounceWall() { } -void KBounceWall::collide( KBounceCollision collision ) +/** + * Changes object's state when collisions have been detected + * Called once per frame before advance() and update() + * @param collision hitters list + * @see wall.h + */ +void KBounceWall::collide(KBounceCollision collision) { - if ( !isVisible() ) + if (!isVisible()) return; - foreach( const KBounceHit &hit, collision ) { + foreach(const KBounceHit &hit, collision) { switch (hit.type) { case ALL: break; + case TILE: finish(); break; + case BALL: if (safeEdgeHit(hit.boundingRect)) { KBounceVector normal = hit.normal; - if (qAbs(normal.x) < qAbs(normal.y)) { // vertical - if (m_dir == Up || m_dir == Down) { - finish( true, m_dir ); - } + + if (qAbs(normal.x) < qAbs(normal.y)) { + // vertical + if (m_dir == Up || m_dir == Down) + finish(true, m_dir); } - else if (m_dir == Left || m_dir == Right) { - finish( true, m_dir ); - } - } else { + else // horizontal + if (m_dir == Left || m_dir == Right) + finish(true, m_dir); + } + else + { emit died(); hide(); } break; + case WALL: - if (safeEdgeHit(hit.boundingRect)) { + if (safeEdgeHit(hit.boundingRect)) finish(); - } break; } } } - +/** + * Performs various movement and state calculations non-related + * to collision responses. Also updates m_boundingRect and + * m_nextBoundingRect. This method is called once per frame + * after collide() and before update() + * @see wall.h + */ void KBounceWall::goForward() { - if (!isVisible()) { + if (!isVisible()) return; - } - switch( m_dir ) { + switch(m_dir) { case Up: m_boundingRect.setTop( m_boundingRect.top() - m_wallVelocity ); m_nextBoundingRect.setTop( m_boundingRect.top() - m_wallVelocity ); break; + case Left: m_boundingRect.setLeft( m_boundingRect.left() - m_wallVelocity ); m_nextBoundingRect.setLeft( m_boundingRect.left() - m_wallVelocity ); break; + case Down: m_boundingRect.setBottom( m_boundingRect.bottom() + m_wallVelocity ); m_nextBoundingRect.setBottom( m_boundingRect.bottom() + m_wallVelocity ); break; + case Right: m_boundingRect.setRight( m_boundingRect.right() + m_wallVelocity ); m_nextBoundingRect.setRight( m_boundingRect.right() + m_wallVelocity ); break; } } +/** + * Updates object's pixmap and position on screen + * Called once per frame after update() + * @see wall.h + */ void KBounceWall::update() { if (!isVisible()) @@ -135,53 +169,62 @@ int tileHeight = s_tileSize.height(); QSize pixSize; - if (m_dir == Left || m_dir == Right) { + if (m_dir == Left || m_dir == Right) pixSize = QSize(boundingRectWidth + 64 - (boundingRectWidth%64), boundingRectHeight); - } else { + else pixSize = QSize(boundingRectWidth, boundingRectHeight + 64 - (boundingRectHeight%64)); - } - + QPixmap px; - if (pixmap().width() < pixSize.width() || pixmap().height() < pixSize.height()) { + + if (pixmap().width() < pixSize.width() || pixmap().height() < pixSize.height()) px = QPixmap(pixSize); - } else { + else px = pixmap(); // already ARGB - } + px.fill(Qt::transparent); QPainter p(&px); QPointF offset = m_board->mapPosition(m_boundingRect.topLeft()); - switch ( m_dir ) { - case Up: { - const int split = qMin(tileHeight, boundingRectHeight); - p.drawPixmap(0, 0, s_sprites->wallEndUp, 0, 0, tileWidth, split); - p.drawTiledPixmap(0, split, tileWidth, boundingRectHeight - split, s_sprites->wallV, 0, offset.y()); - break; - } - case Right: { - const int split = qMin(tileWidth, boundingRectWidth); - p.drawPixmap(boundingRectWidth - tileWidth, 0, split, tileHeight, s_sprites->wallEndRight); - p.drawTiledPixmap(0, 0, boundingRectWidth - split, tileHeight, s_sprites->wallH); - break; - } - case Down: { - const int split = qMin(tileHeight, boundingRectHeight); - p.drawPixmap(0, boundingRectHeight - tileHeight, tileWidth, split, s_sprites->wallEndDown); - p.drawTiledPixmap(0, 0, tileWidth, boundingRectHeight - split, s_sprites->wallV); - break; - } + int split; + switch (m_dir) { + case Up: + split = qMin(tileHeight, boundingRectHeight); + p.drawPixmap(0, 0, s_sprites->wallEndUp, 0, 0, tileWidth, split); + p.drawTiledPixmap(0, split, tileWidth, boundingRectHeight - split, s_sprites->wallV, 0, offset.y()); + break; + + case Right: + split = qMin(tileWidth, boundingRectWidth); + p.drawPixmap(boundingRectWidth - tileWidth, 0, split, tileHeight, s_sprites->wallEndRight); + p.drawTiledPixmap(0, 0, boundingRectWidth - split, tileHeight, s_sprites->wallH); + break; + + case Down: + split = qMin(tileHeight, boundingRectHeight); + p.drawPixmap(0, boundingRectHeight - tileHeight, tileWidth, split, s_sprites->wallEndDown); + p.drawTiledPixmap(0, 0, tileWidth, boundingRectHeight - split, s_sprites->wallV); + break; + case Left: - const int split = qMin(boundingRectWidth, tileWidth); - p.drawPixmap(0, 0, split, tileHeight, s_sprites->wallEndLeft); - p.drawTiledPixmap(split, 0, boundingRectWidth - split, tileHeight, s_sprites->wallH, offset.x()); + split = qMin(boundingRectWidth, tileWidth); + p.drawPixmap(0, 0, split, tileHeight, s_sprites->wallEndLeft); + p.drawTiledPixmap(split, 0, boundingRectWidth - split, tileHeight, s_sprites->wallH, offset.x()); + break; } + setPos(offset); p.end(); setPixmap(px); } +/** + * Load all sprites for top, down, left and right walls as well as for + * the vertical and horizontal semi transparent bars drawn before a wall is + * built. + * @see wall.h + */ void KBounceWall::loadSprites() { s_sprites->wallEndLeft = m_renderer->spritePixmap(QStringLiteral("wallEndLeft"), s_tileSize); s_sprites->wallEndUp = m_renderer->spritePixmap(QStringLiteral("wallEndUp"), s_tileSize); @@ -192,42 +235,54 @@ s_sprites->wallV = m_renderer->spritePixmap(QStringLiteral("wallV"), QSize(s_tileSize.width(), 18*s_tileSize.height())); } + +/** + * Changes on-screen dimensions of the wall. + * Calculations are based on tile size, that is the on-screen + * size of board's tile + * @see wall.h + */ void KBounceWall::resize( const QSize& tileSize ) { - if ( tileSize != s_tileSize ) { + if (tileSize != s_tileSize) + { s_tileSize = tileSize; loadSprites(); update(); } } -void KBounceWall::build( int x, int y ) +/** + * Starts building wall beginning from tile specified by x and y + * The direction has been specified in constructor + * @see wall.h + */ +void KBounceWall::build(int x, int y) { if (isVisible()) return; if ( m_dir == Up || m_dir == Down ) { - m_boundingRect.setTop( y ); + m_boundingRect.setTop(y); - if (m_dir == Down) { + if (m_dir == Down) m_boundingRect.setBottom(y + 1); - } else { - m_boundingRect.setBottom( y ); - } + else + m_boundingRect.setBottom(y); - m_boundingRect.setLeft( x ); - m_boundingRect.setRight( x + 1 ); + m_boundingRect.setLeft(x); + m_boundingRect.setRight(x + 1); } - else if ( m_dir == Left || m_dir == Right ) { - m_boundingRect.setTop( y ); - m_boundingRect.setBottom( y + 1 ); - m_boundingRect.setLeft( x ); + else if ( m_dir == Left || m_dir == Right ) + { + m_boundingRect.setTop(y); + m_boundingRect.setBottom(y + 1); + m_boundingRect.setLeft(x); - if (m_dir == Right) { + if (m_dir == Right) m_boundingRect.setRight(x + 1); - } else { - m_boundingRect.setRight( x ); - } + else + m_boundingRect.setRight(x); } @@ -242,34 +297,50 @@ m_soundWallstart.start(); } +/** + * Returns the bounding rect that is expected for wall to + * have in next frame. Collision in KBounceBoard are based on + * the result of this method + * @see wall.h + */ QRectF KBounceWall::nextBoundingRect() const { return m_nextBoundingRect; } +/** + * Returns true if rect2 intersects the edge at the end of wall + * e.g for wall extending in direction Up this will be the upper + * edge. + * @see wall.h + */ bool KBounceWall::safeEdgeHit( const QRectF& rect2 ) const { bool safeEdgeHit = false; QPointF p1, p2, p3; - switch ( m_dir ) + switch (m_dir) { case Up: p1 = m_nextBoundingRect.topLeft(); p2 = m_nextBoundingRect.topRight(); break; + case Right: p1 = m_nextBoundingRect.topRight(); p2 = m_nextBoundingRect.bottomRight(); break; + case Down: p1 = m_nextBoundingRect.bottomRight(); p2 = m_nextBoundingRect.bottomLeft(); break; + case Left: p1 = m_nextBoundingRect.bottomLeft(); p2 = m_nextBoundingRect.topLeft(); break; + default: Q_ASSERT(false); break; @@ -287,30 +358,41 @@ return safeEdgeHit; } -void KBounceWall::finish( bool shorten, Direction dir ) +/** + * Helper function replacing emiting long finished signal + * It also hides the wall and plays corresponding sound + * If ¶m shorten is true the wall will be one unit in + * direction ¶m dir shorter than normal + * @see wall.h + */ +void KBounceWall::finish(bool shorten, Direction dir) { int left = static_cast( m_boundingRect.left() ); int top = static_cast( m_boundingRect.top() ); int right = static_cast( m_boundingRect.right() ); int bottom = static_cast( m_boundingRect.bottom() ); - if ( shorten ) { - switch ( dir ) + if (shorten) + switch (dir) { case Left: left++; break; case Up: top++; break; case Right: right--; break; case Down: bottom--; break; } - } emit finished( left, top, right, bottom ); hide(); if (KBounceSettings::playSounds()) m_soundReflect.start(); } +/** + * Set the wall velocity for wall filling speed. + * @param velocity new wall velocity + * @see wall.h + */ void KBounceWall::setWallVelocity(qreal velocity) { m_wallVelocity = velocity;