最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用C++一步步實現(xiàn)俄羅斯方塊后續(xù)

 更新時間:2017年12月22日 09:07:57   作者:MCFON  
本文主要給大家分享的是作者在使用C++制作俄羅斯方塊小游戲的時候所需要的常用的函數(shù),有需要的小伙伴可以借鑒下,希望大家能夠喜歡。

一、實驗簡介

1.1 實驗內(nèi)容

本節(jié)實驗我們將實現(xiàn)俄羅斯方塊主要函數(shù)的設(shè)計,完成基本功能并運行。

1.2 實驗知識點

窗口的繪制
方塊類的設(shè)計
旋轉(zhuǎn)算法
移動、消除函數(shù)

1.3 實驗環(huán)境

xface 終端
g++ 編譯器
ncurses 庫

1.4 編譯程序

編譯命令要加上 -l 選項引入 ncurses 庫:

g++ main.c -l ncurses

1.5 運行程序

./a.out

1.6 運行結(jié)果


二、實驗步驟

2.1 頭文件

首先包含頭文件以及定義一個交換函數(shù)和隨機(jī)數(shù)函數(shù),后面用到(交換函數(shù)用來做方塊的旋轉(zhuǎn),隨機(jī)數(shù)用來設(shè)置方塊的形狀)

#include <iostream>
#include <sys/time.h>
#include <sys/types.h>
#include <stdlib.h>
#include <ncurses.h>
#include <unistd.h>

/* 交換a和b */
void swap(int &a, int &b){
 int t=a;
 a = b;
 b = t;
}

/* 得到一個(min,max)區(qū)間的隨機(jī)整數(shù)
int getrand(int min, int max)
{
 return(min+rand()%(max-min+1));
}

2.2 定義類

由于程序內(nèi)容相對簡單,這里只定義了一個 Piece 類

class Piece
 {
 public:
  int score;  //得分
  int shape;  //表示當(dāng)前方塊的形狀
  int next_shape;  //表示下一個方塊的形狀

  int head_x;  //當(dāng)前方塊首個box的位置,標(biāo)記位置
  int head_y;

  int size_h;  //當(dāng)前方塊的size
  int size_w;

  int next_size_h;  //下一個方塊的size
  int next_size_w;

  int box_shape[4][4]; //當(dāng)前方塊的shpe數(shù)組 4x4
  int next_box_shape[4][4];  //下一個方塊的shpe數(shù)組 4x4

  int box_map[30][45];  //用來標(biāo)記游戲框內(nèi)的每個box

  bool game_over;  //游戲結(jié)束的標(biāo)志

 public:
  void initial();  //初始化函數(shù)
  void set_shape(int &cshape, int box_shape[][4],int &size_w, int & size_h);  //設(shè)置方塊形狀

  void score_next();  //顯示下一個方塊的形狀以及分?jǐn)?shù)
  void judge();  //判斷是否層滿
  void move(); //移動函數(shù) 通過 ← → ↓ 控制
  void rotate(); //旋轉(zhuǎn)函數(shù)
  bool isaggin(); //判斷下一次行動是否會越界或者重合
  bool exsqr(int row); //判斷當(dāng)前行是否空


 };

2.3 設(shè)置方塊形狀

這里通過 case 語句定義了7種方塊的形狀,在每次下一個方塊掉落之前都要調(diào)用以設(shè)置好它的形狀以及初始位置

void Piece::set_shape(int &cshape, int shape[][4],int &size_w,int &size_h)
{
 /*首先將用來表示的4x4數(shù)組初始化為0*/
 int i,j;
 for(i=0;i<4;i++)
  for(j=0;j<4;j++)
   shape[i][j]=0;

 /*設(shè)置7種初始形狀并設(shè)置它們的size*/
 switch(cshape)
 {
  case 0: 
   size_h=1;
   size_w=4; 
   shape[0][0]=1;
   shape[0][1]=1;
   shape[0][2]=1;
   shape[0][3]=1;
   break;
  case 1:
   size_h=2;
   size_w=3;
   shape[0][0]=1;
   shape[1][0]=1;
   shape[1][1]=1;
   shape[1][2]=1;
   break;
  case 2:
   size_h=2;
   size_w=3; 
   shape[0][2]=1;
   shape[1][0]=1;
   shape[1][1]=1;
   shape[1][2]=1;
   break;
  case 3:
   size_h=2;
   size_w=3;
   shape[0][1]=1;
   shape[0][2]=1;
   shape[1][0]=1;
   shape[1][1]=1;
   break;

  case 4:
   size_h=2;
   size_w=3;
   shape[0][0]=1;
   shape[0][1]=1;
   shape[1][1]=1;
   shape[1][2]=1;
   break;

  case 5: 
   size_h=2;
   size_w=2;
   shape[0][0]=1;
   shape[0][1]=1;
   shape[1][0]=1;
   shape[1][1]=1;
   break;

  case 6: 
   size_h=2;
   size_w=3;
   shape[0][1]=1;
   shape[1][0]=1;
   shape[1][1]=1;
   shape[1][2]=1;
   break;
 }

 //設(shè)置完形狀以后初始化方塊的起始位置
 head_x=game_win_width/2;
 head_y=1;

 //如果剛初始化就重合了,游戲結(jié)束~
 if(isaggin()) /* GAME OVER ! */
  game_over=true;

}

2.4 旋轉(zhuǎn)函數(shù)

這里用了一個比較簡單的算法對方塊進(jìn)行旋轉(zhuǎn),類似于矩陣的旋轉(zhuǎn),先將 shape 數(shù)組進(jìn)行斜對角線對稱化,再進(jìn)行左右對稱,便完成了旋轉(zhuǎn),需要注意的是要判斷旋轉(zhuǎn)后方塊是否出界或重合,如果是,則取消本次旋轉(zhuǎn)。

void Piece::rotate()
 {
  int temp[4][4]={0}; //臨時變量
  int temp_piece[4][4]={0}; //備份用的數(shù)組
  int i,j,tmp_size_h,tmp_size_w;

  tmp_size_w=size_w;
  tmp_size_h=size_h;

  for(int i=0; i<4;i++)
   for(int j=0;j<4;j++)
    temp_piece[i][j]=box_shape[i][j]; //備份一下當(dāng)前的方塊,如果旋轉(zhuǎn)失敗則返回到當(dāng)前的形狀


  for(i=0;i<4;i++)
   for(j=0;j<4;j++)
    temp[j][i]=box_shape[i][j]; //斜對角線對稱
  i=size_h;
  size_h=size_w;
  size_w=i;
  for(i=0;i<size_h;i++)
   for(j=0;j<size_w;j++)
    box_shape[i][size_w-1-j]=temp[i][j]; //左右對稱


  /*如果旋轉(zhuǎn)以后重合,則返回到備份的數(shù)組形狀*/
  if(isaggin()){
   for(int i=0; i<4;i++)
    for(int j=0;j<4;j++)
     box_shape[i][j]=temp_piece[i][j];
   size_w=tmp_size_w; //記得size也要變回原來的size
   size_h=tmp_size_h;
  }

  /*如果旋轉(zhuǎn)成功,那么在屏幕上進(jìn)行顯示*/
  else{
   for(int i=0; i<4;i++)
    for(int j=0;j<4;j++){
     if(temp_piece[i][j]==1){
      mvwaddch(game_win,head_y+i,head_x+j,' '); //移動到game_win窗口的某個坐標(biāo)處打印字符
      wrefresh(game_win);
     }
    }
   for(int i=0; i<size_h;i++)
    for(int j=0;j<size_w;j++){
     if(this->box_shape[i][j]==1){
      mvwaddch(game_win,head_y+i,head_x+j,'#');
      wrefresh(game_win);
     }
   }

  }
}

2.5 移動函數(shù)

如果玩家沒有按下任何按鍵,方塊需要慢速下落,所以我們不能夠因為等待按鍵輸入而阻塞在 getch() ,這里用到了 select() 來取消阻塞。

/* 這里只是截取了程序的一部分,具體實現(xiàn)請參考源碼 */
struct timeval timeout;
 timeout.tv_sec = 0;
 timeout.tv_usec= 500000;

if (select(1, &set, NULL, NULL, &timeout) == 0)

timeout 就是我們最多等待按鍵的時間,這里設(shè)置了 500000us,超過這個時間就不再等待 getch() 的輸入,直接進(jìn)行下一步。

如果在 timeout 時間內(nèi)檢測到按鍵,則下面的 if 語句為真,得到輸入的 key 值,通過判斷不同的 key 值進(jìn)行向左、右、下、旋轉(zhuǎn)等操作。

if (FD_ISSET(0, &set))
    while ((key = getch()) == -1) ;
向左、右、下移動的函數(shù)處理方式基本相同,這里只拿向下移動的函數(shù)進(jìn)行說明

/* 這里只是截取了程序的一部分,具體實現(xiàn)請參考源碼 */

/* 如果輸入的按鍵是 ↓ */
if(key==KEY_DOWN){
  head_y++; //方塊的y坐標(biāo)+1
  if(isaggin()){ //如果重合或出界,則取消這次移動
   head_y--;

   /*既然停下來了,那么把地圖上對應(yīng)的box設(shè)置為已被占用,用1表示,0表示未被占用
   for(int i=0;i<size_h;i++)
    for(int j=0;j<size_w;j++)
     if(box_shape[i][j]==1)
      box_map[head_y+i][head_x+j]=1;

   score_next(); //顯示分?jǐn)?shù)以及提示下一個方塊

  }

  /*如果能夠向下移動,那么取消當(dāng)前方塊的顯示,向下移動一行進(jìn)行顯示,這里注意for循環(huán)的行要從下往上
  else{
   for(int i=size_h-1; i>=0;i--)
    for(int j=0;j<size_w;j++){
     if(this->box_shape[i][j]==1){
      mvwaddch(game_win,head_y-1+i,head_x+j,' ');
      mvwaddch(game_win,head_y+i,head_x+j,'#');

     }
    }
   wrefresh(game_win);
}

2.6 重復(fù)函數(shù)

每次移動或旋轉(zhuǎn)之后要進(jìn)行判斷的函數(shù),函數(shù)返回真則不能行動,返回假則可以進(jìn)行下一步。

bool Piece::isaggin(){
 for(int i=0;i<size_h;i++)
  for(int j=0;j<size_w;j++){
   if(box_shape[i][j]==1){
    if(head_y+i > game_win_height-2) //下面出界
     return true;
    if(head_x+j > game_win_width-2 || head_x+i-1<0) //左右出界
     return true;
    if(box_map[head_y+i][head_x+j]==1) //與已占用的box重合
     return true ;
   }
  }
 return false;
}

2.7 層滿函數(shù)

最后一個很重要的功能是對方塊已滿的行進(jìn)行消除,每當(dāng)一個方塊向下移動停止后都需要進(jìn)行判斷。

void Piece::judge(){
 int i,j;
 int line=0; //用來記錄層滿的行數(shù)
 bool full;
 for(i=1;i<game_win_height-1;i++){ //除去邊界
  full=true;
  for(j=1;j<game_win_width-1;j++){
   if(box_map[i][j]==0) //存在未被占用的box
    full=false; //說明本層未滿
  }
  if(full){ //如果該層滿
   line++; //行滿+1
   score+=50; //加分~
   for(j=1;j<game_win_width-1;j++)
    box_map[i][j]=0; //把該層清空(標(biāo)記為未被占用)
  }
 }

 /*上面判斷完后 看line的值,如果非 0 說明有層已滿需要進(jìn)行消除*/
 if(line!=0){
 for(i=game_win_height-2;i>=2;i--){
  int s=i;
  if(exsqr(i)==0){
   while(s>1 && exsqr(--s)==0); //查找存在方塊的行,將其下移
   for(j=1;j<game_win_width-1;j++){
    box_map[i][j]=box_map[s][j]; //上層下移
    box_map[s][j]=0; //上層清空
   }
  }
 }

 /*清空和移動標(biāo)記完成以后就要屏幕刷新了,重新打印game_win*/
 for(int i=1;i<game_win_height-1;i++)
   for(int j=1;j<game_win_width-1;j++){
    if(box_map[i][j]==1){
     mvwaddch(game_win,i,j,'#');
     wrefresh(game_win);
    }
    else{
     mvwaddch(game_win,i,j,' ');
     wrefresh(game_win);
    }
   }
 }
}

三、實驗總結(jié)

到這里幾個關(guān)鍵函數(shù)的介紹也就完成了,搞明白這些函數(shù)的功能并實現(xiàn),再參考源碼補(bǔ)全其他函數(shù)以及main函數(shù)就可以運行啦!當(dāng)然俄羅斯方塊的實現(xiàn)方法還有很多,每個人的思路和方法可能會不一樣,或許你寫出來的俄羅斯方塊更簡潔、更流暢! Enjoy it ?。海?/p>

相關(guān)文章

  • C++中delete和delete[]的區(qū)別

    C++中delete和delete[]的區(qū)別

    這篇文章主要介紹了C++中delete和delete[]的區(qū)別的相關(guān)資料,需要的朋友可以參考下
    2016-03-03
  • 示例詳解C++語言中的命名空間 (namespace)

    示例詳解C++語言中的命名空間 (namespace)

    C++名字空間是一種描述邏輯分組的機(jī)制,也就是說,如果有一些聲明按照某種準(zhǔn)則在邏輯上屬于同一個模塊,就可以將它們放在同一個名字空間,以表明這個事實,這篇文章主要給大家介紹了關(guān)于C++語言中命名空間 (namespace)的相關(guān)資料,需要的朋友可以參考下
    2021-08-08
  • C++ 異常處理 catch(...)介紹

    C++ 異常處理 catch(...)介紹

    catch(…)能夠捕獲多種數(shù)據(jù)類型的異常對象,所以它提供給程序員一種對異常 對象更好的控制手段,使開發(fā)的軟件系統(tǒng)有很好的可靠性
    2013-09-09
  • C++?容器中map和unordered?map區(qū)別詳解

    C++?容器中map和unordered?map區(qū)別詳解

    這篇文章主要為大家介紹了C++?容器中map和unordered?map區(qū)別示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11
  • 利用C++實現(xiàn)矩陣的相加/相稱/轉(zhuǎn)置/求鞍點

    利用C++實現(xiàn)矩陣的相加/相稱/轉(zhuǎn)置/求鞍點

    利用C++實現(xiàn)矩陣的相加/相稱/轉(zhuǎn)置/求鞍點。需要的朋友可以過來參考下,希望對大家有所幫助
    2013-10-10
  • 詳解C++中的萬能頭文件

    詳解C++中的萬能頭文件

    C++萬能頭文件它是一個包含了每一個標(biāo)準(zhǔn)庫的頭文件,接下來通過本文給大家介紹C++中的萬能頭文件及優(yōu)缺點,需要的朋友可以參考下
    2023-02-02
  • 使用C++開發(fā)一個串口讀寫軟件的實現(xiàn)步驟

    使用C++開發(fā)一個串口讀寫軟件的實現(xiàn)步驟

    這篇文章主要介紹了使用xmake(一個項目管理工具兼包管理工具)和asio2(一個asio的框架,可以實現(xiàn)輕松各種網(wǎng)絡(luò)應(yīng)用,一般支持tcp,udp,http,websocket,rpc,ssl,icmp,serial_port.)來快速的開發(fā)個串口讀寫軟件(整合例程),需要的朋友可以參考下
    2025-04-04
  • C++基本用法實踐之智能指針詳解

    C++基本用法實踐之智能指針詳解

    為了減少手動管理內(nèi)存帶來的困擾,c++提出了智能指針,可以幫助我們進(jìn)行內(nèi)存管理,下面小編就來和大家簡單聊聊C++中智能指針的基本用法吧
    2023-07-07
  • vscode 安裝go第三方擴(kuò)展包填坑記錄的詳細(xì)教程

    vscode 安裝go第三方擴(kuò)展包填坑記錄的詳細(xì)教程

    這篇文章主要介紹了vscode 安裝go第三方擴(kuò)展包填坑記錄,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-05-05
  • C++小知識:不要節(jié)約代碼行數(shù)

    C++小知識:不要節(jié)約代碼行數(shù)

    今天小編就為大家分享一篇關(guān)于C++小知識:不要節(jié)約代碼行數(shù),小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-01-01

最新評論

壶关县| 南投市| 化州市| 灯塔市| 宁津县| 乐陵市| 潢川县| 册亨县| 枞阳县| 邯郸县| 正镶白旗| 汤阴县| 鹰潭市| 兴国县| 厦门市| 蓬安县| 随州市| 佛山市| 封开县| 黄骅市| 岫岩| 黄陵县| 通榆县| 长白| 驻马店市| 正宁县| 湘乡市| 奎屯市| 罗甸县| 郑州市| 肃宁县| 瑞金市| 紫阳县| 德保县| 依安县| 开江县| 军事| 大关县| 井陉县| 平江县| 苗栗市|