1. 程式人生 > >QT學習(六)QT之貪吃蛇

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.  }