温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

C++怎么实现俄罗斯方块游戏

发布时间:2021-04-14 11:20:23 来源:亿速云 阅读:185 作者:小新 栏目:编程语言

这篇文章主要介绍了C++怎么实现俄罗斯方块游戏,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

编译器是code::block  +  MinGW ,具体代码如下:

#include <windows.h>  #include <iostream>  #include <cstdlib>  #include <ctime>  using namespace std;  #define CellWidth 20  #define MAP_WIDTH 12  #define MAP_HEIGHT 18  #define ID_TIMER 1  class map_floor;  class Block;  LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);  /* Make the class name into a global variable */  char szClassName[ ] = "CodeBlocksWindowsApp";  int WINAPI WinMain (HINSTANCE hThisInstance,             HINSTANCE hPrevInstance,             LPSTR lpszArgument,             int nCmdShow)  {    HWND hwnd;        /* This is the handle for our window */    MSG messages;      /* Here messages to the application are saved */    WNDCLASSEX wincl;    /* Data structure for the windowclass */      /* The Window structure */    wincl.hInstance = hThisInstance;    wincl.lpszClassName = szClassName;    wincl.lpfnWndProc = WindowProcedure;   /* This function is called by windows */    wincl.style = CS_DBLCLKS|CS_HREDRAW | CS_VREDRAW;         /* Catch double-clicks */    wincl.cbSize = sizeof (WNDCLASSEX);      /* Use default icon and mouse-pointer */    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);    wincl.lpszMenuName = NULL;         /* No menu */    wincl.cbClsExtra = 0;           /* No extra bytes after the window class */    wincl.cbWndExtra = 0;           /* structure or the window instance */    /* Use Windows's default colour as the background of the window */    wincl.hbrBackground =(HBRUSH) GetStockObject(WHITE_BRUSH);//COLOR_BACKGROUND;      /* Register the window class, and if it fails quit the program */    if (!RegisterClassEx (&wincl))      return 0;      /* The class is registered, let's create the program*/    hwnd = CreateWindowEx (        0,         /* Extended possibilites for variation */        szClassName,     /* Classname */        "Code::Blocks Template Windows App",    /* Title Text */        WS_OVERLAPPEDWINDOW, /* default window */        CW_USEDEFAULT,    /* Windows decides the position */        CW_USEDEFAULT,    /* where the window ends up on the screen */        CW_USEDEFAULT,         /* The programs width */        CW_USEDEFAULT,         /* and height in pixels */        NULL,    /* The window is a child-window to desktop */        NULL,        /* No menu */        hThisInstance,    /* Program Instance handler */        NULL         /* No Window Creation data */        );      /* Make the window visible on the screen */    ShowWindow (hwnd, nCmdShow);      /* Run the message loop. It will run until GetMessage() returns 0 */    while (GetMessage (&messages, NULL, 0, 0))    {      /* Translate virtual-key messages into character messages */      TranslateMessage(&messages);      /* Send message to WindowProcedure */      DispatchMessage(&messages);    }      /* The program return-value is 0 - The value that PostQuitMessage() gave */    return messages.wParam;  }    enum{e_LINE,e_CORNER,e_STAIR,e_TANCK,e_TIAN};  const int TOTAL_BLOCK_STYLE = 5;//方块类型有4种  class Block  {    public:        Block(int x = 100, int y = 100);        Block(const Block & rh)//复制构造函数,可能没什么用,但是还是定义它吧        {          this->m_style = rh.m_style;          this->m_direct = rh.m_direct;          for(int i = 0 ; i < 4 ; i ++)            this->m_block[i] = rh.m_block[i];        }        Block & operator = (const Block& rh)//重载=号,实现方块的赋值        {          this->m_style = rh.m_style;          this->m_direct = rh.m_direct;          for(int i = 0 ; i < 4 ; i ++)            this->m_block[i] = rh.m_block[i];          return *this;        }        ~Block(){}    int   create_block(int x = 100 , int y = 100);    //显示在游戏区内移动的方块    int   show_block(HDC hdc,const POINT& GameLeftTop);    //显示将要出现的方块,即游戏区左边的方块    int   show_next_block(HDC hdc);    //旋转,该函数比较难实现,代码量也比较大,以后有时间在慢慢优化,关于解析看定义处    int   rotate();    //产生随机方块    int   random_block();      //下面为方块移动的成员函数    int   get_block_height(){ return m_block[1].y;}    int   move_down(const RECT& GameClient);    int   move_left(const RECT& GameClient);    int   move_right(const RECT& GameClient);    int   move_up(const RECT& GameClient);    int   move_to(int x , int y);    //检测方块是否在游戏区内  //  int   check_block(const map_floor& map, const RECT& GameClent);    int   check_block(const map_floor& map, const POINT& LeftTopScrCdnt);    int   print_to_map(map_floor& map , const POINT& LeftTopScrCdnt);    private:    int   m_style;//方块的风格样式,具体看定义的枚举变量    int   m_direct;//方块的方向,是对m_style的具体数据   POINT   m_block[4];//下标为1的方块是中心坐标,旋转都是围绕着该方块进行,这样可以利于旋转和逻辑清晰  };  class map_floor  {    public:      map_floor()      {        ZeroMemory(m_block_bar,sizeof(int )*12*18);      }      ~map_floor(){}    void show_block_bar(HDC hdc , const POINT& LeftTopScrCdnt)    {      for(int i = 0 ; i < MAP_HEIGHT ; ++ i)      {        for(int j = 0 ; j < MAP_WIDTH ; ++ j)        {          if(m_block_bar[i][j])          {            Rectangle(hdc,LeftTopScrCdnt.x + j*CellWidth , LeftTopScrCdnt.y + i*CellWidth,                   LeftTopScrCdnt.x + (j+1)*CellWidth , LeftTopScrCdnt.y + (i+1)*CellWidth);          }        }      }      }    friend class Block;    protected:      private:      int     m_block_bar[MAP_HEIGHT][MAP_WIDTH];//游戏区的地板,用18*12的二维数组表示      };    Block::Block(int x , int y)  {  //  ZeroMemory(m_block_bar,sizeof(int )*12*18);    srand( (unsigned)time( NULL ) );//初始化随机数,用于产生方块  //  POINT pt = {100,100};    create_block(x,y);  }  int Block::random_block()  {    m_style = rand()%TOTAL_BLOCK_STYLE;  //  m_style = e_CORNER; //测试之用  //  m_style = e_LINE; //测试之用    if(m_style == e_STAIR || m_style == e_TANCK)      m_direct = rand()%4;    else if(m_style == e_LINE)      m_direct = rand()%2;    else if(m_style == e_CORNER)      m_direct = rand()%8;    else if(m_style == e_TIAN)      m_direct = 0;    m_direct = 1;    }  int  Block::check_block(const map_floor& map, const POINT& LeftTopScrCdnt)  {    int x , y ; //x , y 为方块相对于地图的坐标,左上角为(0,0)    for(int i = 0 ; i < 4 ; i ++)    {      x = (m_block[i].x - LeftTopScrCdnt.x)/CellWidth;      y = (m_block[i].y - LeftTopScrCdnt.y)/CellWidth;      if(x < 0 || x >= MAP_WIDTH || y >= MAP_HEIGHT)//不用检测y < 0 的情况      return 0;      if(y < 0) continue;      if(map.m_block_bar[y][x])      return 0;    }    return 1;  }  int Block::move_down(const RECT& GameClient)//下移,由计时器消息调用  {    int i;  //  for (i = 0 ; i < 4 ; i ++ )  //  {  //   if(m_block[i].y == GameClient.bottom - CellWidth)  //   return 0;  //  }    for (i = 0; i < 4 ;i ++ )    {      m_block[i].y += CellWidth;    }    return 1;  }  int Block::move_up(const RECT& GameClient)  {    move_to(m_block[1].x,m_block[1].y - CellWidth);    return 1;  }  int Block::move_left(const RECT& GameClient)  {    move_to(m_block[1].x - CellWidth,m_block[1].y);    return 1;  }  int Block::move_right(const RECT& GameClient)  {    move_to(m_block[1].x + CellWidth , m_block[1].y);    return 1;  }  int Block::create_block(int x , int y)  {    m_block[1].x = x;    m_block[1].y = y;    random_block();    rotate();    return 1;  }  int Block::move_to(int x , int y)  {    int Vx = x - m_block[1].x;    int Vy = y - m_block[1].y;    for(int i = 0 ; i < 4 ; i ++)    {      m_block[i].x += Vx;      m_block[i].y += Vy;    }  }  int Block::print_to_map(map_floor& map , const POINT& LeftTopScrCdnt)  {    int x , y;    int i , j;    for(i = 0 ; i < 4 ; i ++ )    {      x = (m_block[i].x - LeftTopScrCdnt.x)/CellWidth;      y = (m_block[i].y - LeftTopScrCdnt.y)/CellWidth;      if(x<0 || x >= MAP_WIDTH || y <0 || y >= MAP_HEIGHT)//为保安全 ,测试之用,完成后将被注释掉        return 0;      map.m_block_bar[y][x] = 1 ;      for(j = 0 ; j < MAP_WIDTH ; j ++)      {        if(map.m_block_bar[y][j] != 1)          break;      }      if(MAP_WIDTH == j)      {        for(j = 0 ; j < MAP_WIDTH ; j ++)        {          map.m_block_bar[y][j] = 5;//数字5代表要消掉的行        }      }      }    int idx;    for(i = 0 ; i < MAP_WIDTH ; i ++)    {      for(idx = j = MAP_HEIGHT - 1 ; j >= 0 ; j --)      {        if(map.m_block_bar[j][i] != 5)        {          map.m_block_bar[idx--][i] = map.m_block_bar[j][i];        }      }      while(idx >= 0)      {        map.m_block_bar[idx--][i] = 0;      }    }    return 1;  }    //下面该函数功能是实现方块旋转,可以说是整个【俄罗斯方块】的难点所在,也是其核心部分  //方块用以数组block【4】表示,其余3个方格都将围绕block【1】旋转,方块由于有不对称方块  //存在,我原本是要分7种,但是后面代码量太大了,所以我将方块根据样式归为了四种,分别是:  //  //e_LINE 线形   就是一条线的那个,这个是对称的方块,只需分两个方向分别为横向和纵向,方向  //        用m_direct保持,其他的方块一样  //  //e_TANCK 坦克形 这个是方块是对称的,分四种方向,根据m_direct对4进行求余的方法可以大大缩减  //        代码量,对于下面两种方块也是利用了求余的方式化简许多,才使得代码不会那么冗余,  //        这是后面我才想到的方法。  //  //e_STAIR 楼梯形 这个方块相对前面两种来说有点难度,主要是因为它不是对称的,但是相对下面的这种  //        来说比较简单,原本我没用对m_direct求余的方法时,我将它分为了e_STAIR_BACK和e_STAIR_FRONT  //        两类来讨论的,后面发现代码可以缩减才将其归为一类只要记住block【0】和block【1】的位置不会  //        变化,变化的是block【2】和block【3】,block【2】相对block【1】上移或下移,x坐标与block【1】  //        相同,block【3】.y一直在block【1】下面一行,相对其左右变化  //  //e_CORNER 角形 这个方块个人觉得是最难旋转的方块,与上面一种异样,原本我将它分为e_CORNER_FRONT , e_CORNER_BACK  //        两类,每类有四个方向的变化,后来根据求余可以将同一个方向的变化变为一种,只是block【3】号方块要  //        根据m_direct方向来进行调整    int Block::rotate()  {        switch (m_style)        {          case e_LINE:          {            switch(m_direct)            {              case 0://横向转为纵向              {                for(int i = 0 ; i < 4 ; i ++)                  {                    m_block[i].x = m_block[1].x;                    m_block[i].y = m_block[1].y + (1-i)*CellWidth;                  }                m_direct = 1;              }                break;              case 1://纵向转为横向              {                for(int i = 0 ; i < 4 ; i ++)                {                    m_block[i].y = m_block[1].y;                    m_block[i].x = m_block[1].x + (1-i)*CellWidth;                }                m_direct = 0;              }                break;            }          }            break;          //下面为楼梯风格的方块,由于其不是对称的分类为正反两种,正反种风格各有两种变化,          //m_direct% == 0是正反两面的同种变化          case e_STAIR:          {            int flag;            flag = m_direct < 2 ? 1 : -1;            m_block[0].x = m_block[1].x + flag*CellWidth;            m_block[0].y = m_block[1].y;            m_block[2].x = m_block[1].x;            m_block[3].y = m_block[1].y + CellWidth;            if(m_direct%2 == 0)            {              m_block[2].y = m_block[1].y - CellWidth;              m_block[3].x = m_block[1].x + flag*CellWidth;              m_direct++;            }            else            {              m_block[2].y = m_block[1].y + CellWidth;              m_block[3].x = m_block[1].x - flag*CellWidth;              if(m_direct < 2) m_direct = 0;              else       m_direct = 2;            }          }            break;          //角形方块,与楼梯形方块一样非对称,有正反俩个种,每种有四种变化,          //下面根据m_direct%4的值将这些变化归类解决,对于正,反面对应的相同          //变化的方向,只有block【3】方格位置不一样,可以看我画的图对比即可了解          case e_CORNER:          {            switch (m_direct%4)            {              case 0:              {                m_block[0].x = m_block[1].x+CellWidth;                m_block[0].y = m_block[2].y = m_block[1].y;                m_block[2].x = m_block[1].x-CellWidth;                m_block[3].x = m_block[1].x-CellWidth;                if(m_direct>=4) m_block[3].y = m_block[1].y-CellWidth;                else       m_block[3].y = m_block[1].y+CellWidth;                m_direct ++;              }                break;              case 1:              {                m_block[0].x = m_block[2].x = m_block[1].x;                m_block[0].y = m_block[1].y+CellWidth;                m_block[2].y = m_block[1].y-CellWidth;                if(m_direct>=4)   m_block[3].x = m_block[1].x+CellWidth;                else       m_block[3].x = m_block[1].x-CellWidth;                m_block[3].y = m_block[1].y-CellWidth;                m_direct ++;              }                break;              case 2:              {                m_block[0].x = m_block[1].x-CellWidth;                m_block[0].y = m_block[2].y = m_block[1].y;                m_block[2].x = m_block[1].x+CellWidth;                m_block[3].x = m_block[1].x+CellWidth;                if (m_direct>=4)  m_block[3].y = m_block[1].y+CellWidth;                else       m_block[3].y = m_block[1].y-CellWidth;                  m_direct ++;              }                break;              case 3:              {                m_block[0].x = m_block[2].x = m_block[1].x;                m_block[0].y = m_block[1].y-CellWidth;                m_block[2].y = m_block[1].y+CellWidth;                if(m_direct>=4)  { m_block[3].x = m_block[1].x-CellWidth; m_direct = 4;}                else       { m_block[3].x = m_block[1].x+CellWidth; m_direct = 0;}                m_block[3].y = m_block[1].y+CellWidth;              }                break;              default:                break;            }            }            break;          case e_TANCK://坦克形方块,与线形方块一样是对称的,分四种变化          {            switch (m_direct%2)            {              case 0:              {                m_block[0].x = m_block[2].x = m_block[1].x;                m_block[0].y = m_block[1].y - CellWidth;                m_block[2].y = m_block[1].y + CellWidth;                int flag = m_direct == 0 ? 1 : -1;                m_block[3].x = m_block[1].x + flag*CellWidth;                m_block[3].y = m_block[1].y;                m_direct++;              }                break;              case 1:              {                m_block[0].y = m_block[2].y = m_block[1].y;                m_block[0].x = m_block[1].x - CellWidth;                m_block[2].x = m_block[1].x + CellWidth;                m_block[3].x = m_block[1].x;                int flag = m_direct == 3 ? -1:1;                m_block[3].y = m_block[1].y + flag*CellWidth;                if(m_direct == 3) m_direct = 0;                else m_direct++;                }                break;              default:                break;            }            }            break;          case e_TIAN:          {            m_block[0].y = m_block[1].y;            m_block[0].x = m_block[1].x + CellWidth;            m_block[2].x = m_block[1].x;            m_block[2].y = m_block[1].y + CellWidth;            m_block[3].x = m_block[1].x + CellWidth;            m_block[3].y = m_block[1].y + CellWidth;          }            break;            default:            break;        }            return 0;  }  int Block::show_block(HDC hdc,const POINT& GameLeftTop)  {    for (int i = 0 ; i < 4 ; i ++ )    {      if(m_block[i].y >= GameLeftTop.y)        Rectangle(hdc,m_block[i].x,m_block[i].y,m_block[i].             x+CellWidth,m_block[i].y+CellWidth);      if(i==0)//测试所用,完成后将会被注释掉      {MoveToEx(hdc,m_block[i].x,m_block[i].y,NULL);      LineTo(hdc,m_block[i].x+CellWidth,m_block[i].y+CellWidth);}      }    return 1;  }  int Block::show_next_block(HDC hdc)  {     for (int i = 0 ; i < 4 ; i ++ )    {        Rectangle(hdc,m_block[i].x,m_block[i].y,m_block[i].             x+CellWidth,m_block[i].y+CellWidth);    }    return 1;  }  Block block , next_block , try_block;  map_floor map;int d = 0;  LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)  {     HDC     hdc ;     PAINTSTRUCT ps ;     //游戏客户区     static RECT GameClient;     //一个方格的像素为CellWidth = 20 游戏区宽 12 个方格 高 18 个方格     const int  Width = 240 ,Height = 360;     static POINT LeftTopScrCdnt;//游戏区得左上角坐标       switch (message)     {     case WM_CREATE:       SetTimer(hwnd,ID_TIMER,500,NULL);       return 0 ;     case WM_SIZE:       GetClientRect(hwnd,&GameClient);       LeftTopScrCdnt.x = (GameClient.right-GameClient.left)/2 - Width/2;       LeftTopScrCdnt.y = GameClient.top + 50;       GameClient.left  = LeftTopScrCdnt.x;       GameClient.top  = LeftTopScrCdnt.y;       GameClient.right = LeftTopScrCdnt.x + Width;       GameClient.bottom = LeftTopScrCdnt.y + Height;       //创建下一个将要出现的方块       next_block.create_block(GameClient.right+2*CellWidth,(GameClient.bottom+GameClient.top)/2-3*CellWidth);       block.move_to((GameClient.right+GameClient.left)/2,GameClient.top-CellWidth);         break;     case WM_TIMER:       block.move_down(GameClient);       if(!block.check_block(map,LeftTopScrCdnt))//检测方块的碰撞,如果则说明方块到底底部,将其上移然后打印进地图       {         block.move_up(GameClient);         if(!block.check_block(map,LeftTopScrCdnt) ||           block.get_block_height() <= LeftTopScrCdnt.y )//检测游戏是否结束           {             KillTimer(hwnd,ID_TIMER);             d = 4;           }         block.print_to_map(map,LeftTopScrCdnt);         SendMessage(hwnd,WM_KEYDOWN,VK_ESCAPE,0);       }       InvalidateRect(hwnd,NULL,true);       break;     case WM_PAINT:       hdc = BeginPaint (hwnd, &ps) ;       MoveToEx(hdc,LeftTopScrCdnt.x,LeftTopScrCdnt.y,NULL);       Rectangle(hdc,GameClient.left,GameClient.top,GameClient.right,GameClient.bottom);//游戏区边框       SelectObject(hdc,GetStockObject(BLACK_BRUSH));       map.show_block_bar(hdc,LeftTopScrCdnt);       block.show_block(hdc,LeftTopScrCdnt);       next_block.show_next_block(hdc);       EndPaint (hwnd, &ps);       break;     case WM_KEYDOWN:       InvalidateRect(hwnd,NULL,true);       switch (wParam)       {        case VK_SPACE:        {          try_block = block;          try_block.rotate();          if(try_block.check_block(map ,LeftTopScrCdnt))            block = try_block;          break;        }        case VK_LEFT:        {          block.move_left(GameClient);          if(!block.check_block(map ,LeftTopScrCdnt))            block.move_right(GameClient);        }          break;        case VK_RIGHT:        {          block.move_right(GameClient);          if (!block.check_block(map ,LeftTopScrCdnt))            block.move_left(GameClient);        }          break;        case VK_DOWN:        {  //        block.move_down(GameClient);           SendMessage(hwnd,WM_TIMER,0,0);        }          break;          case VK_ESCAPE://测试用,完成后将会被注释掉        {          block = next_block;          next_block.create_block(GameClient.right+2*CellWidth,(GameClient.bottom+GameClient.top)/2-3*CellWidth);          block.move_to((GameClient.right+GameClient.left)/2,GameClient.top-CellWidth);        }          break;        default:          break;       }       break;     case WM_DESTROY:       PostQuitMessage (0) ;       return 0 ;     }     return DefWindowProc (hwnd, message, wParam, lParam) ;  }

感谢你能够认真阅读完这篇文章,希望小编分享的“C++怎么实现俄罗斯方块游戏”这篇文章对大家有帮助,同时也希望大家多多支持亿速云,关注亿速云行业资讯频道,更多相关知识等着你来学习!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

c++
AI