QT學習(六)QT之貪吃蛇
1、開始介面
對話方塊設定:設定對話方塊控制元件以及標題
1. GameStart::GameStart(QDialog*parent)
2. :QDialog(parent)
3. {
4.
5. createWidgets();
6. setWindowTitle(tr("Snake"));
7. }
設定3個按鈕,連線三種操作:開始遊戲,獲得歷史排名,結束遊戲。
8. beginGame=newQPushButton(tr("start"));
9. beginGame->setFixedSize(120,30);
10. beginGame->setFont(font);
11. connect(beginGame,SIGNAL(clicked()),this,SLOT(startGame()));
12.
13. endGame=newQPushButton(tr("end"));
14. endGame->setFixedSize(120,30);
15. endGame->setFont(font);
16. connect(endGame,SIGNAL(clicked()),this,SLOT(close()));
17.
18. GameRank=newQPushButton(tr("rank"));
19. GameRank->setFixedSize(120,30);
20. GameRank->setFont(font);
21. connect(GameRank,SIGNAL(clicked()),this,SLOT(loadRank()));
設定遊戲等級選項,含有3個等級。
22. GameLevelCombo=newQComboBox(this);
23. GameLevelCombo->setFixedSize(120,30);
24. GameLevelCombo->setFont(font);
25. GameLevelCombo->addItem(tr("elementary"));
26. GameLevelCombo->addItem(tr("intermediate"));
27. GameLevelCombo->addItem(tr("advanced"));
28. connect(GameLevelCombo,SIGNAL(activated(constQString&)),this,SLOT(getGameLevel()));
設定label和lineedit,用於輸入玩家姓名。
29. NameLabel=newQLabel(tr("player"));
30. NameLabel->setFixedSize(120,30);
31. NameLabel->setFont(font);
32. NameEdit=newQLineEdit;
33. NameEdit->setFixedSize(200,30);
34. connect(NameEdit,SIGNAL(textChanged(constQString&)),this,SLOT(setName()));
利用QTextEdit來顯示排名資訊。
35. RankText=newQTextEdit(this);
36. RankText->setStyleSheet("background:argb(248,248,255,0%)");
37. RankLabel=newQLabel(tr("showrank"));
38. RankLabel->setFixedSize(100,30);
39. RankLabel->setFont(font);
佈局:
40. QVBoxLayout*LeftLayout=newQVBoxLayout;
41. LeftLayout->addWidget(beginGame);
42. LeftLayout->addWidget(GameRank);
43. LeftLayout->addWidget(GameLevelCombo);
44. LeftLayout->addWidget(endGame);
45.
46. QVBoxLayout*RightLayout=newQVBoxLayout;
47. RightLayout->addWidget(RankLabel);
48. RightLayout->addWidget(RankText);
49.
50. QHBoxLayout*TopLayout=newQHBoxLayout;
51. TopLayout->addWidget(NameLabel);
52. TopLayout->addWidget(NameEdit);
53.
54.
55. QHBoxLayout*BelowLayout=newQHBoxLayout;
56. BelowLayout->addLayout(LeftLayout);
57. BelowLayout->addLayout(RightLayout);
58.
59. QVBoxLayout*MainLayout=newQVBoxLayout;
60. MainLayout->addLayout(TopLayout);
61. MainLayout->addLayout(BelowLayout);
62. setLayout(MainLayout);
玩家名字獲得、獲得排名資訊、產生遊戲等級的函式實現:
63. voidGameStart::setName(){
64. player=NameEdit->text();
65.
66. }
67.
68.
69. voidGameStart::getGameLevel(){
70. QStringLevelString=GameLevelCombo->currentText();
71. if(LevelString==tr("elementary"))
72. GameLevel=1;
73. elseif(LevelString==tr("intermediate"))
74. GameLevel=2;
75. elseif(LevelString==tr("advanced"))
76. GameLevel=3;
77. else
78. GameLevel=1;
79. }
80.
81.
82.
83.
84. voidGameStart::loadRank(){
85. QFilefile("H:/softprogramme/QTMySnaker/snake/Rank.txt");
86. if(!file.open(QFile::ReadOnly)){
87. QMessageBox::warning(this,tr("loadrank"),tr("cannotloadrankfile%1").arg(file.fileName()));
88. return;
89. }
90. QTextStreamin(&file);
91. RankText->setPlainText(in.readAll());
92.
93. }
對於遊戲介面調出,則要求能夠隱藏當前對話方塊,並且終止當前執行緒,而可以去執行遊戲介面的執行緒,那麼需要在遊戲介面重新實現一個執行函式exec()。
94. voidGameStart::startGame(){
95.
96. this->close();
97.
98. ImageShowImageShow_M1(player,GameLevel);
99. ImageShow_M1.exec();
100.
101. this->show();
102. this->exec();
103.
104.
105. }
如果僅僅是遊戲介面用show()函式,則遊戲介面不會產生控制元件,僅僅會出現一個主視窗。這就是模式和非模式顯示,模式不僅顯示介面而且會鎖定在這個介面上,從而執行操作。一般QDialog有自己的exec()函式,而QWidget沒有,這就需要在QWidget中實現一個。
2、遊戲介面
初始化、定義計時器:
106. ImageShow::ImageShow(constQStringplayer,constintgame_level):
107. player(player),game_level(game_level){
108.
109.
110. setWindowTitle(tr("InGame..."));
111. setFixedSize(ROWS+20,COLUMNS+50);
112. InitSnake();
113.
114. Timer=newQTimer(this);
115. connect(Timer,SIGNAL(timeout()),this,SLOT(timeout()));
116. Timer->start(1000/game_level);
117.
118. }
119. voidImageShow::InitSnake(){
120.
121. game_score=0;
122. IsOver=false;
123. direction=3;//right
124.
125. body_x=newvector<char>;
126. body_y=newvector<char>;
127.
128. for(inti=4;i>=1;i--){
129. body_x->push_back(1);
130. body_y->push_back(i);//初始化具有1個蛇頭和3個蛇身的蛇
131.
132. }
133. food_x=3;
134. food_y=5;
135.
136.
137. }
138. voidImageShow::timeout(){
139.
140. IsOver=walk();
141. if(IsOver==true){
142. Timer->stop();
143.
144.
145. intr=QMessageBox::warning(this,tr("saverank"),tr("gemeisover!\n"
146. "Doyouwanttosavethegameresults?"),
147. QMessageBox::Yes|QMessageBox::No);
148. if(r==QMessageBox::Yes)
149. saveRank();
150. return;
151. }
152.
153. update();
154.
155.
156. }
根據遊戲等級,產生了不同時間限定,時間到就會去執行蛇行走,然後再繪製圖像,通過呼叫了update函式實現繪製事件。
157. boolImageShow::walk(){
158.
159.
160.
161. switch(direction){
162. case1:{
163. body_x->insert(body_x->begin(),(*body_x)[0]);
164. body_x->pop_back();
165. body_y->insert(body_y->begin(),(*body_y)[0]-1);
166. body_y->pop_back();
167. break;
168. }//左移動
169. case2:{
170. body_x->insert(body_x->begin(),(*body_x)[0]-1);
171. body_x->pop_back();
172. body_y->insert(body_y->begin(),(*body_y)[0]);
173. body_y->pop_back();
174. break;
175. }//向上移動
176. case3:{
177. body_x->insert(body_x->begin(),(*body_x)[0]);
178. body_x->pop_back();
179. body_y->insert(body_y->begin(),(*body_y)[0]+1);
180. body_y->pop_back();
181. break;
182. }//向右移動
183. case4:{
184. body_x->insert(body_x->begin(),(*body_x)[0]+1);
185. body_x->pop_back();
186. body_y->insert(body_y->begin(),(*body_y)[0]);
187. body_y->pop_back();
188. break;
189. }//向下移動
190.
191. default:;
192.
193.
194. }
195.
196.
197. if(((*body_x)[0]==food_x)&&((*body_y)[0]==food_y)){
198. body_x->push_back(body_x->back());
199. body_y->push_back(body_y->back());
200. game_score++;
201. produce();
202. }//吃下食物
203.
204. if(((*body_x)[0]==0)||((*body_x)[0]==(ROWS/8))||((*body_y)[0]==0)||((*body_y)[0]==(COLUMNS/8))){
205.
206.
207. returntrue;//蛇撞牆,遊戲失敗
208.
209. }
210. returnfalse;
211.
212.
213.
214.
215. }
216. voidImageShow::paintEvent(QPaintEvent*){
217.
218. QPainter*painter=newQPainter(this);
219. painter->setRenderHint(QPainter::Antialiasing,true);
220.
221. QPenThinPen(palette().foreground(),1);
222.
223. QColorLightSlateBlue(132,112,255);
224. QPenThickPen(LightSlateBlue,4);
225.
226. painter->save();
227. painter->translate(10,40);
228. painter->setPen(ThickPen);
229. painter->setBrush(LightSlateBlue);
230. painter->drawLine(0,0,ROWS,0);
231. painter->drawLine(0,0,0,COLUMNS);
232. painter->drawLine(ROWS,0,ROWS,COLUMNS);
233. painter->drawLine(0,COLUMNS,ROWS,COLUMNS);
234.
235. painter->restore();
236.
237.
238. QColorbrown(255,64,64);
239. QPentextPen(brown,4);
240. painter->setPen(textPen);
241. QFontfont=painter->font();
242. font.setPixelSize(20);
243. painter->setFont(font);
244. constQRectrectangle1=QRect(50,2,150,25);
245. QRectboundingrect;
246. painter->drawText(rectangle1,0,player,&boundingrect);
247. constQRectrectangle2=QRect(130,2,150,25);
248. painter->drawText(rectangle2,0,tr("GameLevel:%1").arg(game_level),&boundingrect);
249. constQRectrectangle3=QRect(300,2,150,25);
250. painter->drawText(rectangle3,0,tr("gamescore:%1").arg(game_score),&boundingrect);
251.
252. painter->save();
253. painter->rotate(270);
254. painter->translate(-40,10);
255.
256. QPointFoodPoint(-food_x*8,food_y*8);
257.
258. QRadialGradientRadialGradient(-food_x*8,food_y*8,6,-food_x*8,food_y*8);
259. RadialGradient.setColorAt(0,Qt::green);
260. RadialGradient.setColorAt(1.0,Qt::darkGreen);
261. painter->setPen(Qt::NoPen);
262. painter->setBrush(RadialGradient);
263. painter->drawEllipse(FoodPoint,6,6);
264.
265. QPointSnakeHeadPoint(-8*((*body_x)[0]),8*((*body_y)[0]));
266. QConicalGradientConicalGradient(-8*((*body_x)[0]),8*((*body_y)[0]),270);
267. ConicalGradient.setColorAt(0,Qt::red);
268. ConicalGradient.setColorAt(1,Qt::darkRed);
269. painter->setPen(ThinPen);
270. painter->setBrush(ConicalGradient);
271. painter->drawEllipse(SnakeHeadPoint,5,5);
272.
273. QColorLightSalmon(255,160,122);
274. painter->setPen(ThinPen);
275. painter->setBrush(LightSalmon);
276.
277. for(inti=1;i<body_x->size();i++){
278. painter->drawRect(-8*((*body_x)[i])-4,8*((*body_y)[i])-4,8,8);
279.
280. }
281.
282. painter->restore();
283.
284.
285.
286.
287. }
對於蛇的移動和控制,通過過載keyPressEvent函式來實現。
288. voidImageShow::keyPressEvent(QKeyEvent*KeyEvent){
289.
290. switch(KeyEvent->key()){
291. caseQt::Key_Left:{direction=1;break;}
292. caseQt::Key_Up:{direction=2;break;}
293. caseQt::Key_Right:{direction=3;break;}
294. caseQt::Key_Down:{direction=4;break;}
295. default:break;
296. }
297.
298.
299. QWidget::keyPressEvent(KeyEvent);
300.
301. }
儲存遊戲結果,並且將原來遊戲歷史記錄根據得分高低排序。
302. voidImageShow::saveRank(){
303.
304. archivearchive_now;
305. archivearchive_history[10];
306. intarchive_num=0;
307.
308. stringPlayerString=player.toStdString();
309. strcpy(archive_now.player_temp,PlayerString.c_str());
310. archive_now.game_leve_temp=game_level;
311. archive_now.game_score_temp=game_score;
312.
313. QFileFile("H:/softprogramme/QTMySnaker/snake/Rank.txt");
314. if(!File.open(QIODevice::ReadWrite))
315. return;
316. QTextStreamInOut(&File);
317. while(!File.atEnd()){
318. QStringplayer_string;
319. InOut>>player_string>>archive_history[archive_num].game_leve_temp
320. >>archive_history[archive_num].game_score_temp;
321. stringPlayerString=player_string.toStdString();
322. strcpy(archive_history[archive_num].player_temp,PlayerString.c_str());
323. archive_num++;
324. }
325.
326.
327.
328.
329. for(inti=0;i<=archive_num;i++){
330.
331. if(archive_now.game_score_temp>archive_history[i].game_score_temp){
332. for(intj=archive_num;j>=i+1;j--){
333.
334. archive_history[j]=archive_history[j-1];
335. }
336. archive_history[i]=archive_now;
337. break;
338. }
339. elseif(i==archive_num){
340. archive_history[archive_num]=archive_now;
341. }
342.
343. }
344.
345. for(inti=0;i<=archive_num;i++){
346. InOut<<archive_history[i].player_temp<<'\t'
347. <<archive_history[i].game_leve_temp<<'\t'
348. <<archive_history[i].game_score_temp<<'\n';
349. }
350. File.close();
351.
352.
353. }
接下來就是如何讓這個介面能夠在開始介面點選開始後可以執行,通過利用一個QEventLoop,可以將執行鎖定住,然後為了退出迴圈,則可以通過關閉事件來呼叫其退出。
354. voidImageShow::exec(){
355.
356. this->show();
357. QEventLooploop;
358. m_loop=&loop;
359. loop.exec();
360.
361.
362. }
363.
364. voidImageShow::closeEvent(QCloseEvent*event){
365. this->hide();
366. m_loop->exit();
367. event->accept();
368.
369. }