?? qt教程一 —— 第十三章:游戲結束.htm
字號:
<A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qpainter.html">QPainter</A> p( this );
if ( gameEnded ) {
p.<A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qpainter.html#setPen">setPen</A>( black );
<A name=x2335></A> p.<A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qpainter.html#setFont">setFont</A>( QFont( "Courier", 48, QFont::Bold ) );
<A name=x2334></A> p.<A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qpainter.html#drawText">drawText</A>( <A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qwidget.html#rect">rect</A>(), AlignCenter, "Game Over" );
}
</PRE>
<P>繪畫事件已經通過如果游戲結束,比如<TT>gameEnded</TT>是TRUE,就顯示文本“Game
Over”而被增強了。我們在這里不怕麻煩來檢查更新矩形,是因為在游戲結束的時候速度不是關鍵性的。
<P>為了畫文本,我們先設置了黑色的畫筆,當畫文本的時候,畫筆顏色會被用到。接下來我們選擇Courier字體中的48號加粗字體。最后我們在窗口部件的矩形中央繪制文本。不幸的是,在一些系統中(特別是使用Unicode的X服務器)它會用一小段時間來載入如此大的字體。因為Qt緩存字體,我們只有第一次使用這個字體的時候才會注意到這一點。
<P><PRE> <A name=x2338></A> if ( updateR.<A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qrect.html#intersects">intersects</A>( cannonRect() ) )
paintCannon( &p );
if ( isShooting() && updateR.<A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qrect.html#intersects">intersects</A>( shotRect() ) )
paintShot( &p );
if ( !gameEnded && updateR.<A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qrect.html#intersects">intersects</A>( targetRect() ) )
paintTarget( &p );
}
</PRE>
<P>我們只有在設計的時候畫炮彈,在玩游戲的時候畫目標(這也就是說,當游戲沒有結束的時候)。
<P>
<H3><A
href="http://www.qtopia.org.cn/doc/qiliang.net/qt/t13-gamebrd-h.html">t13/gamebrd.h</A>
</H3><A name=1-5></A>
<P>這個文件是新的。它包含最后被用來作為MyWidget的GameBoard類的定義。
<P>
<P><PRE> class QPushButton;
class LCDRange;
class QLCDNumber;
class CannonField;
#include "lcdrange.h"
#include "cannon.h"
class GameBoard : public <A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qwidget.html">QWidget</A>
{
<A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/metaobjects.html#Q_OBJECT">Q_OBJECT</A>
public:
GameBoard( <A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qwidget.html">QWidget</A> *parent=0, const char *name=0 );
protected slots:
void fire();
void hit();
void missed();
void newGame();
private:
<A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qlcdnumber.html">QLCDNumber</A> *hits;
<A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qlcdnumber.html">QLCDNumber</A> *shotsLeft;
CannonField *cannonField;
};
</PRE>
<P>我們現在已經添加了四個槽。這些槽都是被保護的,只在內部使用。我們也已經加入了兩個QLCDNumbers(<TT>hits</TT>和<TT>shotsLeft</TT>)用來顯示游戲的狀態。
<P>
<H3><A
href="http://www.qtopia.org.cn/doc/qiliang.net/qt/t13-gamebrd-cpp.html">t13/gamebrd.cpp</A>
</H3><A name=1-6></A>
<P>這個文件是新的。它包含最后被用來作為MyWidget的GameBoard類的實現,
<P>
<P>我們已經在GameBoard的構造函數中做了一些修改。
<P><PRE> cannonField = new CannonField( this, "cannonField" );
</PRE>
<P><TT>cannonField</TT>現在是一個成員變量,所以我們在使用它的時候要小心地改變它的構造函數。(Trolltech的<EM>好</EM>程序員從來不會忘記這點,但是我就忘了。告誡程序員-如果“programmor”是拉丁語,至少。無論如何,返回代碼。)
<P><PRE> <A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qobject.html#connect">connect</A>( cannonField, SIGNAL(hit()),
this, SLOT(hit()) );
<A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qobject.html#connect">connect</A>( cannonField, SIGNAL(missed()),
this, SLOT(missed()) );
</PRE>
<P>這次當炮彈射中或者射失目標的時候,我們想做些事情。所以我們把CannonField的hit()和missed()信號連接到這個類的兩個被保護的同名槽。
<P><PRE> <A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qobject.html#connect">connect</A>( shoot, SIGNAL(<A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qbutton.html#clicked">clicked</A>()), SLOT(fire()) );
</PRE>
<P>以前我們直接把Shoot按鈕的clicked()信號連接到CannonField的shoot()槽。這次我們想跟蹤射擊的次數,所以我們把它改為連接到這個類里面一個被保護的槽。
<P>注意當你用獨立的組件工作的時候,改變程序的行為是多么的容易。
<P><PRE> <A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qobject.html#connect">connect</A>( cannonField, SIGNAL(canShoot(bool)),
<A name=x2348></A> shoot, SLOT(<A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qwidget.html#setEnabled">setEnabled</A>(bool)) );
</PRE>
<P>我們也使用cannonField的canShoot()信號來適當地使Shoot按鈕生效和失效。
<P><PRE> QPushButton *restart
= new <A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qpushbutton.html">QPushButton</A>( "&New Game", this, "newgame" );
restart->setFont( QFont( "Times", 18, QFont::Bold ) );
<A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qobject.html#connect">connect</A>( restart, SIGNAL(clicked()), this, SLOT(newGame()) );
</PRE>
<P>我們創建、設置并且連接這個New Game按鈕就像我們對其它按鈕所做的一樣。點擊這個按鈕就會激活這個窗口部件的newGame()槽。
<P><PRE> hits = new <A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qlcdnumber.html">QLCDNumber</A>( 2, this, "hits" );
shotsLeft = new <A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qlcdnumber.html">QLCDNumber</A>( 2, this, "shotsleft" );
<A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qlabel.html">QLabel</A> *hitsL = new <A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qlabel.html">QLabel</A>( "HITS", this, "hitsLabel" );
QLabel *shotsLeftL
= new <A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qlabel.html">QLabel</A>( "SHOTS LEFT", this, "shotsleftLabel" );
</PRE>
<P>我們創建了四個新的窗口部件。注意我們不怕麻煩的把<A
href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qlabel.html">QLabel</A>窗口部件的指針保留到GameBoard類中是因為我們不想再對它們做什么了。當GameBoard窗口部件被銷毀的時候,Qt將會刪除它們,并且布局類會適當地重新定義它們的大小。
<P><PRE> <A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qhboxlayout.html">QHBoxLayout</A> *topBox = new <A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qhboxlayout.html">QHBoxLayout</A>;
<A name=x2345></A> grid-><A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qgridlayout.html#addLayout">addLayout</A>( topBox, 0, 1 );
topBox-><A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qboxlayout.html#addWidget">addWidget</A>( shoot );
topBox-><A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qboxlayout.html#addWidget">addWidget</A>( hits );
topBox-><A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qboxlayout.html#addWidget">addWidget</A>( hitsL );
topBox-><A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qboxlayout.html#addWidget">addWidget</A>( shotsLeft );
topBox-><A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qboxlayout.html#addWidget">addWidget</A>( shotsLeftL );
<A name=x2342></A> topBox-><A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qboxlayout.html#addStretch">addStretch</A>( 1 );
<A name=x2343></A> topBox-><A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qboxlayout.html#addWidget">addWidget</A>( restart );
</PRE>
<P>右上單元格的窗口部件的數量正在變大。從前它是空的,現在它是完全充足的,我們把它們放到布局中來更好的看到它們。
<P>注意我們讓所有的窗口部件獲得它們更喜歡的大小,改為在New Game按鈕的左邊加入了一個可以自由伸展的東西。
<P><PRE> newGame();
}
</PRE>
<P>我們已經做完了所有關于GameBoard的構造,所以我們使用newGame()來開始。(newGame()是一個槽,但是就像我們所說的,槽也可以像普通的函數一樣使用。)
<P><PRE> void GameBoard::fire()
{
if ( cannonField->gameOver() || cannonField->isShooting() )
return;
shotsLeft-><A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qlcdnumber.html#display">display</A>( shotsLeft-><A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qlcdnumber.html#intValue">intValue</A>() - 1 );
cannonField->shoot();
}
</PRE>
<P>這個函數進行射擊。如果游戲結束了或者還有一個炮彈在空中,我們立即返回。我們減少炮彈的數量并告訴加農炮進行射擊。
<P><PRE> void GameBoard::hit()
{
hits-><A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qlcdnumber.html#display">display</A>( hits-><A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qlcdnumber.html#intValue">intValue</A>() + 1 );
if ( shotsLeft-><A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qlcdnumber.html#intValue">intValue</A>() == 0 )
cannonField->setGameOver();
else
cannonField->newTarget();
}
</PRE>
<P>當炮彈擊中目標的時候這個槽被激活。我們增加射中的數量。如果沒有炮彈了,游戲就結束了。否則,我們會讓CannonField生成新的目標。
<P><PRE> void GameBoard::missed()
{
<A name=x2347></A> if ( shotsLeft-><A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qlcdnumber.html#intValue">intValue</A>() == 0 )
cannonField->setGameOver();
}
</PRE>
<P>當炮彈射失目標的時候這個槽被激活,如果沒有炮彈了,游戲就結束了。
<P><PRE> void GameBoard::newGame()
{
<A name=x2346></A> shotsLeft-><A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qlcdnumber.html#display">display</A>( 15 );
hits-><A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/qlcdnumber.html#display">display</A>( 0 );
cannonField->restartGame();
cannonField->newTarget();
}
</PRE>
<P>當用戶點擊Restart按鈕的時候這個槽被激活。它也會被構造函數調用。首先它把炮彈的數量設置為15。注意這里是我們在程序中唯一設置炮彈數量的地方。把它改變為你所想要的游戲規則。接下來我們重置射中的數量,重新開始游戲,并且生成一個新的目標。
<P>
<H3><A
href="http://www.qtopia.org.cn/doc/qiliang.net/qt/t13-main-cpp.html">t13/main.cpp</A>
</H3><A name=1-7></A>
<P>這個文件僅僅被刪掉了一部分。MyWidget沒了,并且唯一剩下的是main()函數,除了名稱的改變其它都沒有改變。
<P>
<H2>行為 </H2><A name=2></A>
<P>射中的和剩余炮彈的數量被顯示并且程序繼續跟蹤它們。游戲可以結束了,并且還有一個按鈕可以開始一個新游戲。
<P>(請看<A
href="http://www.qtopia.org.cn/doc/qiliang.net/qt/tutorial1-07.html#compiling">編譯</A>來學習如何創建一個makefile和連編應用程序。)
<P>
<H2>練習 </H2><A name=3></A>
<P>添加一個隨機的風的因素并把它顯示給用戶看。
<P>當炮彈擊中目標的時候做一些飛濺的效果。
<P>實現多個目標。
<P>現在你可以進行<A
href="http://www.qtopia.org.cn/doc/qiliang.net/qt/tutorial1-14.html">第十四章</A>了。
<P>[<A
href="http://www.qtopia.org.cn/doc/qiliang.net/qt/tutorial1-12.html">上一章</A>]
[<A
href="http://www.qtopia.org.cn/doc/qiliang.net/qt/tutorial1-14.html">下一章</A>]
[<A href="http://www.qtopia.org.cn/doc/qiliang.net/qt/tutorial.html">教程一主頁</A>]
<P><!-- eof -->
<P>
<ADDRESS>
<HR>
<DIV align=center>
<TABLE cellSpacing=0 width="100%" border=0>
<TBODY>
<TR>
<TD>Copyright © 2002 <A href="http://www.trolltech.com/">Trolltech</A>
<TD><A href="http://www.trolltech.com/trademarks.html">Trademarks</A>
<TD><A
href="http://www.qtopia.org.cn/doc/qiliang.net/qt/zh_CN.html">譯者:Cavendish</A>
<TD align=right>
<DIV align=right>Qt
3.0.5版</DIV></TR></TBODY></TABLE></DIV></ADDRESS></BODY></HTML>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -