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

📄 vc++saoleigame.txt

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

 

扫雷,是附带在Window里面的游戏,是个简单的游戏。因此我们就从扫雷开始我们的游戏旅程。很多人都玩过这个游戏,只是不知道怎么用程序实现。不过还有人不知道怎么玩,下面就先说说游戏的规则:

 

●      开始:按左键开始游戏,按按钮或菜单重新开始。

●       左键:按下时,是雷则结束,非雷则显示数字。

●       数字:代表此数字周围一圈八格中雷的个数。

●       右键:奇次按下表示雷,偶数按下表示对上次的否定。

●       结束:左键按到雷结束,找出全部雷结束。

 

接下来就该介绍游戏的编程过程了。不过要先交代一下一些内容。

 

●       添加位图。

●        添加全局变量。

●       画初始界面。

●       添加函数。

 

为什么要按这种次序呢?因为我们在画初始界面时,可能要用到位图或变量,而变量的定义又可能要对位图进行定义。这样的步骤的好处还有:在做一步之后都可以运行,有错就改,无错就做下一步。

上图是扫雷的一个画面。

下面就一步一步地演示,以编程的思路进行,当然,由于编程过程中有一些函数中的代码是分成两三次写的,我们就不重复,全部代码在第一次讲到时列出,而后面讲到时就只是提一下。

 

新建单文档工程2_1。

 

2.   资源编辑

 

添加位图:

 

前十二幅是在雷区的,后四幅是按钮。为了便于加载,必须各自保证其连续性。另外,为什么不添加一个按钮而用位图呢?是因为即使我们添加了按钮也要添加四幅位图!

 

位图的ID号:

按扭位图:    30*30     IDB_ANNIU1、IDB_ANNIU 2、IDB_ANNIU3、 IDB_ANNIU4

雷区位图:    14*14     ID号按下图依次为:IDB_BITMAP14。。。。。。IDB_BITMAP25

 

位图:下图(图2-1)。

  
                             图2-1

 

3.   变量函数

 

定义新类:

 

对于雷,我们是单独定义一个类,这样有利于程序的操作。

        class Lei

{

public:

    //显示哪一个位图

       int weitu;

    //这个位置相应的值

       int shumu;

};

并有如下规定(图2-2):

 


                         图2-2

                                                                                 

视图类变量: 

 

接着是在View类添加变量和函数:

 

//剩下雷数

int leftnum; 

//雷数

       int leinum;      

//结束     

       int jieshu;

//计时

       short second; 

//开始计时

       int secondstart; 

//位图数组

       CBitmap m_Bitmap[12];

//按扭位图数组

       CBitmap m_anniu[4];

//雷区行数

       int m_RowCount; 

//雷区列数

       int m_ColCount; 

//最大雷区

              Lei lei[50][50]; 

 

    //这个位置周围雷数为0

       void leizero();

    //计时器函数

       afx_msg void OnTimer(UINT nIDEvent);

    //鼠标按下左键

       afx_msg void OnLButtonDown(UINT nFlags, CPoint point);

//鼠标按下右键

       afx_msg void OnRButtonDown(UINT nFlags, CPoint point);

    //初始化函数

       afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);

    //鼠标左键松开

       afx_msg void OnLButtonUp(UINT nFlags, CPoint point);

 

4.   具体实现

 

删去状态栏和工具栏:

 

开始执行程序,就能见到一个有状态栏和工具栏的大的单文档,与上图不同,所以我们第一步就是整理框架:

打开下面函数,把里面的一些语句去掉。如下所示:

    int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

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

              return -1;

       

/*    if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP

              | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||

              !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))

       {

              TRACE0("Failed to create toolbar\n");

              return -1;      // fail to create

       }

 

       if (!m_wndStatusBar.Create(this) ||

              !m_wndStatusBar.SetIndicators(indicators,

                sizeof(indicators)/sizeof(UINT)))

       {

              TRACE0("Failed to create status bar\n");

              return -1;      // fail to create

       }

 

       // TODO: Delete these three lines if you don't want the toolbar to

       //  be dockable

       m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);

       EnableDocking(CBRS_ALIGN_ANY);

       DockControlBar(&m_wndToolBar);

*/

return 0;

} 

 

设置窗口大小:

 

运行附加的代码,还能看到扫雷游戏的框架是不能调大小的,而且总是显示在最前面,这又是怎么实现的呢?       

在下面函数里添加语句,你能说出前三句是什么意思吗?注释已经被我去掉了,如果不知道,不如按一下F1。

                               

 BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)

{

       if( !CFrameWnd::PreCreateWindow(cs) )

              return FALSE;

       // TODO: Modify the Window class or styles here by modifying

       //  the CREATESTRUCT cs

       cs.dwExStyle=cs.dwExStyle|WS_EX_TOPMOST;     //

       cs.style=WS_SYSMENU|WS_OVERLAPPED|WS_MINIMIZEBOX;//; 

       //设置窗口大小:400*340

       cs.cx=400;

       cs.cy=340;   

       return TRUE;

} 

 

构造函数:

 

由于构造函数是程序运行时就执行的,所以,除了对变量赋值之外,我们还可以把游戏的核心结构即内部数组赋值:先是把全部格子的位图和雷数赋值为0,然后调用随机函数按指定雷数赋值为-1,最后把不是雷的格子的雷数赋值为相应的值。

 

CMy2_1View::CMy2_1View()

{

     // TODO: add construction code here

     for(int ii=0;ii<16;ii++)

            m_Bitmap[ii].LoadBitmap(IDB_BITMAP14+ii);

    for(int jj=0;jj<4;jj++)

            m_anniu[jj].LoadBitmap(IDB_ANNIU1+jj);

    //计时

second=0; 

      //1时开始计时

secondstart=0; 

    //行数

m_RowCount=25; 

      //列数

m_ColCount=16; 

//雷数

    leinum=80;

      //剩余雷数

leftnum=leinum; 

      //jieshu=1时停止

jieshu=0; 

 

      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;

            }

     }

     //获取当前时间

     CTime time=GetCurrentTime();

     int s;

     //获取秒数

     s=time.GetSecond();

     //设置40个雷

     do

     {

            //以当前秒数为产生随机算法

            int k=(rand()*s)%m_RowCount;

            int l=(rand()*s)%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++;        

                   }

}

 

界面函数:

 

现在,可以开始画界面了。如下函数:

很明显,前面部分是用画的方法画出整个界面,但是,后面for循环显示的位图并不是现在画界面的内容,为什么要写呢?

这是为了用户框重画的需要,当我们的游戏玩了一半后最小化,或是把部分窗口移出屏幕,或是执行了新的应用程序覆盖了原来的程序时,必须重画。我们调用重画函数,它都要重新执行OnDraw(CDC* pDC)函数,那么,此时它就必须把已经显示出来的位图也显示出来。而开始时雷区位图是不可见的,并不影响界面的初始化。

 

    void CMy2_1View::OnDraw(CDC* pDC)

{

       CMy2_1Doc* pDoc = GetDocument();

       ASSERT_VALID(pDoc);

       // TODO: add draw code for native data here

       //画背景

    CBrush mybrush1;

      mybrush1.CreateSolidBrush(RGB(192,192,192));

      CRect myrect1(0,0,1200,800);

      pDC->FillRect(myrect1,&mybrush1);

  //画黑框

       CBrush mybrush;

      mybrush.CreateSolidBrush(RGB(0,0,0));

      CRect myrect(20,10,70,40);

      pDC->FillRect(myrect,&mybrush);

 

       CRect myrect2(325,10,375,40);

      pDC->FillRect(myrect2,&mybrush);

 

       CPen mypen;

       CPen*myoldPen;

       mypen.CreatePen(PS_SOLID,2,RGB(255,255,255));

    myoldPen=pDC->SelectObject(&mypen);

//画黑框的白线

       pDC->MoveTo(20,40);

       pDC->LineTo(70,40);

       pDC->LineTo(70,10);

       pDC->MoveTo(325,40);

       pDC->LineTo(375,40);

       pDC->LineTo(375,10);

//画雷区边线

//左上角是白线,右下角是黑线,以显示立体感

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

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

              {

                     pDC->MoveTo(10+i*15,50+j*15+14);

                     pDC->LineTo(10+i*15,50+j*15);  

                     pDC->LineTo(10+i*15+14,50+j*15);

              }

       pDC->SelectObject(myoldPen);

 

       CPen mypen2;

       CPen*myoldPen2;

       mypen2.CreatePen(PS_SOLID,1,RGB(0,0,0));

    myoldPen2=pDC->SelectObject(&mypen2);

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

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

              {

                     pDC->MoveTo(10+ii*15,50+jj*15+14);

                     pDC->LineTo(10+ii*15+14,50+jj*15+14);    

                     pDC->LineTo(10+ii*15+14,50+jj*15);

              }

       pDC->SelectObject(myoldPen2);

 

              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);

     //判断显示什么位图

        //weitu=1已按下的数字区

        //weitu=2显示旗

        //weitu=3显示问号

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

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

                     {

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

                            {

                    Dc.SelectObject(m_Bitmap[lei[a][b].shumu]);

                                   pDC->BitBlt(a*15+10,b*15+50,160,160,&Dc,0,0,SRCCOPY);

                            }

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

                            {

                                   Dc.SelectObject(m_Bitmap[9]);

                                   pDC->BitBlt(a*15+10,b*15+50,160,160,&Dc,0,0,SRCCOPY);

                            }

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

                            {

                                   Dc.SelectObject(m_Bitmap[10]);

                                   pDC->BitBlt(a*15+10,b*15+50,160,160,&Dc,0,0,SRCCOPY);

                            }

                            //结束

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

                            {

                    Dc.SelectObject(m_Bitmap[11]);

                                   pDC->BitBlt(a*15+10,b*15+50,160,160,&Dc,0,0,SRCCOPY);

                                   Dc.SelectObject(m_anniu[3]);

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

                            }

⌨️ 快捷键说明

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