C++/Qt/QFrame

Материал из C\C++ эксперт
Перейти к: навигация, поиск

Tetrix game

<source lang="cpp"> /****************************************************************************

    • Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    • All rights reserved.
    • Contact: Nokia Corporation (qt-info@nokia.com)
    • This file is part of the examples of the Qt Toolkit.
    • $QT_BEGIN_LICENSE:LGPL$
    • Commercial Usage
    • Licensees holding valid Qt Commercial licenses may use this file in
    • accordance with the Qt Commercial License Agreement provided with the
    • Software or, alternatively, in accordance with the terms contained in
    • a written agreement between you and Nokia.
    • GNU Lesser General Public License Usage
    • Alternatively, this file may be used under the terms of the GNU Lesser
    • General Public License version 2.1 as published by the Free Software
    • Foundation and appearing in the file LICENSE.LGPL included in the
    • packaging of this file. Please review the following information to
    • ensure the GNU Lesser General Public License version 2.1 requirements
    • will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    • In addition, as a special exception, Nokia gives you certain additional
    • rights. These rights are described in the Nokia Qt LGPL Exception
    • version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
    • GNU General Public License Usage
    • Alternatively, this file may be used under the terms of the GNU
    • General Public License version 3.0 as published by the Free Software
    • Foundation and appearing in the file LICENSE.GPL included in the
    • packaging of this file. Please review the following information to
    • ensure the GNU General Public License version 3.0 requirements will be
    • met: http://www.gnu.org/copyleft/gpl.html.
    • If you have questions regarding the use of this file, please contact
    • Nokia at qt-info@nokia.com.
    • $QT_END_LICENSE$
                                                                                                                                                        • /
  1. ifndef TETRIXPIECE_H
  2. define TETRIXPIECE_H

enum TetrixShape { NoShape, ZShape, SShape, LineShape, TShape, SquareShape,

                  LShape, MirroredLShape };

class TetrixPiece { public:

   TetrixPiece() { setShape(NoShape); }
   void setRandomShape();
   void setShape(TetrixShape shape);
   TetrixShape shape() const { return pieceShape; }
   int x(int index) const { return coords[index][0]; }
   int y(int index) const { return coords[index][1]; }
   int minX() const;
   int maxX() const;
   int minY() const;
   int maxY() const;
   TetrixPiece rotatedLeft() const;
   TetrixPiece rotatedRight() const;

private:

   void setX(int index, int x) { coords[index][0] = x; }
   void setY(int index, int y) { coords[index][1] = y; }
   TetrixShape pieceShape;
   int coords[4][2];

};

  1. endif


  1. include <QtCore>
  2. include <stdlib.h>
  3. include "tetrixpiece.h"

void TetrixPiece::setRandomShape() {

   setShape(TetrixShape(qrand() % 7 + 1));

}

void TetrixPiece::setShape(TetrixShape shape) {

   static const int coordsTable[8][4][2] = {
       { { 0, 0 },   { 0, 0 },   { 0, 0 },   { 0, 0 } },
       { { 0, -1 },  { 0, 0 },   { -1, 0 },  { -1, 1 } },
       { { 0, -1 },  { 0, 0 },   { 1, 0 },   { 1, 1 } },
       { { 0, -1 },  { 0, 0 },   { 0, 1 },   { 0, 2 } },
       { { -1, 0 },  { 0, 0 },   { 1, 0 },   { 0, 1 } },
       { { 0, 0 },   { 1, 0 },   { 0, 1 },   { 1, 1 } },
       { { -1, -1 }, { 0, -1 },  { 0, 0 },   { 0, 1 } },
       { { 1, -1 },  { 0, -1 },  { 0, 0 },   { 0, 1 } }
   };
   for (int i = 0; i < 4 ; i++) {
       for (int j = 0; j < 2; ++j)
           coords[i][j] = coordsTable[shape][i][j];
   }
   pieceShape = shape;

}

int TetrixPiece::minX() const {

   int min = coords[0][0];
   for (int i = 1; i < 4; ++i)
       min = qMin(min, coords[i][0]);
   return min;

} int TetrixPiece::maxX() const

{

   int max = coords[0][0];
   for (int i = 1; i < 4; ++i)
       max = qMax(max, coords[i][0]);
   return max;

}

int TetrixPiece::minY() const {

   int min = coords[0][1];
   for (int i = 1; i < 4; ++i)
       min = qMin(min, coords[i][1]);
   return min;

} int TetrixPiece::maxY() const

{

   int max = coords[0][1];
   for (int i = 1; i < 4; ++i)
       max = qMax(max, coords[i][1]);
   return max;

}

TetrixPiece TetrixPiece::rotatedLeft() const {

   if (pieceShape == SquareShape)
       return *this;
   TetrixPiece result;
   result.pieceShape = pieceShape;
   for (int i = 0; i < 4; ++i) {
       result.setX(i, y(i));
       result.setY(i, -x(i));
   }
   return result;

}

TetrixPiece TetrixPiece::rotatedRight() const {

   if (pieceShape == SquareShape)
       return *this;
   TetrixPiece result;
   result.pieceShape = pieceShape;
   for (int i = 0; i < 4; ++i) {
       result.setX(i, -y(i));
       result.setY(i, x(i));
   }
   return result;

}


  1. ifndef TETRIXBOARD_H
  2. define TETRIXBOARD_H
  3. include <QBasicTimer>
  4. include <QFrame>
  5. include <QPointer>
  6. include "tetrixpiece.h"

QT_BEGIN_NAMESPACE class QLabel; QT_END_NAMESPACE

class TetrixBoard : public QFrame {

   Q_OBJECT

public:

   TetrixBoard(QWidget *parent = 0);
   void setNextPieceLabel(QLabel *label);
   QSize sizeHint() const;
   QSize minimumSizeHint() const;

public slots:

   void start();
   void pause();

signals:

   void scoreChanged(int score);
   void levelChanged(int level);
   void linesRemovedChanged(int numLines);

protected:

   void paintEvent(QPaintEvent *event);
   void keyPressEvent(QKeyEvent *event);
   void timerEvent(QTimerEvent *event);

private:

   enum { BoardWidth = 10, BoardHeight = 22 };
   TetrixShape &shapeAt(int x, int y) { return board[(y * BoardWidth) + x]; }
   int timeoutTime() { return 1000 / (1 + level); }
   int squareWidth() { return contentsRect().width() / BoardWidth; }
   int squareHeight() { return contentsRect().height() / BoardHeight; }
   void clearBoard();
   void dropDown();
   void oneLineDown();
   void pieceDropped(int dropHeight);
   void removeFullLines();
   void newPiece();
   void showNextPiece();
   bool tryMove(const TetrixPiece &newPiece, int newX, int newY);
   void drawSquare(QPainter &painter, int x, int y, TetrixShape shape);
   QBasicTimer timer;
   QPointer<QLabel> nextPieceLabel;
   bool isStarted;
   bool isPaused;
   bool isWaitingAfterLine;
   TetrixPiece curPiece;
   TetrixPiece nextPiece;
   int curX;
   int curY;
   int numLinesRemoved;
   int numPiecesDropped;
   int score;
   int level;
   TetrixShape board[BoardWidth * BoardHeight];

};

  1. endif


  1. include <QtGui>
  2. include "tetrixboard.h"

TetrixBoard::TetrixBoard(QWidget *parent)

   : QFrame(parent)

{

   setFrameStyle(QFrame::Panel | QFrame::Sunken);
   setFocusPolicy(Qt::StrongFocus);
   isStarted = false;
   isPaused = false;
   clearBoard();
   nextPiece.setRandomShape();

}

void TetrixBoard::setNextPieceLabel(QLabel *label) {

   nextPieceLabel = label;

}

QSize TetrixBoard::sizeHint() const {

   return QSize(BoardWidth * 15 + frameWidth() * 2,
                BoardHeight * 15 + frameWidth() * 2);

} QSize TetrixBoard::minimumSizeHint() const

{

   return QSize(BoardWidth * 5 + frameWidth() * 2,
                BoardHeight * 5 + frameWidth() * 2);

}

void TetrixBoard::start() {

   if (isPaused)
       return;
   isStarted = true;
   isWaitingAfterLine = false;
   numLinesRemoved = 0;
   numPiecesDropped = 0;
   score = 0;
   level = 1;
   clearBoard();
   emit linesRemovedChanged(numLinesRemoved);
   emit scoreChanged(score);
   emit levelChanged(level);
   newPiece();
   timer.start(timeoutTime(), this);

}

void TetrixBoard::pause() {

   if (!isStarted)
       return;
   isPaused = !isPaused;
   if (isPaused) {
 timer.stop();
   } else {
 timer.start(timeoutTime(), this);
   }
   update();

}

void TetrixBoard::paintEvent(QPaintEvent *event) {

   QFrame::paintEvent(event);
   QPainter painter(this);
   QRect rect = contentsRect();
   if (isPaused) {
 painter.drawText(rect, Qt::AlignCenter, tr("Pause"));
       return;
   }
   int boardTop = rect.bottom() - BoardHeight*squareHeight();
   for (int i = 0; i < BoardHeight; ++i) {
       for (int j = 0; j < BoardWidth; ++j) {
           TetrixShape shape = shapeAt(j, BoardHeight - i - 1);
     if (shape != NoShape)
               drawSquare(painter, rect.left() + j * squareWidth(),
                          boardTop + i * squareHeight(), shape);
       }

   }
   if (curPiece.shape() != NoShape) {
       for (int i = 0; i < 4; ++i) {
           int x = curX + curPiece.x(i);
           int y = curY - curPiece.y(i);
           drawSquare(painter, rect.left() + x * squareWidth(),
                      boardTop + (BoardHeight - y - 1) * squareHeight(),
                      curPiece.shape());
       }

   }

}

void TetrixBoard::keyPressEvent(QKeyEvent *event) {

   if (!isStarted || isPaused || curPiece.shape() == NoShape) {
 QFrame::keyPressEvent(event);
       return;
   }
   switch (event->key()) {
   case Qt::Key_Left:
       tryMove(curPiece, curX - 1, curY);
 break;
   case Qt::Key_Right:
       tryMove(curPiece, curX + 1, curY);
 break;
   case Qt::Key_Down:
       tryMove(curPiece.rotatedRight(), curX, curY);
 break;
   case Qt::Key_Up:
       tryMove(curPiece.rotatedLeft(), curX, curY);
 break;
   case Qt::Key_Space:
 dropDown();
 break;
   case Qt::Key_D:
 oneLineDown();
 break;
   default:
 QFrame::keyPressEvent(event);
   }

}

void TetrixBoard::timerEvent(QTimerEvent *event) {

   if (event->timerId() == timer.timerId()) {
       if (isWaitingAfterLine) {
     isWaitingAfterLine = false;
     newPiece();
     timer.start(timeoutTime(), this);
       } else {
           oneLineDown();
       }
   } else {
       QFrame::timerEvent(event);

   }

}

void TetrixBoard::clearBoard() {

   for (int i = 0; i < BoardHeight * BoardWidth; ++i)
       board[i] = NoShape;

}

void TetrixBoard::dropDown() {

   int dropHeight = 0;
   int newY = curY;
   while (newY > 0) {
       if (!tryMove(curPiece, curX, newY - 1))
           break;
       --newY;
       ++dropHeight;
   }
   pieceDropped(dropHeight);

}

void TetrixBoard::oneLineDown() {

   if (!tryMove(curPiece, curX, curY - 1))
 pieceDropped(0);

}

void TetrixBoard::pieceDropped(int dropHeight) {

   for (int i = 0; i < 4; ++i) {
       int x = curX + curPiece.x(i);
       int y = curY - curPiece.y(i);
       shapeAt(x, y) = curPiece.shape();
   }
   ++numPiecesDropped;
   if (numPiecesDropped % 25 == 0) {
       ++level;
       timer.start(timeoutTime(), this);
       emit levelChanged(level);
   }
   score += dropHeight + 7;
   emit scoreChanged(score);
   removeFullLines();
   if (!isWaitingAfterLine)
       newPiece();

}

void TetrixBoard::removeFullLines() {

   int numFullLines = 0;
   for (int i = BoardHeight - 1; i >= 0; --i) {
       bool lineIsFull = true;
       for (int j = 0; j < BoardWidth; ++j) {
           if (shapeAt(j, i) == NoShape) {
               lineIsFull = false;
               break;
           }
       }
       if (lineIsFull) {

     ++numFullLines;
     for (int k = i; k < BoardHeight - 1; ++k) {
               for (int j = 0; j < BoardWidth; ++j)
                   shapeAt(j, k) = shapeAt(j, k + 1);
     }

     for (int j = 0; j < BoardWidth; ++j)
               shapeAt(j, BoardHeight - 1) = NoShape;
 }

   }
   if (numFullLines > 0) {
 numLinesRemoved += numFullLines;
 score += 10 * numFullLines;
 emit linesRemovedChanged(numLinesRemoved);
       emit scoreChanged(score);
       timer.start(500, this);
       isWaitingAfterLine = true;
       curPiece.setShape(NoShape);
       update();
   }

}

void TetrixBoard::newPiece() {

   curPiece = nextPiece;
   nextPiece.setRandomShape();
   showNextPiece();
   curX = BoardWidth / 2 + 1;
   curY = BoardHeight - 1 + curPiece.minY();
   if (!tryMove(curPiece, curX, curY)) {
 curPiece.setShape(NoShape);
       timer.stop();
       isStarted = false;
   }

}

void TetrixBoard::showNextPiece() {

   if (!nextPieceLabel)
       return;
   int dx = nextPiece.maxX() - nextPiece.minX() + 1;
   int dy = nextPiece.maxY() - nextPiece.minY() + 1;
   QPixmap pixmap(dx * squareWidth(), dy * squareHeight());
   QPainter painter(&pixmap);
   painter.fillRect(pixmap.rect(), nextPieceLabel->palette().background());
   for (int i = 0; i < 4; ++i) {
       int x = nextPiece.x(i) - nextPiece.minX();
       int y = nextPiece.y(i) - nextPiece.minY();
       drawSquare(painter, x * squareWidth(), y * squareHeight(),
                  nextPiece.shape());
   }
   nextPieceLabel->setPixmap(pixmap);

}

bool TetrixBoard::tryMove(const TetrixPiece &newPiece, int newX, int newY) {

   for (int i = 0; i < 4; ++i) {
       int x = newX + newPiece.x(i);
       int y = newY - newPiece.y(i);
       if (x < 0 || x >= BoardWidth || y < 0 || y >= BoardHeight)
           return false;
       if (shapeAt(x, y) != NoShape)
           return false;
   }
   curPiece = newPiece;
   curX = newX;
   curY = newY;
   update();
   return true;

}

void TetrixBoard::drawSquare(QPainter &painter, int x, int y, TetrixShape shape) {

   static const QRgb colorTable[8] = {
       0x000000, 0xCC6666, 0x66CC66, 0x6666CC,
       0xCCCC66, 0xCC66CC, 0x66CCCC, 0xDAAA00
   };
   QColor color = colorTable[int(shape)];
   painter.fillRect(x + 1, y + 1, squareWidth() - 2, squareHeight() - 2,
                    color);
   painter.setPen(color.light());
   painter.drawLine(x, y + squareHeight() - 1, x, y);
   painter.drawLine(x, y, x + squareWidth() - 1, y);
   painter.setPen(color.dark());
   painter.drawLine(x + 1, y + squareHeight() - 1,
                    x + squareWidth() - 1, y + squareHeight() - 1);
   painter.drawLine(x + squareWidth() - 1, y + squareHeight() - 1,
                    x + squareWidth() - 1, y + 1);

}


  1. ifndef TETRIXWINDOW_H
  2. define TETRIXWINDOW_H
  3. include <QFrame>
  4. include <QWidget>

QT_BEGIN_NAMESPACE class QLCDNumber; class QLabel; class QPushButton; QT_END_NAMESPACE class TetrixBoard;

class TetrixWindow : public QWidget {

   Q_OBJECT

public:

   TetrixWindow();

private:

   QLabel *createLabel(const QString &text);
   TetrixBoard *board;
   QLabel *nextPieceLabel;
   QLCDNumber *scoreLcd;
   QLCDNumber *levelLcd;
   QLCDNumber *linesLcd;
   QPushButton *startButton;
   QPushButton *quitButton;
   QPushButton *pauseButton;

};

  1. endif


  1. include <QtGui>
  2. include "tetrixboard.h"
  3. include "tetrixwindow.h"

TetrixWindow::TetrixWindow() {

   board = new TetrixBoard;
   nextPieceLabel = new QLabel;
   nextPieceLabel->setFrameStyle(QFrame::Box | QFrame::Raised);
   nextPieceLabel->setAlignment(Qt::AlignCenter);
   board->setNextPieceLabel(nextPieceLabel);
   scoreLcd = new QLCDNumber(5);
   scoreLcd->setSegmentStyle(QLCDNumber::Filled);
   levelLcd = new QLCDNumber(2);
   levelLcd->setSegmentStyle(QLCDNumber::Filled);
   linesLcd = new QLCDNumber(5);
   linesLcd->setSegmentStyle(QLCDNumber::Filled);
   startButton = new QPushButton(tr("&Start"));
   startButton->setFocusPolicy(Qt::NoFocus);
   quitButton = new QPushButton(tr("&Quit"));
   quitButton->setFocusPolicy(Qt::NoFocus);
   pauseButton = new QPushButton(tr("&Pause"));

   pauseButton->setFocusPolicy(Qt::NoFocus);

   connect(startButton, SIGNAL(clicked()), board, SLOT(start()));

   connect(quitButton , SIGNAL(clicked()), qApp, SLOT(quit()));
   connect(pauseButton, SIGNAL(clicked()), board, SLOT(pause()));
   connect(board, SIGNAL(scoreChanged(int)), scoreLcd, SLOT(display(int)));
   connect(board, SIGNAL(levelChanged(int)), levelLcd, SLOT(display(int)));
   connect(board, SIGNAL(linesRemovedChanged(int)),
           linesLcd, SLOT(display(int)));
   QGridLayout *layout = new QGridLayout;
   layout->addWidget(createLabel(tr("NEXT")), 0, 0);
   layout->addWidget(nextPieceLabel, 1, 0);
   layout->addWidget(createLabel(tr("LEVEL")), 2, 0);
   layout->addWidget(levelLcd, 3, 0);
   layout->addWidget(startButton, 4, 0);
   layout->addWidget(board, 0, 1, 6, 1);
   layout->addWidget(createLabel(tr("SCORE")), 0, 2);
   layout->addWidget(scoreLcd, 1, 2);
   layout->addWidget(createLabel(tr("LINES REMOVED")), 2, 2);
   layout->addWidget(linesLcd, 3, 2);
   layout->addWidget(quitButton, 4, 2);
   layout->addWidget(pauseButton, 5, 2);
   setLayout(layout);
   setWindowTitle(tr("Tetrix"));
   resize(550, 370);

}

QLabel *TetrixWindow::createLabel(const QString &text) {

   QLabel *lbl = new QLabel(text);
   lbl->setAlignment(Qt::AlignHCenter | Qt::AlignBottom);
   return lbl;

}



  1. include <QtGui>
  2. include <stdlib.h>
  3. include "tetrixwindow.h"

int main(int argc, char *argv[]) {

   QApplication app(argc, argv);
   TetrixWindow window;
   window.show();
   qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
   return app.exec();

}


 </source>