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