用Qt設計自己的方塊遊戲

洛欣發表於2010-05-18

這個教程介紹方塊遊戲類的使用。教程共分三個部分。第一部分是簡介,讓你用最簡單的辦法實現自己的方塊遊戲。第二部分是功能展示,這裡通過一個例子對這個類的所有功能進行了演示。第三部分是遊戲分析,通過對介面函式的展示和對整個遊戲設計流程的分析,幫助你更好的理解原始碼。

需要說明的是:我們下面使用的程式設計環境是基於Qt 4.6的Qt Creator 1.3.0 Windows版本。這個類包含的四個檔案myitem.cpp, myitem.h ,gamearea.cpp ,gamearea.h 會和本教程打包在一起,你也可以到網上下載。

下載地址可以到我的部落格 http://hi.baidu.com/yafeilinux 進行檢視。

基於這個類我已經寫了一個範例遊戲:俄羅斯方塊勞拉版

可以到csdn下載:http://download.csdn.net/source/1866707

或到qt論壇下載:http://www.qtcn.org/bbs/read.php?tid=24169

第一部分:簡介

其實在Qt Creator中已經有了俄羅斯方塊的例子,大家可以在幫助中搜尋Tetrix進行檢視。其內容如下:

 

但是對於初學者,這個例子並不是那麼容易就能看懂。所以我結合這個例子和網上的一些資料,寫了一個比較簡單的方塊遊戲類。希望能幫助初學者更好的理解這個例子和寫出自己的方塊遊戲。

我這裡已經對所有的功能函式進行了整理,最簡單的,你只需要定義一個物件就能讓這個遊戲執行起來。

寫最簡單的遊戲

1. 新建Empty Qt4 Project,我們這裡命名為myTetrix 。

2. 向工程裡新增新的普通文字檔案,命名為main.cpp 。

3. 將myitem.cpp, myitem.h, gamearea.cpp, gamearea.h四個檔案複製到工程資料夾下。

4. 將上面四個檔案加入到工程中。

5. 將main.cpp的內容更改如下:

#include

#include "gamearea.cpp"

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

{

QApplication app(argc,argv);

GameArea box(500);

box.show();

return app.exec();

}

6.然後執行程式。效果如下圖。

 

當遊戲結束時會彈出提示框,確定後遊戲將重新開始。

如下圖所示。

 

7.可以看到,用這個類建立方塊遊戲是這麼的簡單。我們只是在主函式裡新建了一個該類的物件,其中的引數為方塊下移的速度,單位是毫秒,上面的500即0.5秒。

提示:

(如何向工程中新增檔案)

 

在工程資料夾上點右鍵,彈出的選單中Add New表示新增新檔案,Add Existing Files表示新增工程資料夾中已有的檔案。

第二部分:功能展示

要想實現更強大的功能,我們就需要應用控制窗體,而讓這個遊戲區域只作為它的一個部件。為了更好的控制遊戲,我們也需要自己建立定時器,而不再應用該類自帶的定時器了。

核心功能:

(一)建立工程。

1.首先建立工程Qt4 Gui Application,這裡命名為Tetris,選用QWidget作為Base class 。

2.然後將myitem.cpp, myitem.h ,gamearea.cpp, gamearea.h四個檔案複製到工程資料夾下並新增到工程中。

3.在widget.h中新增#include "gamearea.h"的標頭檔案包含。並在下面的private中宣告一個遊戲類物件GameArea *gameArea;

4.在widget.cpp的建構函式裡新增語句。

Widget::Widget(QWidget *parent) :

QWidget(parent),

ui(new Ui::Widget)

{

ui->setupUi(this);

this->resize(800,500);

this->gameArea = new GameArea(this);

}

這裡重新設定了主視窗大小,並在主視窗上新建了一個遊戲區域物件。

5.這時執行程式效果如下。

 

可以看到,因為使用了另一個建構函式,沒有使用該類自帶的定時器,所以只是顯示了遊戲區域,遊戲並沒有執行。

(二)新增定時器和開始按鈕,讓遊戲可以執行。

1.在widget.h裡的private中新增定時器物件和分數變數的宣告。

QTimer *timer;

int score;

在public中新增顯示分數函式的宣告。

void doScore(int);

新增槽函式的宣告。

private slots:

void timer_upDate();

2.在widget.cpp檔案中的建構函式裡新增下面的語句:

this->timer = new QTimer(this);

connect(this->timer,SIGNAL(timeout()),this,SLOT(timer_upDate()));

score =0;

定義了定時器並進行了訊號和槽函式的關聯,初始化分數為0;

3.然後在下面定義兩個函式。

void Widget::timer_upDate() //定時器溢位處理

{

this->gameArea->moveOneStep(); //先移動一步,這時並沒有顯示出來

if(this->gameArea->isMoveEnd()) //如果無法移動,到底了或結束了

{

if(this->gameArea->isGame_Over()) //如果是結束了

{

this->timer->stop(); //停止計時

QMessageBox::warning(this,tr("warning"),tr("Game Over!"),QMessageBox::Yes);

//彈出對話方塊

this->score =0; //清空分數

this->gameArea->init_Game(); //重新開始遊戲

this->gameArea->gameStart();

this->timer->start(500);

}

else //如果是移動到底了

{

this->gameArea->nextItem(); //出現下一個圖形

int num = this->gameArea->getFullRowNum(); //獲得已滿的行數

this->doScore(num); //顯示分數

this->gameArea->gameStart(); //繼續遊戲

}

}

else //如果沒有到底

{

this->gameArea->do_MoveNext(); //顯示方塊下移一步後的介面

}

}

void Widget::doScore(int num) //顯示分數

{

score += num*100;

this->ui->label_2->setText(tr("%1").arg(score));

}

4.在設計器中向主視窗上新增兩個標籤label和label_2,其中label寫上“你的分數是:”,label_2寫上“0”;然後再新增一個開始按鈕。新增完後效果如下。

 

5.然後右擊“開始遊戲”按鈕,選擇其單擊事件的槽函式。更改如下。

void Widget::on_pushButton_clicked() //開始按鈕

{

this->gameArea->init_Game(); //第一次進入遊戲時進行的初始化

this->gameArea->gameStart(); //開始遊戲

this->timer->start(500); //開啟定時器

this->gameArea->setFocus(); //讓遊戲區域獲得焦點,這樣才能響應鍵盤

}

6.現在遊戲已經可以正常進行了。執行效果如下。

 

 

(三)新增暫停和重新開始按鈕,完成基本的控制功能。

1.在主視窗上新增“暫停遊戲”和“重新開始”兩個按鈕。在“暫停遊戲”按鈕的屬性中將checkable選中。如下圖所示。

 

 

2.分別進入兩個按鈕的單擊事件槽函式。修改如下。

void Widget::on_pushButton_2_clicked() //暫停按鈕

{

if(this->ui->pushButton_2->isChecked())

{

this->timer->stop();

this->ui->pushButton_2->setText(tr("取消暫停"));

}

else

{

this->timer->start(500);

this->ui->pushButton_2->setText(tr("暫停遊戲"));

this->gameArea->setFocus();

}

}

void Widget::on_pushButton_3_clicked() //重新開始

{

this->timer->stop();

this->on_pushButton_clicked();

}

3.在main.cpp中新增語句,讓程式中可以使用中文。

新增#include 的標頭檔案包含。

在main()函式裡新增QTextCodec::setCodecForTr(QTextCodec::codecForLocale());語句。

4.程式執行效果如下。

 

高階功能的應用

(一)改變顏色和給方塊新增圖片。

1.新增“更改顏色”按鈕和“方塊貼圖”按鈕。如下圖。

 

2.更改其單擊事件槽函式。如下。

void Widget::on_pushButton_4_clicked() //改變顏色

{

this->gameArea->setGameAreaColor(QColor(255,255,0,qrand()%255));

//更改遊戲區域背景顏色

this->gameArea->setBoxBrushColor(QColor(0,255,0,qrand()%255));

//更改小方塊背景顏色

this->gameArea->setBoxPenColor(QColor(0,0,0,qrand()%255));

//更改小方塊邊框顏色

this->gameArea->draw_gameArea();

//更新遊戲區域

this->gameArea->setFocus();

}

void Widget::on_pushButton_5_clicked() //方塊貼圖

{

this->gameArea->set_draw_box_picture(true);

//確認使用方塊背景圖片

this->gameArea->setBoxPicture("box.gif");

//新增方塊背景圖片

this->gameArea->draw_gameArea();

//更新顯示區域

this->gameArea->setFocus();

}

3.執行效果如下。

點選“改變背景”按鈕後,遊戲區域背景,方塊的填充顏色和邊框顏色都改變了。

 

點選“方塊貼圖”按鈕。注意,只有方塊顏色的透明度不是255時,才能看見貼圖。所以,如果開始遊戲後直接按“方塊貼圖”按鈕,是不能顯示出背景圖片的,我們需要先改變顏色。

 

(二)是否顯示背景網格和下一個要出現的方塊。

1.新增“網格顯示”按鈕和“方塊提示”按鈕。並將它們屬性中的checkable選中。介面如下。

 

2.修改它們的單擊事件槽函式。

void Widget::on_pushButton_6_clicked() //網格顯示

{

if(this->ui->pushButton_6->isChecked())

{

this->gameArea->setDrawGrid(false);

}

else

{

this->gameArea->setDrawGrid(true);

}

this->gameArea->draw_gameArea();

this->gameArea->setFocus();

}

void Widget::on_pushButton_7_clicked() //方塊提示

{

if(this->ui->pushButton_7->isChecked())

{

this->gameArea->setDrawNextItem(false);

}

else

{

this->gameArea->setDrawNextItem(true);

}

this->gameArea->draw_gameArea();

this->gameArea->setFocus();

}

3.執行效果如下。

 

 

(三)新增方塊移動的聲音。

1.新增“開啟聲音”按鈕,並將其屬性中的checkable選中。

 

2.修改其單擊事件槽函式。

void Widget::on_pushButton_8_clicked() //聲音開關

{

if(this->ui->pushButton_8->isChecked())

{

this->gameArea->setPlaySound_itemChange("changeItem.wav",true);

this->gameArea->setPlaySound_moveDown("moveDown.wav",true);

this->gameArea->setPlaySound_moveLeft("moveLeft.wav",true);

this->gameArea->setPlaySound_moveRight("moveLeft.wav",true);

this->ui->pushButton_8->setText(tr("關閉聲音"));

}

else

{

this->gameArea->setPlaySound(false); //關閉音樂

this->ui->pushButton_8->setText(tr("開啟聲音"));

}

this->gameArea->setFocus();

}

3.我們把需要的聲音檔案放到工程資料夾下的debug資料夾下。注意:只能是wav格式的。然後執行程式,測試一下效果。

(四)新增向下按鍵移動步數設定。

1.新增“是否墜落”按鈕,並將其屬性中的checkable選中。

 

2.更改其單擊事件槽函式。

void Widget::on_pushButton_9_clicked() //是否墜落

{

if(this->ui->pushButton_9->isChecked())

{

this->gameArea->setKey_Down_Move_oneStep(true);

//按一下向下方向鍵,下移一步

}

else

{

this->gameArea->setKey_Down_Move_oneStep(false);

//按一下向下方向鍵,移動到底

}

this->gameArea->setFocus();

}

3.執行程式,測試一下效果。

(五)自己新增方塊。

1.新增“新增方塊”按鈕。

 

2.修改其單擊事件槽函式。

void Widget::on_pushButton_10_clicked() //新增方塊

{

this->gameArea->init_Game();

//清空遊戲區域

this->gameArea->setbox(10,4);

this->gameArea->setbox(10,5);

this->gameArea->setbox(10,6);

//在第10行第4,5,6列新增三個方塊

this->gameArea->gameStart();

//重新開始遊戲

this->gameArea->draw_gameArea();

this->gameArea->setFocus();

}

3.執行程式,效果如下。

 

(六)設定旋轉游戲區。

1.新增“旋轉游戲”按鈕。

 

2.修改其單擊事件槽函式。

void Widget::on_pushButton_11_clicked() //旋轉游戲

{

this->gameArea->setRotate(true);

//開啟旋轉

this->gameArea->setGameAreaPixOrigin(100,200);

//設定遊戲區域新的座標原點

this->gameArea->setGameAreaPix(-100,-200);

//設定遊戲區域的位置

this->gameArea->setRotateAngle(qrand()%360);

//旋轉度數

this->gameArea->draw_gameArea();

this->gameArea->setFocus();

}

3.執行程式,效果如下。

 

第三部分:遊戲分析

(一)可被外部呼叫的功能函式的原型。

GameArea(QWidget *parent = 0); //不帶定時器的建構函式

GameArea(int speed,QWidget *parent = 0); //帶定時器的建構函式

//以下是核心功能控制函式

void init_gameArea(int X,int Y,int frame_width,int frame_height,int width,int height,int boxStep,int start_x,int start_y);

void moveOneStep();

bool isMoveEnd();

bool isGame_Over();

void init_Game();

void gameStart();

void nextItem();

int getFullRowNum();

void do_MoveNext();

void draw_gameArea();

//以下是設定顏色函式

void setGameAreaColor(QColor color=Qt::white);

void setBoxBrushColor(QColor color=Qt::green);

void setBoxPenColor(QColor color=Qt::black);

void set_draw_box_picture(bool Bool=false);

void setBoxPicture(QString fileName);

//以下是設定聲音函式

void setPlaySound_moveLeft(QString fileName,bool Bool=false);

void setPlaySound_moveRight(QString fileName,bool Bool=false);

void setPlaySound_moveDown(QString fileName,bool Bool=false);

void setPlaySound_itemChange(QString fileName,bool Bool=false);

void setPlaySound(bool Bool=false);

//以下是設定遊戲區域旋轉函式

void setRotate(bool Bool=false);

void setGameAreaPixOrigin(int x,int y);

void setGameAreaPix(int x,int y);

void setRotateAngle(int angle);

//以下是其他功能函式

void setKey_Down_Move_oneStep(bool Bool = false);

void setDrawGrid(bool Bool = true);

void setDrawNextItem(bool Bool =true);

void setbox(int row,int col);

(二)遊戲流程分析。

這裡共有四個檔案myitem.cpp ,myitem.h, gamearea.cpp, gamearea.h

其中myitem.cpp, myitem.h是方塊類的定義檔案,它用來提供隨機產生的方塊。

gamearea.cpp, gamearea.h是遊戲區域類的定義檔案,它實現了遊戲的所有功能。

為了幫助大家更好的理解原始碼,我們這裡描述一下游戲的實現流程。

 

難點解析:

1. 遊戲實現的核心方法是什麼?

這裡是利用了陣列對整個遊戲區域進行儲存。

2. 遊戲是怎麼實現顯示現在和已有的圖形的?

這裡利用了兩個陣列,方塊每移動一步,都對整個陣列進行一次備份。

3. 遊戲是怎麼判斷方塊已經重合的?

這裡是先嚐試讓方塊移動一步,判斷其是否與其他圖形重合,如果不重合就移動。如果重合了,就進行其他操作。

4. 遊戲是怎麼進行消行的?

這裡是讓已滿的行和它上面的所有的行均等於其上面的一行。

到這裡整篇教程就結束了。這個方塊遊戲類還有很多功能不太完善,為了使程式碼更容易理解,也捨去了一些功能,例如讓不同方塊顯示不同的顏色等。大家可以參考Qt自帶的例程進行完善,也很希望大家對這個類的原始碼進行修改和完善。


最後,如果你喜歡我的寫作風格,並且初學Qt,可以在我的空間檢視Qt Creator系列教程,希望能對你的入門有所幫助。

 

本文來自CSDN部落格,轉載請標明出處:http://blog.csdn.net/yafeilinux/archive/2009/12/21/5049945.aspx

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/22785983/viewspace-662967/,如需轉載,請註明出處,否則將追究法律責任。

相關文章