您好,登錄后才能下訂單哦!
這篇“Qt怎么實(shí)現(xiàn)方塊游戲”文章的知識(shí)點(diǎn)大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細(xì),步驟清晰,具有一定的借鑒價(jià)值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來(lái)看看這篇“Qt怎么實(shí)現(xiàn)方塊游戲”文章吧。
在這個(gè)游戲中,有一個(gè)區(qū)域用來(lái)擺放方塊,該區(qū)域?qū)挒?0,高為20,以小正方形為單位,它可以看作是擁有20行10列的一個(gè)網(wǎng)格。標(biāo)準(zhǔn)的游戲中一共有7種方塊,它們都是由4個(gè)小正方形組成的規(guī)則圖形,依據(jù)形狀分別用字母I、J、L、O、S、T和Z來(lái)命名。
這里使用圖形視圖框架來(lái)實(shí)現(xiàn)整個(gè)游戲的設(shè)計(jì)。小正方形由OneBox來(lái)表示,它繼承自QGraphicsObject類(lèi),之所以繼承自這個(gè)類(lèi),是因?yàn)檫@樣就可以使用信號(hào)和槽機(jī)制,話(huà)可以使用屬性動(dòng)畫(huà)。小正方形就是一個(gè)寬和高都為20像素的正方形圖形項(xiàng)。游戲中的方塊游戲由方塊組BoxGroup類(lèi)來(lái)實(shí)現(xiàn),繼承自QObject和QGraphicsItemGroup類(lèi),這樣該類(lèi)也可以使用信號(hào)和槽機(jī)制。方塊組是一個(gè)寬和高都是80像素的圖形項(xiàng)組,其中包含了4個(gè)小方塊,通過(guò)設(shè)置小方塊的位置來(lái)實(shí)現(xiàn)7種標(biāo)準(zhǔn)的方塊圖形。它們的形狀和位置如下圖,在BoxGroup類(lèi)中實(shí)現(xiàn)了方塊圖形的創(chuàng)建、移動(dòng)和碰撞檢測(cè)。
方塊移動(dòng)區(qū)域在游戲場(chǎng)景中使用四條直線(xiàn)圖形項(xiàng)所圍成區(qū)域來(lái)表示,之所以要這樣實(shí)現(xiàn),是因?yàn)檫@樣可以通過(guò)方塊組是否與直線(xiàn)圖形項(xiàng)碰撞來(lái)檢測(cè)是否移動(dòng)出界。整個(gè)游戲界面由MyView類(lèi)來(lái)實(shí)現(xiàn),該類(lèi)繼承自QGraphicsView類(lèi),實(shí)現(xiàn)了場(chǎng)景設(shè)置、游戲邏輯設(shè)計(jì)和游戲聲音設(shè)置及其他控制功能。
整個(gè)游戲場(chǎng)景寬800像素,高500像素。方塊移動(dòng)區(qū)域?qū)?00像素,高400像素,縱向每20個(gè)像素被視作一行,共有20行;橫行也是每20個(gè)像素視作一列,所以共有10列,該區(qū)域可以看作一個(gè)由20行10列20×20像素的方格組成的網(wǎng)格。方塊組在方塊移動(dòng)區(qū)域的初始位置為上方正中間,但方塊組的最上方一行小正方形在方塊移動(dòng)區(qū)域以外,這樣可以保證方塊組完全出現(xiàn)在移動(dòng)區(qū)域的最上方,方塊組每移動(dòng)一次,就是移動(dòng)一個(gè)方格的位置。場(chǎng)景還設(shè)置了下一個(gè)要出現(xiàn)方塊的提示方塊、游戲暫停等控制按鈕和游戲分?jǐn)?shù)級(jí)別的顯示文本,整個(gè)場(chǎng)景的示意圖如下圖所示:
當(dāng)游戲開(kāi)始后,首先創(chuàng)建一個(gè)新的方塊組,并將其添加到場(chǎng)景中的方塊移動(dòng)區(qū)域上方。然后進(jìn)行碰撞檢測(cè),如果這時(shí)已經(jīng)發(fā)生了碰撞,那么游戲結(jié)束;如果沒(méi)有發(fā)生碰撞,就可以使用鍵盤(pán)的方向鍵對(duì)其進(jìn)行旋轉(zhuǎn)變形或者左右移動(dòng)。當(dāng)?shù)竭_(dá)指定事件時(shí)方塊組會(huì)自動(dòng)下移一個(gè)方格,這時(shí)再次判斷是否發(fā)生碰撞,如果發(fā)生了碰撞,先消除滿(mǎn)行的方格,然后出現(xiàn)新的方塊組,并繼續(xù)進(jìn)行整個(gè)流程。其中方程塊的移動(dòng)、旋轉(zhuǎn)、碰撞檢測(cè)等都在BoxGroup類(lèi)中進(jìn)行;游戲的開(kāi)始、結(jié)束、出現(xiàn)新的方程組、消除滿(mǎn)行等都在MyView類(lèi)中進(jìn)行。游戲程序圖以及方塊組移動(dòng)和旋轉(zhuǎn)流程圖如下:
2.1、方塊組的移動(dòng)和旋轉(zhuǎn)
方塊組的左移、右移、下移和旋轉(zhuǎn)都是先進(jìn)行該操作,然后判斷是否發(fā)生碰撞,比如發(fā)生了碰撞就再進(jìn)行反向操作。比如,使用方向鍵左移方塊組,那么就先將方塊組左移一格,然后進(jìn)行碰撞檢測(cè),看是否與邊界線(xiàn)或者其他方塊碰撞了,如果發(fā)生了碰撞,那么就再移過(guò)來(lái),即右移一個(gè)。方塊組的移動(dòng)和旋轉(zhuǎn)流程如下:
2.2、碰撞檢測(cè)
對(duì)于方塊組的碰撞檢測(cè),其實(shí)是使用方塊組中的4個(gè)小方塊來(lái)進(jìn)行的,這樣就不用再為每個(gè)方塊圖形都設(shè)置一個(gè)碰撞檢測(cè)時(shí)使用的形狀。要進(jìn)行碰撞檢測(cè)時(shí),對(duì)每一個(gè)小方塊都使用函數(shù)來(lái)獲取與它們碰撞的圖形項(xiàng)的數(shù)目,因?yàn)楝F(xiàn)在小方塊在方塊組中,所以應(yīng)該只有方塊組與它們碰撞了(由于我們對(duì)小方塊的形狀進(jìn)行了設(shè)置,所以挨著的四個(gè)小方塊相互間不會(huì)被檢測(cè)出發(fā)生了碰撞),也就是說(shuō)與它們碰撞的圖形項(xiàng)數(shù)目應(yīng)該不會(huì)大于1,如果有哪個(gè)小方塊發(fā)現(xiàn)與它碰撞的圖形項(xiàng)的數(shù)目大于1,那么說(shuō)明已經(jīng)發(fā)生了碰撞。
2.3、游戲結(jié)束
當(dāng)一個(gè)新的方塊組出現(xiàn)時(shí),就立即對(duì)齊進(jìn)行碰撞檢測(cè),如果它一出現(xiàn)就與其他方塊發(fā)生了碰撞,說(shuō)明游戲已經(jīng)結(jié)束了,這時(shí)由方塊組發(fā)射游戲結(jié)束信號(hào)。
2.4、消除滿(mǎn)行
游戲開(kāi)始后,每當(dāng)出現(xiàn)一個(gè)新的方塊以前,都判斷游戲移動(dòng)區(qū)域的每一行是否已經(jīng)擁有10個(gè)小方塊。如果有一行已經(jīng)擁有了10個(gè)小方塊,說(shuō)明改行已滿(mǎn),那么就銷(xiāo)毀該行的所有小方塊,然后讓該行上面的所有小方塊都下移一格。
box.h
#ifndef BOX_H #define BOX_H #include <QGraphicsObject> #include<QGraphicsItemGroup> class OneBox :public QGraphicsObject { public: OneBox(const QColor &color = Qt::red); QRectF boundingRect() const; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); QPainterPath shape() const; private: QColor brushColor; }; class BoxGroup : public QObject,public QGraphicsItemGroup { Q_OBJECT public: enum BoxShape {IShape, JShape, LShape, OShape, SShape, TShape, ZShape, RandomShape};//8中俄羅斯方框形狀 BoxGroup(); QRectF boundingRect() const;//在函數(shù)后用const表示不能改變類(lèi)的成員 void clear_box_group(bool destroy_box = false); void create_box(const QPointF &point, BoxShape shape = RandomShape);//在函數(shù)的申明處可以將參數(shù)設(shè)定為默認(rèn)值,定義處不需要 bool isColliding(); BoxShape getCurrentShape() {return current_shape;}//獲得當(dāng)前俄羅斯方塊的形狀 protected: void keyPressEvent(QKeyEvent *event); signals: void need_new_box(); void game_finished(); public slots: void move_one_step(); void startTimer(int interval); void stop_timer(); private: BoxShape current_shape; QTransform old_transform; QTimer *timer; }; #endif // BOX_H
box.cpp
#include "box.h" #include<QPainter> #include<QTimer> #include<QKeyEvent> //OneBox是從QGraphicsObject繼承而來(lái)的 OneBox::OneBox(const QColor &color) : brushColor(color) { } //該函數(shù)為指定后面的繪圖區(qū)域的外邊框 QRectF OneBox::boundingRect() const { qreal pen_width = 1; //小方塊的邊長(zhǎng)為20.5像素 return QRectF(-10-pen_width/2, -10-pen_width/2, 20+pen_width, 20+pen_width); } void OneBox::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget){ //貼圖,看起來(lái)有質(zhì)感,否則單獨(dú)用顏色去看,會(huì)感覺(jué)那些方塊顏色很單一 painter->drawPixmap(-10, -10, 20, 20, QPixmap(":/images/box.gif")); painter->setBrush(brushColor);//設(shè)置畫(huà)刷顏色 QColor penColor = brushColor; penColor.setAlpha(20);//將顏色的透明度減小,使方框邊界和填充色直接能區(qū)分開(kāi) painter->setPen(penColor);//色繪制畫(huà)筆 //這里畫(huà)矩形框,框內(nèi)填充部分用畫(huà)刷畫(huà),框外線(xiàn)條用畫(huà)筆畫(huà) painter->drawRect(-10, -10, 20, 20);//畫(huà)矩形框 } //在局部坐標(biāo)點(diǎn)上返回item的shape,但是好像沒(méi)有其它地方調(diào)用了該函數(shù) QPainterPath OneBox::shape() const{ //QPainterPath是一個(gè)繪圖操作的容器 QPainterPath path; path.addRect(-9.5, -9.5, 19, 19); return path; } //BoxGroup是從QGraphicsItemGroup,QObject繼承而來(lái)的 BoxGroup::BoxGroup() { setFlags(QGraphicsItem::ItemIsFocusable);//允許設(shè)置輸入焦點(diǎn) old_transform = transform();//返回當(dāng)前item的變換矩陣,當(dāng)BoxGroup進(jìn)行旋轉(zhuǎn)后,可以使用它來(lái)進(jìn)行恢復(fù) timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(move_one_step())); current_shape = RandomShape; } QRectF BoxGroup::boundingRect() const { qreal pen_width = 1; return QRectF(-40-pen_width/2, -40-pen_width/2, 80+pen_width, 80+pen_width);//2*2個(gè)小方塊組成一個(gè)小方塊組 } void BoxGroup::keyPressEvent(QKeyEvent *event) { static qreal angle = 0; switch(event->key()) { //向下鍵位墜落鍵 case Qt::Key_Down:{ moveBy(0, 20);//moveBy是系統(tǒng)自帶的函數(shù),不需要我們自己去實(shí)現(xiàn) while(!isColliding()) { moveBy(0, 20); } moveBy(0, -20);//往回跳 clear_box_group();//到達(dá)底部后就將當(dāng)前方塊組的4個(gè)item移除,不銷(xiāo)毀方塊組 emit need_new_box();//發(fā)射信號(hào),在MyView中接收 break;} case Qt::Key_Left:{ moveBy(-20, 0); if(isColliding()) { moveBy(20, 0); } break;} case Qt::Key_Right:{ moveBy(20, 0); if(isColliding()) { moveBy(-20, 0); } break;} //實(shí)現(xiàn)小方塊組變形 case Qt::Key_Up:{ setRotation(angle+90.0); angle = angle+90.0; //rotation(); if(isColliding()) { setRotation(angle-90); angle = angle-90.0; //rotation(); } break;} } } //檢測(cè)是否有碰撞 bool BoxGroup::isColliding() { QList<QGraphicsItem *> item_list = childItems();//返回子item列表 QGraphicsItem *item; foreach(item, item_list) { if(item->collidingItems().count()>1)//collidingItems返回與當(dāng)前item碰撞的子item列表 return true;//代表至少有一個(gè)item發(fā)生了碰撞 } return false; } //將方塊組從視圖中移除掉,如果有需要(即參數(shù)為true的情況下)則銷(xiāo)毀掉 //其本質(zhì)是將所有的小方塊從方塊組中移除掉,達(dá)到從視圖中將方塊組移除的目的 void BoxGroup::clear_box_group(bool destroy_box) { QList<QGraphicsItem *> item_list = childItems(); QGraphicsItem *item; foreach(item, item_list) { removeFromGroup(item);//將item從方塊組中移除掉 if(destroy_box) { OneBox *box = (OneBox*)item; box->deleteLater();//當(dāng)控制返回到事件循環(huán)時(shí),該目標(biāo)被刪除,即銷(xiāo)毀 } } } //創(chuàng)建俄羅斯方塊組,根據(jù)形狀參數(shù)選擇方塊組的顏色和形狀 void BoxGroup::create_box(const QPointF &point, BoxShape shape) { static const QColor color_table[7] = { QColor(200, 0, 0, 100), QColor(255, 200, 0, 100), QColor(0, 0, 200, 100), QColor(0, 200, 0, 100), QColor(0, 200, 255, 100), QColor(200, 0, 255, 100), QColor(150, 100, 100, 100) }; int shape_id = shape; //Box_Shape是枚舉型,其實(shí)也是整型,因?yàn)樗喈?dāng)于整型的宏定義 if(shape == RandomShape) { shape_id = qrand()%7;//隨機(jī)取一個(gè)顏色 } QColor color = color_table[shape_id];//根據(jù)id選顏色 QList<OneBox *> list; setTransform(old_transform);//恢復(fù)方塊組前的變換矩陣 for(int i = 0; i < 4; ++i) { //4個(gè)小方塊組成一個(gè)方塊組 OneBox *temp = new OneBox(color); list << temp;//將小方塊加入list列表 addToGroup(temp); } switch(shape_id) { case IShape: current_shape = IShape;//橫著的一桿 list.at(0)->setPos(-30, -10); list.at(1)->setPos(-10, -10); list.at(2)->setPos(10, -10); list.at(3)->setPos(30, -10); break; case JShape: current_shape = JShape;//J型 list.at(0)->setPos(10, -10); list.at(1)->setPos(10, 10); list.at(2)->setPos(10, 30); list.at(3)->setPos(-10, 30); break; case LShape: current_shape = LShape;//L型的方塊組 list.at(0)->setPos(-10, -10); list.at(1)->setPos(-10, 10); list.at(2)->setPos(-10, 30); list.at(3)->setPos(10, 30); break; case OShape://田字型 current_shape = OShape; list.at(0)->setPos(-10, -10); list.at(1)->setPos(10, -10); list.at(2)->setPos(-10, 10); list.at(3)->setPos(10, 10); break; case SShape://S型 current_shape = SShape; list.at(0)->setPos(10, -10); list.at(1)->setPos(30, -10); list.at(2)->setPos(-10, 10); list.at(3)->setPos(10, 10); break; case TShape: //土子型 current_shape = TShape; list.at(0)->setPos(-10, -10); list.at(1)->setPos(10, -10); list.at(2)->setPos(30, -10); list.at(3)->setPos(10, 10); break; case ZShape://Z字型 current_shape = ZShape; list.at(0)->setPos(-10, -10); list.at(1)->setPos(10, -10); list.at(2)->setPos(10, 10); list.at(3)->setPos(30, 10); break; default: break; } setPos(point);//將準(zhǔn)備好的俄羅斯方塊放入指定的位置,然后進(jìn)行碰撞檢測(cè) if(isColliding()) { //如果俄羅斯方塊一出現(xiàn)后就發(fā)生了碰撞,因?yàn)樗菑闹虚g出來(lái)的,所以一開(kāi)始不可能是與左右兩邊發(fā)生碰撞, //只能是與下面碰撞,因此如果發(fā)生了碰撞,說(shuō)明游戲已經(jīng)結(jié)束,就可以發(fā)送游戲結(jié)束信號(hào)了,且定時(shí)器停止。 stop_timer(); emit game_finished(); } } //這個(gè)是系統(tǒng)里的函數(shù),本程序中是在主函數(shù)中啟動(dòng)的 //其實(shí)是該子類(lèi)中的timeEvent()函數(shù)調(diào)用的 void BoxGroup::startTimer(int interval) { timer->start(interval);//啟動(dòng)定時(shí)器并且設(shè)置定時(shí)器間隔,然后在BoxGroup()的構(gòu)造函數(shù)中設(shè)置了該定時(shí)器的信號(hào)與槽函數(shù) } //每當(dāng)定時(shí)器到時(shí)間了,小方塊組就向下移一步 void BoxGroup::move_one_step() { moveBy(0, 20);//該函數(shù)是父類(lèi)的函數(shù),這里指向下移動(dòng)一個(gè)單位,因?yàn)橄蛳聻檎鴺?biāo) if(isColliding()) {//發(fā)生碰撞的情況下 moveBy(0, -20); clear_box_group();//將方塊組移除視圖 emit need_new_box();//發(fā)生信號(hào)通知程序需要新的方塊組出現(xiàn) } } void BoxGroup::stop_timer() { timer->stop();//定時(shí)器停止 }
myview.h
#ifndef MYVIEW_H #define MYVIEW_H #include <QGraphicsView> class BoxGroup; class MyView : public QGraphicsView { Q_OBJECT public: explicit MyView(QWidget *parent = 0);//關(guān)鍵字explicit是為了防止隱式類(lèi)型轉(zhuǎn)換 public slots: void start_game(); void clear_full_rows(); void move_box(); void game_over(); void restartGame(); void finishGame(); void pauseGame(); void returnGame(); protected: private: //遮罩面板 QGraphicsWidget *maskWidget; //各種按鈕 QGraphicsWidget *mask_widget; //首頁(yè)和游戲中需要用到的各種按鈕 QGraphicsWidget *start_button; QGraphicsWidget *finish_button; QGraphicsWidget *restart_button; QGraphicsWidget *pause_button; QGraphicsWidget *option_button; QGraphicsWidget *return_button; QGraphicsWidget *help_button; QGraphicsWidget *exit_button; QGraphicsWidget *show_menu_button; //顯示人機(jī)交互的文本信息 QGraphicsTextItem *game_welcome_text; QGraphicsTextItem *game_pause_text; QGraphicsTextItem *game_over_text; QGraphicsTextItem *gameScoreText; QGraphicsTextItem *gameLevelText; QGraphicsLineItem *top_line; QGraphicsLineItem *bottom_line; QGraphicsLineItem *left_line; QGraphicsLineItem *right_line; BoxGroup *box_group; BoxGroup *next_box_group; qreal game_speed; QList<int> rows; void init_view(); void init_game(); void update_score(const int full_row_num = 0); }; #endif // MYVIEW_H
myview.cpp
#include "myview.h" #include"box.h" #include<QIcon> #include<QPropertyAnimation> #include<QGraphicsBlurEffect> #include<QTimer> #include<QPushButton> #include<QGraphicsProxyWidget> #include<QApplication> #include<QLabel> #include<QFileInfo> static const qreal INITSSPEED = 500;//游戲的初始化速度 MyView::MyView(QWidget *parent) { init_view(); } void MyView::start_game() { game_welcome_text->hide(); start_button->hide(); option_button->hide(); help_button->hide(); exit_button->hide(); mask_widget->hide(); init_game(); } void MyView::clear_full_rows() { for(int y = 429; y > 50; y -= 20) { //每隔20行取一個(gè)item出來(lái),括號(hào)里面的參數(shù)不能弄錯(cuò),否則沒(méi)有方塊消失的效果 QList<QGraphicsItem *> list = scene()->items(199, y, 202, 22, Qt::ContainsItemShape,Qt::DescendingOrder);//返回指定區(qū)域內(nèi)所有可見(jiàn)的item if(list.count() == 10) { //如果一行已滿(mǎn),則銷(xiāo)毀該行的所有小方塊 foreach(QGraphicsItem *item, list) { OneBox *box = (OneBox *) item; // box->deleteLater(); //先為小方塊使用了模糊圖形效果,然后為其添加了放大再縮小的屬性動(dòng)畫(huà),等動(dòng)畫(huà)指定結(jié)束后才調(diào)用deleteLater()槽 QGraphicsBlurEffect *blurEffect = new QGraphicsBlurEffect; box->setGraphicsEffect(blurEffect); QPropertyAnimation *animation = new QPropertyAnimation(box,"scale"); animation->setEasingCurve(QEasingCurve::OutBounce); animation->setDuration(250); animation->setStartValue(4); animation->setEndValue(0.25); animation->start(QAbstractAnimation::DeleteWhenStopped); //connect(animation,SIGNAL(finished()),box,SLOT(deleteLater())); connect(animation,&QPropertyAnimation::finished,box,&OneBox::deleteLater); } rows << y;//將滿(mǎn)行的行號(hào)保存到rows中 } } //如果滿(mǎn)行,則下移上面的方塊 if(rows.count()>0) { // move_box(); QTimer::singleShot(400,this,SLOT(move_box())); } else { //沒(méi)有滿(mǎn)行,則新出現(xiàn)提示方塊,且提示方塊出更新新的提示方塊 box_group->create_box(QPointF(300, 70), next_box_group->getCurrentShape()); next_box_group->clear_box_group(true); next_box_group->create_box(QPointF(500, 70));// } } void MyView::move_box() { for(int i = rows.count(); i > 0; --i) { int row = rows.at(i-1);//取出滿(mǎn)行的行號(hào),從最上面的位置開(kāi)始 //取出從區(qū)域上邊界到當(dāng)前滿(mǎn)行之間所形成的矩形區(qū)域 foreach(QGraphicsItem *item, scene()->items(199, 49, 202, row-47, Qt::ContainsItemShape,Qt::DescendingOrder)) { item->moveBy(0, 20); } } //更新分?jǐn)?shù) update_score(rows.count()); //出現(xiàn)新的方塊組 rows.clear(); box_group->create_box(QPointF(300, 70), next_box_group->getCurrentShape()); next_box_group->clear_box_group(true); next_box_group->create_box(QPoint(500, 70)); } void MyView::game_over() { //游戲結(jié)束 pause_button->hide(); show_menu_button->hide(); mask_widget->show(); game_over_text->show(); restart_button->setPos(370, 200); finish_button->show(); } void MyView::restartGame() { mask_widget->hide(); game_over_text->hide(); finish_button->hide(); restart_button->setPos(600, 150); //銷(xiāo)毀當(dāng)前方塊組和當(dāng)前方塊中的所有小方塊 next_box_group->clear_box_group(true); box_group->clear_box_group(); box_group->hide(); foreach(QGraphicsItem *item, scene()->items(199, 49, 202, 402,Qt::ContainsItemBoundingRect,Qt::DescendingOrder)) { scene()->removeItem(item); OneBox *box = (OneBox*)item; box->deleteLater(); } init_game(); } void MyView::finishGame() { game_over_text->hide(); finish_button->hide(); restart_button->setPos(600, 150); restart_button->hide(); pause_button->hide(); show_menu_button->hide(); gameScoreText->hide(); gameLevelText->hide(); top_line->hide(); bottom_line->hide(); left_line->hide(); right_line->hide(); next_box_group->clear_box_group(true); box_group->clear_box_group(); box_group->hide(); foreach(QGraphicsItem *item, scene()->items(199, 49, 202, 402,Qt::ContainsItemBoundingRect,Qt::DescendingOrder)) { scene()->removeItem(item); OneBox *box = (OneBox*)item; box->deleteLater(); } mask_widget->show(); game_welcome_text->show(); start_button->show(); option_button->show(); help_button->show(); exit_button->show(); scene()->setBackgroundBrush(QPixmap(":/images/background.png")); } void MyView::pauseGame() { box_group->stop_timer();//中斷游戲最主要的是停止方塊下移的定時(shí)器工作 restart_button->hide(); pause_button->hide(); show_menu_button->hide(); mask_widget->show(); game_pause_text->show(); return_button->show(); } void MyView::returnGame() { return_button->hide(); game_pause_text->hide(); mask_widget->hide(); restart_button->show(); pause_button->show(); show_menu_button->show(); box_group->startTimer(game_speed); } void MyView::init_view() { setRenderHint(QPainter::Antialiasing);//使用抗鋸齒的方式渲染 setCacheMode(CacheBackground);//設(shè)置緩存背景,這樣可以加快渲染速度 setWindowTitle(tr("Teris游戲")); setWindowIcon(QIcon(":/images/icon.png"));//設(shè)置標(biāo)題處的圖標(biāo) setMinimumSize(810, 510); //2者設(shè)置成一樣說(shuō)明視圖尺寸不能再更改 setMaximumSize(810, 510); QGraphicsScene *scene = new QGraphicsScene;//新建場(chǎng)景指針 scene->setSceneRect(5, 5, 800, 500);//場(chǎng)景大小 scene->setBackgroundBrush(QPixmap(":/images/background.png")); setScene(scene);//設(shè)置場(chǎng)景 //俄羅斯方塊可移動(dòng)區(qū)域外界的4條線(xiàn),與外界預(yù)留3個(gè)像素是為了方便進(jìn)行碰撞檢測(cè) top_line = scene->addLine(197, 27, 403, 27); bottom_line = scene->addLine(197, 453, 403, 453); left_line = scene->addLine(197, 27, 197, 453); right_line = scene->addLine(403, 27, 403, 453); //添加當(dāng)前方塊組 box_group = new BoxGroup;//通過(guò)新建BoxGroup對(duì)象間接達(dá)到調(diào)用box的2個(gè)類(lèi) connect(box_group, SIGNAL(need_new_box()), this, SLOT(clear_full_rows())); connect(box_group, SIGNAL(game_finished()), this, SLOT(game_over())); scene->addItem(box_group); //添加提示方塊組 next_box_group = new BoxGroup; scene->addItem(next_box_group); gameScoreText = new QGraphicsTextItem();//文本的父item為對(duì)應(yīng)的場(chǎng)景 gameScoreText->setFont(QFont("Times", 50, QFont::Bold));//為文本設(shè)置字體 gameScoreText->setPos(450, 350);//分?jǐn)?shù)在場(chǎng)景中出現(xiàn)的位置 gameLevelText = new QGraphicsTextItem(); gameLevelText->setFont(QFont("Times", 50, QFont::Bold)); gameLevelText->setPos(20, 150); scene->addItem(gameLevelText); scene->addItem(gameScoreText); //開(kāi)始游戲 //start_game(); //設(shè)置初始為隱藏狀態(tài) top_line->hide(); bottom_line->hide(); left_line->hide(); right_line->hide(); gameScoreText->hide(); gameLevelText->hide(); //黑色遮罩 QWidget *mask = new QWidget; mask->setAutoFillBackground(true); mask->setPalette(QPalette(QColor(0, 0, 0, 50)));//alpha為不透明度 mask->resize(900, 600); //addWidget()函數(shù)的返回值是QGraphicsProxyWidget,如果不添加相應(yīng)的頭文件,則此處會(huì)報(bào)錯(cuò) mask_widget = scene->addWidget(mask); mask_widget->setPos(-50, -50); mask_widget->setZValue(1);//該層薄紗放在原圖的上面,這里有點(diǎn)類(lèi)似于opengl中的3維繪圖 //選項(xiàng)面板 QWidget *option = new QWidget; //將關(guān)閉按鈕放在option上 QPushButton *option_close_button = new QPushButton(tr("關(guān) 閉"), option);//第2個(gè)參數(shù)為按鈕所在的widget //設(shè)置按鈕的字體顏色是白色 QPalette palette; palette.setColor(QPalette::ButtonText, Qt::black);//第一個(gè)參數(shù)調(diào)色版的role,這里指的是按鈕字體顏色 option_close_button->setPalette(palette); //設(shè)置關(guān)閉按鈕的位置,和單擊后的響應(yīng) option_close_button->move(120, 300); connect(option_close_button, SIGNAL(clicked()), option, SLOT(hide()));//單擊后消失 option->setAutoFillBackground(true); option->setPalette(QPalette(QColor(0, 0, 0, 180))); option->resize(300, 400); QGraphicsWidget *option_widget = scene->addWidget(option); option_widget->setPos(250, 50); option_widget->setZValue(3); option_widget->hide(); //幫助面板 QWidget *help = new QWidget; QPushButton *help_close_button = new QPushButton(tr("幫 助"), help); help_close_button->setPalette(palette); help_close_button->move(120, 300); connect(help_close_button, SIGNAL(clicked()), help, SLOT(hide())); help->setAutoFillBackground(true); help->setPalette(QPalette(QColor(0, 0, 0, 180))); help->resize(300, 400); QGraphicsWidget *help_widget = scene->addWidget(help); help_widget->setPos(250, 50); help_widget->setZValue(3); help_widget->hide(); //游戲歡迎文本 game_welcome_text = new QGraphicsTextItem();//第一個(gè)參數(shù)為文本內(nèi)容,第二個(gè)參數(shù)為父item game_welcome_text->setHtml(tr("<font color=green>Tetris游戲</font>")); game_welcome_text->setFont(QFont("Times", 40, QFont::Bold)); game_welcome_text->setPos(300, 100); game_welcome_text->setZValue(2);//放在第2層 //游戲暫停文本 game_pause_text = new QGraphicsTextItem();//第一個(gè)參數(shù)為文本內(nèi)容,第二個(gè)參數(shù)為父item game_pause_text->setHtml(tr("<font color=green>游戲暫停中!</font>")); game_pause_text->setFont(QFont("Times", 40, QFont::Bold)); game_pause_text->setPos(300, 100); game_pause_text->setZValue(2);//放在第2層 game_pause_text->hide(); //游戲結(jié)束文本 game_over_text = new QGraphicsTextItem();//第一個(gè)參數(shù)為文本內(nèi)容,第二個(gè)參數(shù)為父item game_over_text->setHtml(tr("<font color=green>GAME OVER!</font>")); game_over_text->setFont(QFont("Times", 40, QFont::Bold)); game_over_text->setPos(300, 100); game_over_text->setZValue(2);//放在第2層 game_over_text->hide(); scene->addItem(game_welcome_text); scene->addItem(game_pause_text); scene->addItem(game_over_text); // 游戲中使用的按鈕 QPushButton *button1 = new QPushButton(tr("開(kāi) 始")); QPushButton *button2 = new QPushButton(tr("選 項(xiàng)")); QPushButton *button3 = new QPushButton(tr("幫 助")); QPushButton *button4 = new QPushButton(tr("退 出")); QPushButton *button5 = new QPushButton(tr("重新開(kāi)始")); QPushButton *button6 = new QPushButton(tr("暫 停")); QPushButton *button7 = new QPushButton(tr("主 菜 單")); QPushButton *button8 = new QPushButton(tr("返回游戲")); QPushButton *button9 = new QPushButton(tr("結(jié)束游戲")); connect(button1, SIGNAL(clicked()), this, SLOT(start_game())); connect(button2, SIGNAL(clicked()), option, SLOT(show())); connect(button3, SIGNAL(clicked()), help, SLOT(show())); connect(button4, SIGNAL(clicked()), qApp, SLOT(quit()));//此處槽函數(shù)的接收對(duì)象為應(yīng)用程序本身 connect(button5, SIGNAL(clicked()), this, SLOT(restartGame())); connect(button6, SIGNAL(clicked()), this, SLOT(pauseGame())); connect(button7, SIGNAL(clicked()), this, SLOT(show_menu_button())); connect(button8, SIGNAL(clicked()), this, SLOT(returnGame()));//返回主菜單 connect(button9, SIGNAL(clicked()), this, SLOT(finishGame())); start_button = scene->addWidget(button1);//restart_button并不是QPushbutton類(lèi)型,而是QGraphicsItem類(lèi)型,后面的類(lèi)似 option_button = scene->addWidget(button2); help_button = scene->addWidget(button3); exit_button = scene->addWidget(button4); restart_button = scene->addWidget(button5); pause_button = scene->addWidget(button6); show_menu_button = scene->addWidget(button7); return_button = scene->addWidget(button8); finish_button = scene->addWidget(button9); //設(shè)置位置 start_button->setPos(370, 200); option_button->setPos(370, 250); help_button->setPos(370, 300); exit_button->setPos(370, 350); restart_button->setPos(600, 150); pause_button->setPos(600, 200); show_menu_button->setPos(600, 250); return_button->setPos(370, 200); finish_button->setPos(370, 250); //將這些按鈕都放在z方向的第二層 start_button->setZValue(2); option_button->setZValue(2); help_button->setZValue(2); exit_button->setZValue(2); restart_button->setZValue(2); return_button->setZValue(2); finish_button->setZValue(2); //一部分按鈕隱藏起來(lái) restart_button->hide(); finish_button->hide(); pause_button->hide(); show_menu_button->hide(); return_button->hide(); } void MyView::init_game() { box_group->create_box(QPointF(300, 70)); //創(chuàng)建方塊組,在中間位置處出現(xiàn) box_group->setFocus();//設(shè)置人機(jī)交互焦點(diǎn),這樣就可以使用鍵盤(pán)來(lái)控制它 box_group->startTimer(INITSSPEED);//啟動(dòng)定時(shí)器 game_speed = INITSSPEED;//游戲速度,暫停時(shí)需要用到 next_box_group->create_box(QPoint(500, 70));//創(chuàng)建提示方塊組 scene()->setBackgroundBrush(QPixmap(":/images/background01.png")); gameScoreText->setHtml(tr("<font color=red>00</font>")); gameLevelText->setHtml(tr("<font color=white>第<br>一<br>幕</font>")); restart_button->show(); pause_button->show(); show_menu_button->show(); gameScoreText->show(); gameLevelText->show(); top_line->show(); bottom_line->show(); left_line->show(); right_line->show(); // 可能以前返回主菜單時(shí)隱藏了boxGroup box_group->show(); } void MyView::update_score(const int full_row_num) { //更新分?jǐn)?shù) int score = full_row_num *100; int currentScore =gameScoreText->toPlainText().toInt(); currentScore+=score; //顯示當(dāng)前分?jǐn)?shù) gameScoreText->setHtml(tr("<font color=red>%1</font>").arg(currentScore)); //判斷級(jí)別 if(currentScore<500) { //第一級(jí),什么都不用做 } else if(currentScore <1000) { //第二級(jí) gameLevelText->setHtml(tr("<font color=white>第<br>二<br>幕</font>")); scene()->setBackgroundBrush(QPixmap(":/images/background02.png")); game_speed =300; box_group->stop_timer(); box_group->startTimer(game_speed); } else { //添加下一個(gè)級(jí)別的設(shè)置 } }
main.cpp
#include<QApplication> #include"myview.h" #include<QTextCodec> #include<QTime> int main(int argc, char* argv[]) { QApplication app(argc, argv); QTextCodec::setCodecForLocale(QTextCodec::codecForLocale()); //QTime提供了鬧鐘功能 qsrand(QTime(0, 0, 0).secsTo(QTime::currentTime()));//secsTo()為返回當(dāng)前的秒數(shù) MyView view;//主函數(shù)是直接調(diào)用的視圖類(lèi) view.show(); return app.exec(); }
以上就是關(guān)于“Qt怎么實(shí)現(xiàn)方塊游戲”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對(duì)大家有幫助,若想了解更多相關(guān)的知識(shí)內(nèi)容,請(qǐng)關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。