自己写“扫雷”(二).业务逻辑实现

来源:互联网 发布:拉比 婴儿床 知乎 编辑:程序博客网 时间:2024/05/21 22:33

这个时候我们需要处理一下我们的业务逻辑了!

在这里先简略滴说说业务逻辑的思路:

主要是用一个二维数组来表示这些格子,status表示是否点击,或者标记为雷,hasLandmine记录这个格子是否有雷

每次绘图的时候根据这几个数组来判断应该载入哪种位图就可以了!蛮简单的!

我这里是主要在我们的MineView类中动工,在这个类中控制业务逻辑

初始化自动生成的类是:

class CMy17MyMineView : public CView{protected: // 仅从序列化创建CMy17MyMineView();DECLARE_DYNCREATE(CMy17MyMineView)// 特性public:CMy17MyMineDoc* GetDocument() const;// 操作public:// 重写public:virtual void OnDraw(CDC* pDC);  // 重写以绘制该视图virtual BOOL PreCreateWindow(CREATESTRUCT& cs);protected:virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);// 实现public:virtual ~CMy17MyMineView();#ifdef _DEBUGvirtual void AssertValid() const;virtual void Dump(CDumpContext& dc) const;#endifprotected:// 生成的消息映射函数protected:afx_msg void OnFilePrintPreview();afx_msg void OnRButtonUp(UINT nFlags, CPoint point);afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);DECLARE_MESSAGE_MAP()};

接下来加入我个人的业务逻辑:

加入几个成员,先不理会消息映射函数!

class CMy17MyMineView : public CView{protected: // 仅从序列化创建CMy17MyMineView();DECLARE_DYNCREATE(CMy17MyMineView)// 特性public:CMy17MyMineDoc* GetDocument() const;// 操作public:// 重写public:virtual void OnDraw(CDC* pDC);  // 重写以绘制该视图virtual BOOL PreCreateWindow(CREATESTRUCT& cs);protected:virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);// 实现public:virtual ~CMy17MyMineView();/*-------------------自己所加的成员如下--------------------*/public:void myRestart();//重新开盘void gameOver(); //游戏结束了void zeroHit(int x, int y);int m_RowCount; // 行数int m_ColCount; // 列数int landmineNum;     // 雷数int leftNum;    // 剩余雷数int overflag;   // 表示是否结束的标志int seconds;    //已经过去的时间CString m_MousePoint;CBitmap restart;//点击之后重新开始新一盘的游戏的位图CBitmap test1;CBitmap bitmap[31];        // 位图映射int haveLandmine[100][100];    //  雷区int landmineAround[100][100]; // 周围雷数int status[100][100];   // 0-未点开 1-点开 2-标记 3-?void landmineSet();         //生成雷区 设置周围雷数/*-------------------自己所加的成员如下--------------------*/#ifdef _DEBUGvirtual void AssertValid() const;virtual void Dump(CDumpContext& dc) const;#endifprotected:// 生成的消息映射函数protected:afx_msg void OnFilePrintPreview();afx_msg void OnRButtonUp(UINT nFlags, CPoint point);afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);/*----------------自己加入的消息映射函数---------------------*//*----------------自己加入的消息映射函数---------------------*/DECLARE_MESSAGE_MAP()};

在cpp文件中定义几个函数,分别是

void myRestart();//重新开盘void gameOver(); //游戏结束了void zeroHit(int x, int y);void landmineSet();         //生成雷区 设置周围雷数
其实扫雷的业务逻辑还是蛮简单的,这里就不对业务逻辑展开叙述了。
接下来在OnDraw()中画格子:

加入的代码是:

//-----------------------------画雷区的边界线for (int i = 0; i<m_ColCount; i++)for (int j = 0; j<m_RowCount; j++) {pDC->MoveTo(20 + i * 30, 100 + j * 30 + 28);pDC->LineTo(20 + i * 30, 100 + j * 30);pDC->LineTo(20 + i * 30 + 28, 100 + j * 30);}pDC->SelectObject(myoldPen);
实现效果如下:

接下来要把边界线加粗一点,形成叠影效果,把扫雷的这个框弄正常一点:

OnDraw() 函数中加入绘图代码:

/*----------------------把边界线加粗一点,形成叠影的效果----------------------*/CPen mypen2;CPen*myoldPen2;mypen2.CreatePen(PS_SOLID, 1, RGB(0, 0, 0));myoldPen2 = pDC->SelectObject(&mypen2);for (int ii = 0; ii<m_ColCount; ii++)for (int jj = 0; jj<m_RowCount; jj++) {pDC->MoveTo(20 + ii * 30 + 28, 100 + jj * 30);pDC->LineTo(20 + ii * 30 + 28, 100 + jj * 30 + 28);pDC->LineTo(20 + ii * 30, 100 + jj * 30 + 28);}pDC->SelectObject(myoldPen2);/*----------------------把边界线加粗一点,形成叠影的效果----------------------*/

就可以看到如下的效果:



是不是很像我们平时玩的扫雷的格子啦?

再加个绘制笑脸图片的代码:

/*----------------这部分画用来重启的笑脸----------------------*/CDC Dc;if (Dc.CreateCompatibleDC(pDC) == FALSE)AfxMessageBox(_T("Can't create DC"));Dc.SelectObject(restart);//restart是该类的一个成员,是CBitMap对象pDC->StretchBlt(365, 20, 60, 60, &Dc, 0, 0, 30, 30, SRCCOPY);/*----------------这部分画用来重启的笑脸----------------------*/
关于载入资源的问题:

vs中添加图片资源——————要在资源视图中导入资源,还要保存,保存之后会自动在resource.h中定义对应的ID和宏

或者在百度上找找也是不少的

再加入显示字体的代码:

int nOldDC = pDC->SaveDC();pDC->SetTextColor(RGB(255, 0, 0));pDC->SetBkColor(RGB(0, 0, 0));CFont font;pDC->SelectObject(&font);CString str, str1;//利用判断显示位数,不够三位前面加0if (leftNum<10)str.Format(_T("00%d"), leftNum);else             str.Format(_T("0%d"), leftNum);if (seconds<10)str1.Format(_T("00%d"), seconds);else if (seconds<100) str1.Format(_T("0%d"), seconds);else  str1.Format(_T("%d"), seconds);LOGFONT lf;CFont fontTemp, *pFontOld;pDC->GetCurrentFont()->GetLogFont(&lf);lstrcpy(lf.lfFaceName, _T("宋体"));lf.lfWidth = 30;lf.lfWeight = FW_HEAVY;lf.lfHeight = 59;fontTemp.CreateFontIndirect(&lf);      //创建字体pFontOld = pDC->SelectObject(&fontTemp);pDC->TextOut(45, 20, str);//使用当前选择的字体在指定位置输出文本。 参数x指定文本起始点的x坐标;参数y指定文本起始点的y坐标;//参数lpszString为要输出的文本字符串;参数nCount指定字符串中的字节个数;参数str为包含要输出的字符的CString对象pDC->TextOut(650, 20, str1);pDC->SelectObject(pFontOld);
加入了这2部分代码的现实效果如下图:

可以看到,那么整个界面,我们就差不多做出来啦!
这个时候就要加入我们的业务逻辑啦,应该我们的每一个格子是你点开或者是没点开的,看看OnDraw()函数中的业务逻辑吧:

/*--------------------加入逻辑控制------------------------------------*/for (int iii = 1; iii <= m_ColCount; iii++)for (int jjj = 1; jjj <= m_RowCount; jjj++) {if (status[jjj][iii] == 1 && haveLandmine[jjj][iii] == 1) {//点开了这个地方,而且是有雷的。Dc.SelectObject(bitmap[12]); //载入这个踩到雷的位图pDC->StretchBlt(20 + 30 * (iii - 1), 100 + 30 * (jjj - 1), 28, 28, &Dc, 0, 0, 14, 14, SRCCOPY);}else if (status[jjj][iii] == 1 && haveLandmine[jjj][iii] == 0) {Dc.SelectObject(bitmap[landmineAround[jjj][iii] + 14]);//载入对应的(显示1,2,3,4,5,6,7,8)的图片pDC->StretchBlt(20 + 30 * (iii - 1), 100 + 30 * (jjj - 1), 28, 28, &Dc, 0, 0, 14, 14, SRCCOPY);}else if (status[jjj][iii] == 2) {Dc.SelectObject(bitmap[22]);//标记为雷,是个旗子pDC->StretchBlt(20 + 30 * (iii - 1), 100 + 30 * (jjj - 1), 28, 28, &Dc, 0, 0, 14, 14, SRCCOPY);}}/*--------------------加入逻辑控制------------------------------------*/
这里设计比较多的还是CDC类的使用啦。我也是一边看教程一边慢慢学着用的






阅读全文
0 0