虫虫教学

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 581|回复: 0

俄罗斯方块

[复制链接]

4449

主题

4659

帖子

4万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
41710

最佳新人发帖达人推广达人热心会员突出贡献优秀讲师

发表于 2021-10-15 18:27:16 | 显示全部楼层 |阅读模式
    俄罗斯方块
      相信许多人都玩过俄罗斯方块游戏,该游戏即可以锻炼反应能力,也可以提高思维能力。笔者小时候就为该游戏所痴迷,就梦想长大后也设计一个类似的游戏。如今选择了程序员的职业,自然可以实现这个“梦想”了。图1显示了笔者设计的俄罗斯方块游戏的效果图。

                             

关键技术
在实现俄罗斯方块游戏时,涉及的技术比较简单,主要有两个,一是在绘制表格时使用内存画布来绘制表格,减少屏幕刷新次数,二是随机产生不同类型的方块。首先将所有的绘图操作在内存画布上完成,然后在内存画布对象释放时,将其内容绘制到窗口中,这样在窗口中只进行了一次绘图,减少了屏幕的刷新次数;其次在游戏过程中,需要产生不同类型的方块,为此需要编写一个方法,来生成方块。由于方块的基本类型只有7种,因此产生的类型必须在1到7之间。为此,需要使用随机函数rand与7进行取模运算。
在设计俄罗斯方块时,首先需要设计游戏的表格(CGrid类),游戏中的表格由单元格(CCell类)构成。在单元格对象中描述了所在表格的行和列索引,单元格是否被使用,单元格是否被固定(当图像移动到表格的底部,不能再向下移动了)等信息。
俄罗斯方块中共有7种基本形状,基本类型可以按90°旋转,这样又可以变换出12种新的类型,为这些形状统一建一个类CPiece。在CPiece类中,有一个关键的成员m_ImagesPT,该成员是一个数组,其中包含了4个CPoint对象。由于罗斯方块图像都占有4个单元格,因此使用4个CPoint对象描述每一个单元格坐标,这里的坐标是单元格的行和列索引。当游戏产生一个新的方块图像时,图像最左边的位置由m_nLeftIndex成员表示,顶部位置由m_nTopIndex成员表示。依据这两个成员和当前图像的类型

游戏中显示方块时,将遍历CPiece的m_ImagesPT成员,读取每个元素表示的单元格坐标,通过该坐标来定位表格中的单元格CCell,将单元格CCell的m_bUsed成员设置为TRUE,然后调用表格CGrid的DrawGrid来绘制表格,使得方块显示在表格中。
在游戏进行中,默认时方块会向下移动,用户也可以使用左右方向键来移动图像。为了能够移动图像,需要设置CPiece类的m_nLeftIndex成员和m_nTopIndex成员,然后重新设置CPiece类的m_ImagesPT成员,最后绘制表格就可以实现移动图像的效果了。
设计过程
(1)创建一个基于对话框的工程,工程名称为“RussianGrid”。
(2)向对话框中添加图片、按钮、静态文本和群组框的控件,
(3)向对话框中添加HorMovePiece方法,当用户按左右方向键时左右移动方块图像。其实现代码如下:
void CRussianGridDlg::HorMovePiece(int nOffset)
{
      if (m_Piece.m_bMoving == FALSE)                                 //方块是否处于移动过程中
      {
            return;

      }
      BOOL bLeftMove = (nOffset < 1)? TRUE: FALSE;            //防止左右穿透图像
      if (!m_pGrid->IsAllowHorMove(m_Piece, bLeftMove))
      {
            m_bKeyDown = FALSE;                                    //如果不能左右移动,则在OnTimer中继续向下移动
            return;
      }
      m_Piece.MovePiece(m_Piece.m_nLeftIndex + nOffset , m_Piece.m_nTopIndex);   
      for(int i=0; i<4; i++)                                          //显示图像
      {
             int nX = m_Piece.m_ImagesPT.x;
            int nY = m_Piece.m_ImagesPT.y;
            m_pGrid->m_CellGrid[nY][nX].m_bUsed = TRUE;
      }
      m_pGrid->DrawGrid(GetDC());                                //绘制表格
      for( i=0; i<4; i++)                                              //在绘制下一次图像时使之前的图像消失
      {
            int nX = m_Piece.m_ImagesPT.x;
            int nY = m_Piece.m_ImagesPT.y;
             m_pGrid->m_CellGrid[nY][nX].m_bUsed = FALSE;
      }
      //获取当前方块所在列对应的底部行索引
      BOOL bRet = m_pGrid->GetBottomRowIndex(m_Piece.m_nLeftIndex, m_Piece.m_nWidth, m_Piece);
      if (bRet)
      {
            for( i=0; i<4; i++)           
            {
                  int nX = m_Piece.m_ImagesPT.x;
                   int nY = m_Piece.m_ImagesPT.y;
                  m_pGrid->m_CellGrid[nY][nX].m_bUsed = FALSE;
                  if (m_nKeyDown > 3)
                  {
                        m_pGrid->m_CellGrid[nY][nX].m_bFixed = TRUE;
                        m_Piece.m_bMoving = FALSE;
                        GradeHandle(m_Piece);                           //计算成绩
                        if (GameOver())                              //判断游戏是否结束
                        {
                              m_bGameRunning = FALSE;
                              MessageBox("游戏结束!");
                        }
                  }
            }                     
      }
}
秘笈心法
心法领悟596:FrameRect方法的使用
实例中使用CDC类的FrameRect方法绘制区域的边框,该方法同Draw3dRect方法类似,不同的是Draw3dRect方法将区域分为两组进行绘制显示立体效果,FrameRect方法使用一种颜色对区域四周进行绘制。



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|虫虫教学--虫虫联盟官网

GMT+8, 2025-4-28 23:25 , Processed in 0.246919 second(s), 25 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表