⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vc++saoleigame.txt

📁 一个用vc编的有关图形界面游戏编程开发的扫雷游戏以及具体讲解。包括:1. 游戏实现2. 资源编辑3. 变量函数4. 具体实现(删去状态栏和工具栏;设置窗口大小;构造函数;界面函数;显示
💻 TXT
📖 第 1 页 / 共 2 页
字号:

                            

                     }

 

//显示黑框里的数字

       int nOldDC=pDC->SaveDC();

       pDC->SetTextColor(RGB(255,0,0));

       pDC->SetBkColor(RGB(0,0,0));

       CFont font;                                             

       if(0==font.CreatePointFont(160,"Comic Sans MS"))

       {

              AfxMessageBox("Can't Create Font");

       }

       pDC->SelectObject(&font);

       CString str;  

    //利用判断显示位数,不够三位前面加0

       if(leftnum<10) 

              str.Format("00%d",leftnum);

       else

              str.Format("0%d",leftnum);                               

       pDC->TextOut(25,10,str);

       if(second<10)

              str.Format("00%d",second);

       else if(second<100)

                     str.Format("0%d" ,second);

              else

                     str.Format("%d" ,second);

       pDC->TextOut(330,10,str);

       pDC->RestoreDC(nOldDC);

                      

}

运行一下,外观已经出来了,只是还不能玩。那我们就来添加一些功能函数,使它可以玩。

当然,如果你对程序已经有一定的经验的话,你就会指出上面的函数太长了。这并不太符合我们编程的要求。我们编程有一个讲究,就是尽量使函数的代码少,一般为一页左右,便于查看。那么,我们可以把上面的函数细分为几个小函数,然后在这个函数里面分别调用。

 

按下鼠标左键:

 

用if语句判断,如果在按钮上面,则显示按钮按下位图;如果在扫雷区,先把按钮位图改为张口位图,再判断按下的是否是雷,是就结束,重画,以显示所有的雷;否则,重画相应格子以显示数字。

 

void CMy2_1View::OnLButtonDown(UINT nFlags, CPoint point) 

{

   // TODO: Add your message handler code here and/or call default     

    //获取指针pdc

     CDC *pDC=GetDC();

    CDC Dc;

    if(Dc.CreateCompatibleDC(pDC)==FALSE)

            AfxMessageBox("Can't create DC"); 

    //显示按下按钮

    if(point.x>180&&point.x<210&&point.y>10&&point.y<40)

    {

       Dc.SelectObject(m_anniu[3]);

       pDC->BitBlt(180,10,160,160,&Dc,0,0,SRCCOPY);           

    }

    if((point.x>=10)&&(point.x<=385)&&(point.y>=50)&&(point.y<=290))

   {                   

          if(jieshu==1)

                 return;

 

           //显示张口按钮

          Dc.SelectObject(m_anniu[1]);

          pDC->BitBlt(180,10,160,160,&Dc,0,0,SRCCOPY);             

       // secondstart为1时计时有效

          secondstart=1;

      //鼠标坐标转换为数组坐标

          int a=(point.x-10)/15;

          int b=(point.y-50)/15;

          if(lei[a][b].weitu==0||lei[a][b].weitu==3)

        {

              if(lei[a][b].shumu==-1)

                 {

                        jieshu=1;

          //结束时,释放Timer 

KillTimer(1);

//重画,因为这次重画将显示全部的雷,

//不能用部分重画

                        Invalidate();

                 }

         else 

                 {

                        lei[a][b].weitu=1;

                        CRect rect;

                        rect.left=a*15+10;

                        rect.right=a*15+25;

                        rect.top=b*15+50;

                        rect.bottom=b*15+65;

                        InvalidateRect(&rect);

                 }     

          }

          

   }     CView::OnLButtonDown(nFlags, point);

}

如果你现在运行的话,你会发现按下按钮时并不还原,这就涉及到鼠标函数:OnLButtonUp(UINT nFlags, CPoint point)

 

松开鼠标左键:

 

松开左键时,显示按钮没有按下的位图;再判断,如果结束,就要显示失败的位图;另外,如果是在按钮上松开按钮,即表示我们已经按下了重新开始的按钮,必须调用重新开始函数OnStart()。

由于OnStart()函数是与菜单里的开始共有的,此处先保留不说,若有必要运行,可以先去掉最后两行。

 

 void CMy2_1View::OnLButtonUp(UINT nFlags, CPoint point) 

{

   // TODO: Add your message handler code here and/or call default

  CDC *pDC=GetDC();

   CDC Dc;

   if(Dc.CreateCompatibleDC(pDC)==FALSE)

     AfxMessageBox("Can't create DC"); 

   //显示按钮

   Dc.SelectObject(m_anniu[0]);

   pDC->BitBlt(180,10,160,160,&Dc,0,0,SRCCOPY);

   

   if(jieshu==1)

   {

      //显示按扭位图

          Dc.SelectObject(m_anniu[2]);

          pDC->BitBlt(180,10,160,160,&Dc,0,0,SRCCOPY);

   }     

  

  //如果按下的是按扭,重新开始

   if(point.x>180&&point.x<210&&point.y>10&&point.y<40)

       OnStart();

 

   CView::OnLButtonUp(nFlags, point);

}

 

按下鼠标右键:

 

如果是雷,我们按右键,显示旗子,并减少一个剩下雷数;如果我们认为那旗子的格子不是雷,我们按右键,显示问号,并在剩下雷数加上1。有关函数:

 

void CMy2_1View::OnRButtonDown(UINT nFlags, CPoint point) 

{

   // TODO: Add your message handler code here and/or call default

   //结束,返回

   if(jieshu==1)

          return;

   if((point.x>=10)&&(point.x<=385)&&(point.y>=50)&&(point.y<=290))

   {            

          int a=(point.x-10)/15;

          int b=(point.y-50)/15;

 

          if(lei[a][b].weitu==0||lei[a][b].weitu==3)      

          {

                 lei[a][b].weitu=2;                 

                 leftnum--;       

          

          }

       else

                 if(lei[a][b].weitu==2)

                 {

                        lei[a][b].weitu=3;

                        leftnum++;

                 }

 

      //重画剩下雷数

          CRect rect2;

          rect2.left=20;

          rect2.right=70;

          rect2.top=10;

          rect2.bottom=40;

          InvalidateRect(&rect2);         

   

          //重画打击格子

          CRect rect;

       rect.left=a*15+10;

          rect.right=a*15+25;

          rect.top=b*15+50;

          rect.bottom=b*15+65;

          InvalidateRect(&rect);          

   }

   CView::OnRButtonDown(nFlags, point);

}

 

显示没有雷的区域:

 

运行,玩一下,你会发现当按下的是一个周围没有雷的格子是它并不会象Window里面的扫雷游戏一样显示它周围的格子雷数。怎么实现呢?

添加一个如下函数:

 

//扫描,如果是已经被按下且雷数为0,显示它周围的八个格,并重画

void CMy2_1View::leizero()

{

    for(int i=0;i<m_RowCount;i++)

          for(int j=0;j<m_ColCount;j++)

                 if(lei[i][j].shumu==0&&lei[i][j].weitu==1)

                 {

                        for(int n=i-1;n<i+2;n++)

                               for(int m=j-1;m<j+2;m++)

                                      if(n>=0&&n<25&&m>=0&&m<m_ColCount)

                                             if(lei[n][m].shumu!=-1&&lei[n][m].weitu==0)

                                             {

                                                    lei[n][m].weitu=1;

                                                    CRect rect;

                                                    rect.left=n*15+10;

                                                    rect.right=n*15+25;

                                                    rect.top=m*15+50;

                                                    rect.bottom=m*15+65;

                                                    InvalidateRect(&rect);          

                                             }

                 }

}

再运行,效果是有的,只是它只显示一部分,即这个周围的几个。那么我们应该怎样使它显示全部呢?可以利用计时器函数。

 

计时器函数:

 

OnTimer(UINT nIDEvent)函数,同时也可以实现计时显示。添加OnCreate(LPCREATESTRUCT lpCreateStruct)和 OnTimer(UINT nIDEvent):

 

int CMy2_1View::OnCreate(LPCREATESTRUCT lpCreateStruct) 

{

   if (CView::OnCreate(lpCreateStruct) == -1)

          return -1; 

   // TODO: Add your specialized creation code here

 //20次为一秒

   SetTimer(1,50,NULL);

   return 0;

}

 

void CMy2_1View::OnTimer(UINT nIDEvent) 

{

   // TODO: Add your message handler code here and/or call default

   //结束,返回

   if(jieshu==1)

          return;

   //显示个数为0的方格

   leizero();

   //计时

   if(secondstart>0)

          secondstart++;

  //二十次为一秒

   if(secondstart==20)

   {

          secondstart=1;

          second++;      

          //重画时间

       CRect rect3;

          rect3.left=325;

          rect3.right=375;

          rect3.top=10;

          rect3.bottom=40;

          InvalidateRect(&rect3);  

   }

   CView::OnTimer(nIDEvent);

}

 

   扫雷游戏就这样就是了。下面是附加内容,它将说明菜单的添加和重新开始函数的算法。

 

 

5.   附加内容

 

修改菜单:

 

游戏已经可以玩了,只是点到雷之后就完了,无法重新开始。还有,菜单还没有改。下面就修改菜单并实现重新开始功能:

把菜单改为如下图2-3。

 


                         图2-3

 

并在View()函数中按下图添加OnStart()函数(图2-4):

  
图2-4

 

开始函数:

 

OnStart()函数其实只是构造函数的再版。

 

    void CMy2_1View::OnStart() 

{ 

SetTimer(1,50,NULL);

       // TODO: Add your command handler code here

       second=0;//计时

       secondstart=0;//1时开始计时

//     num=0;

    leftnum=leinum;//剩余雷数

       jieshu=0;//jieshu=1时停止

       int aa=0;

       //初始化0

       for(int i=0;i<m_RowCount;i++)

       {

              for(int j=0;j<m_ColCount;j++)

              {

                     lei[i][j].shumu=0;

                     lei[i][j].weitu=0;

              }

       }

       //设置leinum个雷

       do

       {

              int k=rand()%m_RowCount;

              int l=rand()%m_ColCount;

              if(lei[k][l].shumu!=-1)

              {

                     lei[k][l].shumu=-1; 

                  aa++; 

              }

        

       }while(aa!=leinum);   

    //给方格赋值

       for(int a=0;a<m_RowCount;a++)

              for(int b=0;b<m_ColCount;b++)

                     if(lei[a][b].shumu==0)

                     {

                            for(int c=a-1;c<a+2;c++)

                                   for(int d=b-1;d<b+2;d++)

                                          if(c>=0&&c<m_RowCount&&d>=0&&d<m_ColCount)

                                                 if(lei[c][d].shumu==-1)

                                                        lei[a][b].shumu++;        

                     }

       Invalidate(); 

 

}

 

这样,整个程序完成了。

 

 

6.   小结

 

 

当然,这个游戏比Window自带的简单。但就目前来说,离它其实也不远。添加菜单项,并相应修改参数值:m_RowCount、       m_ColCount、leinum,并重新初始化界面就行了。    

本书的例子都只是一些最基本的游戏算法,它教你怎样去实现游戏,而至于游戏的扩展,我只是提一些建议,让你自己去实现。

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -