štvrtok, 01 december 2011 10:35 Written by Zdeno Sekerak 5176 times
Rate this item
(1 Vote)

Tetris v qt++

Všetkým dobre známa hra Tetris. Je plne funkčná, kľudne si ju skúste. Hra je napísaná v qt++ pod linuxom.

 

Časť kód :

#include "mainwindow.h"
#include "ui_mainwindow.h"

#ifdef Q_OS_WIN
#include <windows.h> // for Sleep
#endif

#define OPT_CLR     0
#define OPT_PUT     1
#define OPT_SAV     2

#define SMER_NONE   0
#define SMER_LEFT   1
#define SMER_RIGHT  2
#define SMER_OTOCR  3
#define SMER_OTOCL  4

#define TO_LEV  24      // kolko riadkov ma level
#define COLOR_UNDEF   -1  // nedefinovana farba

const int CUBE[7][4][4] =
      {{{0,0,0,0},    // kocka
        {0,1,1,0},
        {0,1,1,0},
        {0,0,0,0}},

       {{0,1,0,0},    // dlhe I
        {0,1,0,0},
        {0,1,0,0},
        {0,1,0,0}},

       {{0,1,0,0},    // opacne T
        {0,1,1,0},
        {0,1,0,0},
        {0,0,0,0}},

       {{0,0,0,0},    // Z vpravo
        {0,1,1,0},
        {1,1,0,0},
        {0,0,0,0}},

       {{0,0,0,0},    // Z vlavo
        {1,1,0,0},
        {0,1,1,0},
        {0,0,0,0}},

       {{0,1,0,0},    // L vpravo
        {0,1,0,0},
        {0,1,1,0},
        {0,0,0,0}},

       {{0,0,1,0},    // L vlavo
        {0,0,1,0},
        {0,1,1,0},
        {0,0,0,0}}};


MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    y=0;
    ui->setupUi(this);

    icon[0].addFile(QString::fromUtf8(":/obrazky/Resources/green_field.png"), QSize(), QIcon::Normal, QIcon::Off);
    icon[1].addFile(QString::fromUtf8(":/obrazky/Resources/red_field.png"), QSize(), QIcon::Normal, QIcon::Off);
    icon[2].addFile(QString::fromUtf8(":/obrazky/Resources/blue_field.png"), QSize(), QIcon::Normal, QIcon::Off);
    icon[3].addFile(QString::fromUtf8(":/obrazky/Resources/magenta_field.png"), QSize(), QIcon::Normal, QIcon::Off);
    icon[4].addFile(QString::fromUtf8(":/obrazky/Resources/orange_field.png"), QSize(), QIcon::Normal, QIcon::Off);
    icon[5].addFile(QString::fromUtf8(":/obrazky/Resources/yellow_field.png"), QSize(), QIcon::Normal, QIcon::Off);
    icon[6].addFile(QString::fromUtf8(":/obrazky/Resources/cyan_field.png"), QSize(), QIcon::Normal, QIcon::Off);
    icon_empty.addFile(QString::fromUtf8(":/obrazky/Resources/empty_field.png"), QSize(), QIcon::Normal, QIcon::Off);

    timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(dalsiTAH()));
    // automaticky spusti
    on_pushButtonTurn_clicked();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::changeEvent(QEvent *e)
{
    QMainWindow::changeEvent(e);
    switch (e->type()) {
    case QEvent::LanguageChange:
        ui->retranslateUi(this);
        break;
    default:
        break;
    }
}

void MainWindow::qSleep(int ms)
{
#ifdef Q_OS_WIN
    Sleep(uint(ms));
#else
    struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 };
    nanosleep(&ts, NULL);
#endif
}

void MainWindow::ClrPole()
{
    for(int y=0; y<MAX_Y; y++)
      for(int x=0; x<MAX_X; x++) {
        pole[x][y]=COLOR_UNDEF;
        ui->pushButton[x][y]->setIcon(icon_empty);
    }
}

// urci predchadzajuci prvok
int MainWindow::TPred(int otoc)
{
  if(otoc==0) otoc=3;
         else otoc=otoc-1;
  return otoc;
}

// urci nasledujuci prvok
int MainWindow::TSucc(int otoc)
{
  if(otoc==3) otoc=0;
         else otoc=otoc+1;
  return otoc;
}

// urci mensi prvok
int MainWindow::Min(int a,int b)
{
  if(a<b) return a;
     else return b;
 }


// vykresli, zmaz, uloz kocku, alebo urci ci je mozne kocku polozit
void MainWindow::Kocka(int xp,int yp,int typ,int otoc,int col, int option)
{
int x,y;
int bod;

  // v cykle vygenerujeme jednotlive prvky kocky
  for(y=0; y<4; y++)
    for(x=0; x<4; x++) {
      switch(otoc) {
        case 0: bod = CUBE[typ][  x][  y]; break;
        case 1: bod = CUBE[typ][3-y][  x]; break;
        case 2: bod = CUBE[typ][3-x][3-y]; break;
        case 3: bod = CUBE[typ][  y][3-x]; break;
      }

      switch(option) {
        case OPT_CLR: // zmaze kocku
            if( bod==1 )
                ui->pushButton[xp+x][yp+y]->setIcon(icon_empty);
            break;

        case OPT_PUT: // nakresli, zmaze kocku
              if( bod==1 )
                  ui->pushButton[xp+x][yp+y]->setIcon(icon[col]);
              break;

        case OPT_SAV: // ulozi kocku do pola
              if( bod==1 )
                  pole[x+xp][y+yp]=col;
              break;
       }    // switch
     }      // for
 }


// zisti ci je mozne polozit kocku
bool MainWindow::KockaOK(int xp, int yp, int typ, int otoc)
{
int x,y;
int bod;
bool res;

  // zatial si mysli ze kocku je mozne polozit
  res=true;

  // v cykle vygenerujeme jednotlive prvky kocky
  for(y=0; y<4; y++)
    for(x=0; x<4; x++) {
       switch(otoc) {
        case 0: bod = CUBE[typ][  x][  y]; break;
        case 1: bod = CUBE[typ][3-y][  x]; break;
        case 2: bod = CUBE[typ][3-x][3-y]; break;
        case 3: bod = CUBE[typ][  y][3-x]; break;
       }

       if( bod==1 ) {
         // hrube podmienky
         if((x+xp) <0      ) res=false;
         if((x+xp) >=MAX_X ) res=false;
         if((y+yp) >=MAX_Y ) res=false;
         if(  otoc <0      ) res=false;
         if(  otoc >3      ) res=false;

         // este ci je tam volne miesto
         if( res )
            if( pole[x+xp][y+yp] != COLOR_UNDEF )
                res=false;
           }  // if
       } // for

  // moja odpoved
  return res;
}

// zmaze zaplneny riadok
// a ostane posunie nadol
void MainWindow::ZmazRiadok(int yr)
{
int x,y;

  // efekt postupneho mazania
  for(x=0; x<MAX_X; x++)
  {
    ui->pushButton[x][yr]->setIcon(icon_empty);
    qSleep(20);
  }

  // efekt padu riadkov
  for(y=yr; y>1; y--)
    for(x=0; x<MAX_X; x++)
    {
      pole[x][y]=pole[x][y-1];
      //
      if( pole[x][y] == COLOR_UNDEF )
        ui->pushButton[x][y]->setIcon(icon_empty);
      else
        ui->pushButton[x][y]->setIcon(icon[(int)pole[x][y]]);
    }
}


// skontroluje ktore riadky ma zmazat
void MainWindow::Skontroluj(int yr)
{
int x,y;
bool del;

  for(y=yr; y<Min(yr+4, MAX_Y); y++)
  {
    del=true;
    for(x=0; x<MAX_X; x++)
      if( pole[x][y] == COLOR_UNDEF )
          del=false;

    if( del )
    {
      ZmazRiadok(y);
      body=body+ui->horizontalScrollBar->value();
      tlev=tlev+1;
      ui->label_3->setText(QString::number(body));
    }
  }

  // ideme do dalsieho levelu
  if( body>=TO_LEV ) {
    tlev=0;
    ui->horizontalScrollBar->setValue( ui->horizontalScrollBar->value()+1);
    ui->label_3->setText(QString::number(body));
  }
}


void MainWindow::on_pushButtonTurn_clicked()
{
    if(y==0) {
        ClrPole();
        x    = (MAX_X / 2)-2;
        otoc = (rand() % 4);
        typ  = 6;
        typ  = (rand() % 7);
        col  = (rand() % MAX_COLOR);
        y    = 0;
        // bodovanie
        body =0;
        tlev =0;
        // zrus info
        ui->pushButtonTurn->setText("");

        // nahodim timer
        timer->start(10*(101-ui->horizontalScrollBar->value()));
        return;
    }

    smer = SMER_OTOCR;
}

// vlevo
void MainWindow::on_pushButtonDayDown_clicked()
{
    smer = SMER_LEFT;
}

// vpravo
void MainWindow::on_pushButtonDayUp_clicked()
{
    smer = SMER_RIGHT;
}

void MainWindow::dalsiTAH()
{    
    // zmaz staru
    Kocka(x,y,typ,otoc,col,OPT_CLR);

    // podmienky otocit, vlavo, vpravo
    if((smer==SMER_LEFT)  && KockaOK(x-1,y,typ,otoc)) x=x-1;
    if((smer==SMER_RIGHT) && KockaOK(x+1,y,typ,otoc)) x=x+1;
    if((smer==SMER_OTOCR) && KockaOK(x,y,typ,TPred(otoc))) otoc=TPred(otoc);
    if((smer==SMER_OTOCL) && KockaOK(x,y,typ,TSucc(otoc))) otoc=TSucc(otoc);

    // posuniem o riadok nizsie
    if( KockaOK(x,y+1,typ,otoc)) {
        y=y+1;
    } else {
        // kocka spadla
        Kocka(x,y,typ,otoc,col,OPT_PUT);
        Kocka(x,y,typ,otoc,col,OPT_SAV);
        Skontroluj(y);

        // zobraz
        /*
        for(y=0; y<MAX_Y; y++)
          for(x=0; x<MAX_X; x++) {
            if(pole[x][y] != COLOR_UNDEF)
                ui->pushButton[x][y]->setText(QString::number(pole[x][y]));
        }
        */

        // niet kam polozit koncim, nerestartujem timer
        if( y==0 ) {
            ui->pushButtonTurn->setText("Press for start");
            return;
        }

        // nova kocka
        x    = (MAX_X / 2)-2;
        otoc = (rand() % 4);
        typ  = (rand() % 7);
        col  = (rand() % MAX_COLOR);
        y    = 0;
    }

    // nakresli
    Kocka(x,y,typ,otoc,col,OPT_PUT);
    smer = SMER_NONE;

    // znova za timer
    timer->start(10*(101-ui->horizontalScrollBar->value()));
}

Tento článok je pridaný so súhlasom autora :

TrSek alias Zdeno Sekerak

http://www.trsek.com

Last modified on štvrtok, 01 december 2011 11:25
More in this category: Hello World v QT »