自己寫“掃雷”(二).業務邏輯實現
阿新 • • 發佈:2019-02-04
這個時候我們需要處理一下我們的業務邏輯了!
在這裡先簡略滴說說業務邏輯的思路:
主要是用一個二維陣列來表示這些格子,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 _DEBUG virtual void AssertValid() const; virtual void Dump(CDumpContext& dc) const; #endif protected: // 生成的訊息對映函式 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 _DEBUG virtual void AssertValid() const; virtual void Dump(CDumpContext& dc) const; #endif protected: // 生成的訊息對映函式 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;
//利用判斷顯示位數,不夠三位前面加0
if (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類的使用啦。我也是一邊看教程一邊慢慢學著用的