<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                #(31):貪吃蛇游戲(1) 經過前面一段時間的學習,我們已經了解到有關 Qt 相當多的知識。現在,我們將把前面所講過的知識綜合起來,開發一個貪吃蛇游戲。游戲很簡單,相信大家都有見過,多多少少也都玩過。我們在實現這個貪吃蛇游戲時,會利用到事件系統、Graphics View Framework、QPainter 等相關內容,也會了解到一個游戲所具有的一些特性,比如游戲循環等,在 Qt 中如何體現出來。當然,最重要的是,通過一個相對較大的程序,學習到如何將之前的點點滴滴結合在一起。 本部分的代碼出自:[http://qtcollege.co.il/developing-a-qt-snake-game/](http://qtcollege.co.il/developing-a-qt-snake-game/),但是有一些基于軟件工程方面考慮的修改,例如常量放置的位置等。 前面說過,Qt 提供了自己的繪制系統,還提供了 Graphics View Framework。很明顯,繪制圖形和移動圖形,是一個游戲的核心。對于游戲而言,將其中的每一個部分看做對象是非常合理的,也是相當有成效的。因此,我們選擇 Graphics View Framework 作為核心框架。回憶一下,這個框架具有一系列面向對象的特性,能夠讓我們將一個個圖形作為對象進行處理。同時,Graphics View Framework 的性能很好,即便是數千上萬的圖形也沒有壓力。這一點非常適合于游戲。 正如我們前面所說,Graphics View Framework 有三個主要部分: * `QGraphicsScene`:能夠管理元素的非 GUI 容器; * `QGraphicsItem`:能夠被添加到場景的元素; * `QGraphicsView`:能夠觀察場景的可視化組件視圖。 對于游戲而言,我們需要一個`QGraphicsScene`,作為游戲發生的舞臺;一個`QGraphicsView`,作為觀察游戲舞臺的組件;以及若干元素,用于表示游戲對象,比如蛇、食物以及障礙物等。 大致分析過游戲組成以及各部分的實現方式后,我們可以開始編碼了。這當然是一個 GUI 工程,主窗口應該是一個`QGraphicsView`。為了以后的實現方便(比如,我們希望向工具欄添加按鈕等),我們不會直接以`QGraphicsView`作為頂層窗口,而是將其添加到一個主窗口上。這里,我們不會使用 QtDesigner 進行界面設計,而是直接編碼完成(**注意,我們這里的代碼并不一定能夠通過編譯,因為會牽扯到其后幾章的內容,因此,如果需要編譯代碼,請在全部代碼講解完畢之后進行**): ~~~ #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> class QGraphicsScene; class QGraphicsView; class GameController; class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = 0); ~MainWindow(); private slots: void adjustViewSize(); private: void initScene(); void initSceneBackground(); QGraphicsScene *scene; QGraphicsView *view; GameController *game; }; #endif // MAINWINDOW_H ~~~ 在頭文件中聲明了`MainWindow`。構造函數除了初始化成員變量,還設置了窗口的大小,并且需要對場景進行初始化: ~~~ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), scene(new QGraphicsScene(this)), view(new QGraphicsView(scene, this)), game(new GameController(*scene, this)) { setCentralWidget(view); resize(600, 600); initScene(); initSceneBackground(); QTimer::singleShot(0, this, SLOT(adjustViewSize())); } ~~~ 值得說明的是最后一行代碼。`singleShot()`函數原型如下: ~~~ static void QTimer::singleShot(int msec, QObject * receiver, const char * member); ~~~ 該函數接受三個參數,簡單來說,它的作用是,在 msec 毫秒之后,調用 receiver 的 member?**槽函數**。在我們的代碼中,第一個參數傳遞的是 0,也就是 0ms 之后,調用`this->adjustViewSize()`。這與直接調用`this->adjustViewSize();`有什么區別呢?如果你看文檔,這一段的解釋很隱晦。文檔中寫到:“It is very convenient to use this function because you do not need to bother with a timerEvent or create a local QTimer object”,也就是說,它的作用是方便使用,無需重寫`timerEvent()`函數或者是創建一個局部的`QTimer`對象。當我們使用`QTimer::signleShot(0, ...)`的時候,實際上也是對`QTimer`的簡化,而不是簡單地函數調用。`QTimer`的處理是將其放到事件列表中,等到下一次事件循環開始時去調用這個函數。那么,`QTimer::signleShot(0, ...)`意思是,在下一次事件循環開始時,立刻調用指定的槽函數。在我們的例子中,我們需要在視圖繪制完畢后才去改變大小(視圖繪制當然是在`paintEvent()`事件中),因此我們需要在下一次事件循環中調用`adjustViewSize()`函數。這就是為什么我們需要用`QTimer`而不是直接調用`adjustViewSize()`。如果熟悉 flash,這相當于 flash 里面的`callLater()`函數。接下來看看`initScene()`和`initSceneBackground()`的代碼: ~~~ void MainWindow::initScene() { scene->setSceneRect(-100, -100, 200, 200); } void MainWindow::initSceneBackground() { QPixmap bg(TILE_SIZE, TILE_SIZE); QPainter p(&bg); p.setBrush(QBrush(Qt::gray)); p.drawRect(0, 0, TILE_SIZE, TILE_SIZE); view->setBackgroundBrush(QBrush(bg)); } ~~~ `initScene()`函數設置場景的范圍,是左上角在 (-100, -100),長和寬都是 200px 的矩形。默認情況下,場景是無限大的,我們代碼的作用是設置了一個有限的范圍。Graphics View Framework 為每一個元素維護三個不同的坐標系:場景坐標,元素自己的坐標以及其相對于父組件的坐標。除了元素在場景中的位置,其它幾乎所有位置都是相對于元素坐標系的。所以,我們選擇的矩形 (-100, -100, 200, 200),實際是設置了場景的坐標系。此時,如果一個元素坐標是 (-100, -100),那么它將出現在場景左上角,(100, 100) 的坐標則是在右下角。 `initSceneBackground()`函數看似很長,實際卻很簡單。首先我們創建一個邊長`TILE_SIZE`的`QPixmap`,將其使用灰色填充矩形。我們沒有設置邊框顏色,默認就是黑色。然后將這個`QPixmap`作為背景畫刷,鋪滿整個視圖。 現在我們的程序看起來是這樣的: [![](https://box.kancloud.cn/2015-12-29_5682325592af7.png)](http://files.devbean.net/images/2012/12/snake-scene.png) 在后面的章節中,我們將繼續我們的游戲之旅。下一章,我們開始創建游戲對象。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看