www.gusucode.com > LibUIDK控件编写VC++消球游戏源程序-源码程序 > LibUIDK控件编写VC++消球游戏源程序-源码程序\code\BubbleBreakerCtrl.cpp
// BubbleBreakerCtrl.cpp : implementation file // Download by http://www.NewXing.com #include "stdafx.h" #include "BubbleBreaker.h" #include "BubbleBreakerCtrl.h" #include <mmsystem.h> #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ////////////////////////////////////////////////////////////////////////// // CBubble CBubble::CBubble() { m_eBubble = BC_GREEN; m_bChecked = FALSE; } CBubble::~CBubble() { } ///////////////////////////////////////////////////////////////////////////// // CBubbleBreakerCtrl CBubbleBreakerCtrl::CBubbleBreakerCtrl() { m_nScore = 0; NewGame(); } CBubbleBreakerCtrl::~CBubbleBreakerCtrl() { } BOOL CBubbleBreakerCtrl::Create(DWORD dwStyle, const RECT &rect, CWnd *pParentWnd, UINT nID) { WNDCLASS wndcls; memset(&wndcls, 0, sizeof(WNDCLASS)); wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW; wndcls.lpfnWndProc = ::DefWindowProc; wndcls.hInstance = AfxGetInstanceHandle(); wndcls.hCursor = ::LoadCursor(NULL, IDC_ARROW); wndcls.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1); wndcls.lpszMenuName = NULL; wndcls.lpszClassName = _T("Bubble Breaker Control"); // Register the new class and exit if it fails if(!AfxRegisterClass(&wndcls)) { TRACE(_T("Class Registration Failed\n")); return FALSE; } CWnd* pWnd = this; return pWnd->Create(wndcls.lpszClassName, NULL, dwStyle, rect, pParentWnd, nID); } BEGIN_MESSAGE_MAP(CBubbleBreakerCtrl, CWnd) //{{AFX_MSG_MAP(CBubbleBreakerCtrl) ON_WM_PAINT() //}}AFX_MSG_MAP END_MESSAGE_MAP() ////////////////////////////////////////////////////////////////////////// // attributes int CBubbleBreakerCtrl::CloseAudio(BOOL bClose) { return 0; } int CBubbleBreakerCtrl::GetScore() const { return m_nScore; } int CBubbleBreakerCtrl::GetCheckedBubbleCount() const { int nCount = 0; for (int l = 0; l < m_nLine; l++) { for (int r = 0; r < m_nRow; r++) { if (m_BubblArray[l][r].m_bChecked) { ++nCount; } } } return nCount; } BOOL CBubbleBreakerCtrl::CanBreak() { BOOL bCanBreak = FALSE; for (int l = 0; l < m_nLine ; l++) { for (int r = 0; r < m_nRow ; r++) { BUBBLE_COLOR eBc = m_BubblArray[l][r].m_eBubble; if (eBc == BC_EMPTY) continue; // check left if (r - 1 >=0 ) { if (m_BubblArray[l][r-1].m_eBubble == eBc) { bCanBreak = TRUE; break; } } // check top if (l - 1 >= 0) { if (m_BubblArray[l-1][r].m_eBubble == eBc) { bCanBreak = TRUE; break; } } // check right if (r+1 < m_nRow) { if (m_BubblArray[l][r+1].m_eBubble == eBc) { bCanBreak = TRUE; break; } } // check down if (l+1 < m_nLine) { if (m_BubblArray[l+1][r].m_eBubble == eBc) { bCanBreak = TRUE; break; } } } if (bCanBreak) { break; } } return bCanBreak; } ////////////////////////////////////////////////////////////////////////// // Operations int CBubbleBreakerCtrl::NewGame() { for (int i = 0; i < m_nLine ; i++) { for (int j = 0; j < m_nRow ; j++) { int nRand = rand(); m_BubblArray[i][j].m_eBubble = BUBBLE_COLOR(nRand % BC_LAST); } } m_nScore = 0; if (m_hWnd != NULL) Invalidate(); return 0; } ///////////////////////////////////////////////////////////////////////////// // CBubbleBreakerCtrl message handlers void CBubbleBreakerCtrl::OnPaint() { CPaintDC dc(this); // device context for painting CRect rcClient; GetClientRect(rcClient); CDC memDC; memDC.CreateCompatibleDC(&dc); CBitmap bitmap; bitmap.CreateCompatibleBitmap(&dc, rcClient.Width(), rcClient.Height()); CBitmap *pOldBitmap = memDC.SelectObject(&bitmap); memDC.FillSolidRect(rcClient, RGB(255, 255, 255)); memDC.SetBkMode(TRANSPARENT); // Draw bubble CDC memDCBubble; memDCBubble.CreateCompatibleDC(&dc); BOOL bLeftTopCheckedBubble = FALSE; for (int i = 0; i < m_nLine ; i++) { for (int j = 0; j < m_nRow ; j++) { if (m_BubblArray[i][j].m_eBubble != BC_EMPTY) { CString strBubble; strBubble.Format(_T("%s%d.bmp"), CUIMgr::GetUIPathWithoutTitle(), m_BubblArray[i][j].m_eBubble); HBITMAP hBmp = LoadBITMAPOBJ(strBubble); HBITMAP hOldBmp = (HBITMAP)memDCBubble.SelectObject(hBmp); memDC.BitBlt(j*40, i*40, 40, 40, &memDCBubble, 0, 0, SRCCOPY); memDCBubble.SelectObject(hOldBmp); SafeDeleteBITMAPOBJ(hBmp); } // Draw checked flag if (m_BubblArray[i][j].m_bChecked) { memDC.Draw3dRect(j*40, i*40, 40, 40, 0, 0); // Draw total checked bubble count. if (!bLeftTopCheckedBubble) { int nCount = GetCheckedBubbleCount(); CString strCount; strCount.Format(_T("%d"), nCount * (nCount - 1)); memDC.DrawText(strCount, CRect(j*40, i*40, j*40+40, i*40+40), DT_LEFT|DT_TOP); bLeftTopCheckedBubble = TRUE; } } } } dc.BitBlt(0, 0, rcClient.Width(), rcClient.Height(), &memDC, 0, 0, SRCCOPY); memDC.SelectObject(pOldBitmap); // Do not call CWnd::OnPaint() for painting messages } int CheckTogetherBubble(CBubble *pBubbleArray, int nTotalLine, int nTotalRow, int nLine, int nRow) { if (nLine < 0 || nLine >= nTotalLine || nRow < 0 || nRow >= nTotalRow) return -1; // Check bubble if (!(pBubbleArray + nLine * nTotalRow + nRow)->m_bChecked && ((pBubbleArray + nLine * nTotalRow + nRow)->m_eBubble != BC_EMPTY)) (pBubbleArray + nLine * nTotalRow + nRow)->m_bChecked = TRUE; else return 0; if (nRow - 1 >= 0 && ((pBubbleArray + nLine * nTotalRow + nRow - 1)->m_eBubble == (pBubbleArray + nLine * nTotalRow + nRow)->m_eBubble)) { CheckTogetherBubble(pBubbleArray, nTotalLine, nTotalRow, nLine, nRow - 1); } if (nLine - 1 >= 0 && ((pBubbleArray + (nLine - 1)* nTotalRow + nRow)->m_eBubble == (pBubbleArray + nLine * nTotalRow + nRow)->m_eBubble)) { CheckTogetherBubble(pBubbleArray, nTotalLine, nTotalRow, nLine - 1, nRow); } if (nRow + 1 < nTotalRow && ((pBubbleArray + nLine * nTotalRow + nRow + 1)->m_eBubble == (pBubbleArray + nLine * nTotalRow + nRow)->m_eBubble)) { CheckTogetherBubble(pBubbleArray, nTotalLine, nTotalRow, nLine, nRow + 1); } if (nLine + 1 < nTotalLine && ((pBubbleArray + (nLine + 1) * nTotalRow + nRow)->m_eBubble == (pBubbleArray + nLine * nTotalRow + nRow)->m_eBubble)) { CheckTogetherBubble(pBubbleArray, nTotalLine, nTotalRow, nLine + 1, nRow); } return 0; } int UnCheckAllBubble(CBubble *pBubbleArray, int nTotalLine, int nTotalRow) { for (int i = 0; i < nTotalLine ; i++) { for (int j = 0; j < nTotalRow ; j++) { (pBubbleArray + i * nTotalRow + j)->m_bChecked = FALSE; } } return 0; } BOOL HasCheckedBubble(CBubble *pBubbleArray, int nTotalLine, int nTotalRow) { BOOL bHas = FALSE; for (int i = 0; i < nTotalLine ; i++) { for (int j = 0; j < nTotalRow ; j++) { if ((pBubbleArray + i * nTotalRow + j)->m_bChecked) { bHas = TRUE; break; } } } return bHas; } BOOL IsLeftRowHasUnEmptyRow(CBubble *pBubbleArray, int nTotalLine, int nTotalRow, int nFromRow) { if (nFromRow <= 0) return FALSE; if (nFromRow >= nTotalRow) nFromRow = nTotalRow - 1; BOOL bHas = FALSE; for (int r = nFromRow - 1; r >= 0 ; r--) { for (int l = 0; l < nTotalLine ; l++) { if ((pBubbleArray + l * nTotalRow + r)->m_eBubble != BC_EMPTY) { bHas = TRUE; break; } } } return bHas; } int BreakBubbles(CBubble *pBubbleArray, int nTotalLine, int nTotalRow) { // break bubbles for (int i = 0; i < nTotalLine ; i++) { for (int j = 0; j < nTotalRow ; j++) { if ((pBubbleArray + i * nTotalRow + j)->m_bChecked) { (pBubbleArray + i * nTotalRow + j)->m_bChecked = FALSE; (pBubbleArray + i * nTotalRow + j)->m_eBubble = BC_EMPTY; } } } // To Down for (int r = 0; r < nTotalRow ; r++) { for (int l=nTotalLine-1; l>=0; l--) { if ((pBubbleArray + l * nTotalRow + r)->m_eBubble == BC_EMPTY) { // find first bubble to down BOOL bFind = FALSE; for (int l2 = l-1; l2>=0 ; l2--) { if ((pBubbleArray + l2 * nTotalRow + r)->m_eBubble != BC_EMPTY) { bFind = TRUE; break; } } if (bFind) { *(pBubbleArray + l * nTotalRow + r) = *(pBubbleArray + l2 * nTotalRow + r); (pBubbleArray + l2 * nTotalRow + r)->m_eBubble = BC_EMPTY; (pBubbleArray + l2 * nTotalRow + r)->m_bChecked = FALSE; } else { break; } } } } // To Right { for (int r = nTotalRow - 1; r > 0 ; r--) { // Check this row is empty BOOL bEmpty = TRUE; for (int l = 0; l < nTotalLine ; l++) { if ((pBubbleArray + l * nTotalRow + r)->m_eBubble != BC_EMPTY) { bEmpty = FALSE; break; } } if (!bEmpty) continue; if (!IsLeftRowHasUnEmptyRow(pBubbleArray, nTotalLine, nTotalRow, r)) break; // Move left row to this row for (int r2 = r; r2 > 0 ; r2--) { for (l = 0; l < nTotalLine ; l++) { *(pBubbleArray + l * nTotalRow + r2) = *(pBubbleArray + l * nTotalRow + r2 - 1); (pBubbleArray + l * nTotalRow + r2 - 1)->m_eBubble = BC_EMPTY; (pBubbleArray + l * nTotalRow + r2 - 1)->m_bChecked = FALSE; } } // recheck this row if (r > 0) r++; } } return 0; } LRESULT CBubbleBreakerCtrl::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) { // TODO: Add your specialized code here and/or call the base class if (message == WM_ERASEBKGND) { return 0; } if (message == WM_LBUTTONDOWN || message == WM_LBUTTONDBLCLK) { CPoint point((DWORD)lParam); CRect rcClient; GetClientRect(rcClient); int nLine = point.y / 40; if (nLine < 0 || nLine >= m_nLine) nLine = -1; int nRow = point.x / 40; if (nRow < 0 || nRow >= m_nRow) nRow = -1; if (nLine != -1 && nRow != -1) { // Break the bubble if (m_BubblArray[nLine][nRow].m_bChecked && (m_BubblArray[nLine][nRow].m_eBubble != BC_EMPTY)) { // Play wav TCHAR buf[1024] = {0}; CString command = _T("play \""); command += CUIMgr::GetUIPathWithoutTitle(); command += _T("Alarm.wav\""); mciSendString(command, buf, sizeof(buf), NULL); // Break bubble int nCheckedCount = GetCheckedBubbleCount(); BreakBubbles(m_BubblArray[0], m_nLine, m_nRow); int nOldScore = m_nScore; m_nScore += (nCheckedCount * (nCheckedCount - 1)); GetParent()->SendMessage(WM_SCORECHANGED, nOldScore, m_nScore); if (!CanBreak()) { Invalidate(); CString strScore; strScore.Format(_T("分数:%d"), m_nScore); AfxMessageBox(strScore); NewGame(); } } // Check the bubbles else { if (HasCheckedBubble(m_BubblArray[0], m_nLine, m_nRow)) { UnCheckAllBubble(m_BubblArray[0], m_nLine, m_nRow); } else { CheckTogetherBubble(m_BubblArray[0], m_nLine, m_nRow, nLine, nRow); int nCheckedCount = GetCheckedBubbleCount(); if (nCheckedCount < 2) { UnCheckAllBubble(m_BubblArray[0], m_nLine, m_nRow); } } } } Invalidate(); } return CWnd::WindowProc(message, wParam, lParam); }