需要源码和资源请点赞关注收藏后评论区留言私信~~~
在前面的博客中已经讲解了扫雷游戏的菜单和各种对话框的实现,下面将对扫雷游戏的核心算法设计与实现进行讲解
一、新游戏处理模块的设计与实现
新游戏处理模块主要负责游戏中的游戏初始化以及开始游戏,其设计比较简单,只需要通过如下几个步骤即可实现
1:载入图片资源和配置文件中的数据
2:把所有的游戏参数进行初始化,例如当前消耗时间和状态等
3:初始化表示地雷区域的二维数组
4:让地雷区域图像失效,重新绘制新的图像
实现代码如下
void CMyMine::LoadConfig()
{
char pszTmp[128] = {0};
GetPrivateProfileString("HERO", "time", "0",
pszTmp, 127, ".\\hero.ini");
m_uHighTime = atoi(pszTmp);
m_uXNum = 30; //X坐标上的方块个数
m_uYNum = 16; //Y坐标上的方块个数
m_uMineNum = 10; //地雷个数
m_bMarkful = TRUE;
m_bColorful = TRUE;
}
/*载入图片资源*/
void CMyMine::LoadBitmap()
{
if (m_bColorful) {
m_clrDark = COLOR_DARK_GRAY;
m_bmpMine.DeleteObject();
m_bmpMine.LoadBitmap(IDB_MINE_COLOR);
m_bmpNumber.DeleteObject();
m_bmpNumber.LoadBitmap(IDB_NUM_COLOR);
m_bmpButton.DeleteObject();
m_bmpButton.LoadBitmap(IDB_BTN_COLOR);
}
else {
m_clrDark = COLOR_BLACK;
m_bmpMine.DeleteObject();
m_bmpMine.LoadBitmap(IDB_MINE_GRAY);
m_bmpNumber.DeleteObject();
m_bmpNumber.LoadBitmap(IDB_NUM_GRAY);
m_bmpButton.DeleteObject();
m_bmpButton.LoadBitmap(IDB_BTN_GRAY);
}
}
/*初始化游戏*/
void CMyMine::InitGame()
{
LoadBitmap();
LoadConfig();
m_nLeaveNum = m_uMineNum;
m_uSpendTime = 0;
m_uBtnState = BS_NORMAL; //设置当前方块状态
m_uGameState = GS_WAIT; //设置当前游戏状态
if (m_uTimer) {
KillTimer(ID_TIMER_EVENT);
m_uTimer = 0;
}
m_pNewMine = NULL; //清空当前选中的小方块
m_pOldMine = NULL; //清空上次选中的小方块
//初始化表示雷区的二维数组
for (UINT i = 0; i<m_uYNum; i++) {
for (UINT j = 0; j<m_uXNum; j++) {
m_pMines[i][j].uRow = i;
m_pMines[i][j].uCol = j;
m_pMines[i][j].uState = STATE_NORMAL;
m_pMines[i][j].uAttrib = ATTRIB_EMPTY;
m_pMines[i][j].uOldState = STATE_NORMAL;
}
}
}
void CMyMine::StartGame()
{
InitGame();
Invalidate();
}
二、地雷格子模块的设计与实现
地雷格子的处理是扫雷游戏的核心内容,包括如下几个部分
1:地雷铺设模块
游戏中的地雷是随机铺设的,可以调用随机数发生函数生成随机数,利用随机数去除最大行列树,得到放置地雷行列坐标,然后分别放置地雷到不同的行和列的格子中去
2:自动打开周围不是地雷的格子
在游戏中,当玩家单击的格子周围没有地雷格子时,就需要程序自动把周围的格子自动打开来提高玩家的效率,其实现是通过递归的方法不断的打开当前格子周围地雷个数为0的格子来实现
3:获得周围地雷个数模块
在游戏中当玩家打开一个格子时,如果当前这个格子不是地雷,那么其一定是标明周围的地雷个数的格子,要实现这个功能主要是通过遍历当前格子周围的3×3范围的数组,当找到一个元素状态是地雷时,就把记录增加1,直到9个格子全部找完,这样就可以得到当前格子周围的地雷个数,代码实现如下
void CMyMine::ExpandMines(UINT row, UINT col)
{
UINT i, j;
UINT minRow = (row == 0) ? 0 : row - 1;
UINT maxRow = row + 2;
UINT minCol = (col == 0) ? 0 : col - 1;
UINT maxCol = col + 2;
UINT around = GetAroundNum(row, col);
m_pMines[row][col].uState = 15 - around;
m_pMines[row][col].uOldState = 15 - around;
//在指定位置画出地雷
DrawSpecialMine(row, col);
if (around == 0) {
for (i = minRow; i < maxRow; i++) {
for (j = minCol; j < maxCol; j++) {
if (!(i == row && j == col) &&
m_pMines[i][j].uState == STATE_NORMAL
&& m_pMines[i][j].uAttrib != ATTRIB_MINE) {
if (!IsInMineArea(i, j)) continue;
ExpandMines(i, j);
}
}
}
}
}
/*获得周围地雷个数*/
UINT CMyMine::GetAroundNum(UINT row, UINT col)
{
UINT i, j;
UINT around = 0;
UINT minRow = (row == 0) ? 0 : row - 1;
UINT maxRow = row + 2;
UINT minCol = (col == 0) ? 0 : col - 1;
UINT maxCol = col + 2;
for (i = minRow; i < maxRow; i++) {
for (j = minCol; j < maxCol; j++) {
if (!IsInMineArea(i, j)) continue;
if (m_pMines[i][j].uAttrib == ATTRIB_MINE) around++;
}
}
return around;
}
/*得到周围格子状态*/
UINT CMyMine::GetAroundFlags(UINT row, UINT col)
{
UINT i, j;
UINT flags = 0;
UINT minRow = (row == 0) ? 0 : row - 1;
UINT maxRow = row + 2;
UINT minCol = (col == 0) ? 0 : col - 1;
UINT maxCol = col + 2;
for (i = minRow; i < maxRow; i++) {
for (j = minCol; j < maxCol; j++) {
if (!IsInMineArea(i, j)) continue;
if (m_pMines[i][j].uState == STATE_FLAG) flags++;
}
}
return flags;
}
/*地雷判断*/
BOOL CMyMine::IsMine(UINT row, UINT col)
{
return (m_pMines[row][col].uAttrib == ATTRIB_MINE);
}
/*雷区判断*/
BOOL CMyMine::IsInMineArea(UINT row, UINT col)
{
return (row >= 0 && row < m_uYNum && col >= 0 && col < m_uXNum);
}
/*游戏结束*/
void CMyMine::Dead(UINT row, UINT col)
{
CRect rcBtn(m_uBtnRect[1], 15, m_uBtnRect[2], 39);
CRect rcMineArea(MINE_AREA_LEFT, MINE_AREA_TOP,
MINE_AREA_LEFT + m_uXNum * MINE_WIDTH, MINE_AREA_TOP + m_uYNum * MINE_HEIGHT);
UINT i, j;
if (m_pMines[row][col].uAttrib == ATTRIB_MINE) {//打开了是地雷的格子
for (i = 0; i < m_uYNum; i++) {
for (j = 0; j < m_uXNum; j++) {
m_pMines[row][col].uState = STATE_BLAST;
m_pMines[row][col].uOldState = STATE_BLAST;
if (m_pMines[i][j].uAttrib == ATTRIB_MINE
&& m_pMines[i][j].uState != STATE_FLAG) {
m_pMines[i][j].uState = STATE_MINE;
m_pMines[i][j].uOldState = STATE_MINE;
}
}
}
}
else { //打开了判断错误的格子
for (i = 0; i < m_uYNum; i++) {
for (j = 0; j < m_uXNum; j++) {
m_pMines[row][col].uState = STATE_ERROR;
m_pMines[row][col].uOldState = STATE_ERROR;
if (m_pMines[i][j].uAttrib == ATTRIB_MINE
&& m_pMines[i][j].uState != STATE_FLAG) {
m_pMines[i][j].uState = STATE_MINE;
m_pMines[i][j].uOldState = STATE_MINE;
}
}
}
}
InvalidateRect(rcMineArea);
m_uBtnState = BS_DEAD;
InvalidateRect(rcBtn);
m_uGameState = GS_DEAD;
if (m_uTimer != 0) {
KillTimer(ID_TIMER_EVENT);
m_uTimer = 0;
}
AfxMessageBox("您踩到地雷了,游戏结束");
}
/*获得胜利*/
BOOL CMyMine::Victory()
{
UINT i, j;
CRect rcBtn(m_uBtnRect[1], 15, m_uBtnRect[2], 39);
for (i = 0; i < m_uYNum; i++) {
for (j = 0; j < m_uXNum; j++) {
if (m_pMines[i][j].uState == STATE_NORMAL) return FALSE;
if (m_pMines[i][j].uState == STATE_DICEY) return FALSE;
}
}
m_uBtnState = BS_VICTORY;
m_uGameState = GS_VICTORY;
Invalidate();
if (m_uTimer != 0) {
KillTimer(ID_TIMER_EVENT);
m_uTimer = 0;
}
AfxMessageBox("恭喜您胜利了,游戏结束");
if(m_uSpendTime < m_uHighTime)
{
CHeroDlg dlg;
dlg.m_time = m_uSpendTime;
dlg.SetWriteFlg(TRUE);
dlg.DoModal();
}
return TRUE;
}
/*打开指定行列周围格子*/
void CMyMine::OpenAround(UINT row, UINT col)
{
if (GetAroundFlags(row, col) != GetAroundNum(row, col)) return;
UINT i, j;
UINT around = 0;
UINT minRow = (row == 0) ? 0 : row - 1;
UINT maxRow = row + 2;
UINT minCol = (col == 0) ? 0 : col - 1;
UINT maxCol = col + 2;
for (i = minRow; i < maxRow; i++) {
for (j = minCol; j < maxCol; j++) {
if (!IsInMineArea(i, j)) continue;
if (m_pMines[i][j].uState == STATE_NORMAL) {
ExpandMines(i, j);
around = GetAroundNum(i, j);
m_pMines[i][j].uState = 15 - around;
m_pMines[i][j].uOldState = 15 - around;
}
}
}
// 检查是否胜利
if (Victory()) {
for (i = 0; i < m_uYNum; i++) {
for (j = 0; j < m_uXNum; j++) {
if (m_pMines[i][j].uAttrib == ATTRIB_MINE) {
m_pMines[i][j].uState = STATE_FLAG;
m_pMines[i][j].uOldState = STATE_FLAG;
}
}
}
m_nLeaveNum = 0;
Invalidate();
}
}
BOOL CMyMine::ErrorAroundFlag(UINT row, UINT col)
{
if (GetAroundFlags(row, col) != GetAroundNum(row, col)) return FALSE;
UINT i, j;
UINT minRow = (row == 0) ? 0 : row - 1;
UINT maxRow = row + 2;
UINT minCol = (col == 0) ? 0 : col - 1;
UINT maxCol = col + 2;
for (i = minRow; i < maxRow; i++) {
for (j = minCol; j < maxCol; j++) {
if (!IsInMineArea(i, j)) continue;
if (m_pMines[i][j].uState == STATE_FLAG) {
if (m_pMines[i][j].uAttrib != ATTRIB_MINE) {
Dead(i, j);
return TRUE;
}
}
}
}
return FALSE;
}
void CMyMine::OnLRBtnDown(UINT row, UINT col)
{
UINT i, j;
UINT minRow = (row == 0) ? 0 : row - 1;
UINT maxRow = row + 2;
UINT minCol = (col == 0) ? 0 : col - 1;
UINT maxCol = col + 2;
for (i = minRow; i < maxRow; i++) {
for (j = minCol; j < maxCol; j++) {
if (!IsInMineArea(i, j)) continue;
// if (i == row && j == col) continue;
if (m_pMines[i][j].uState == STATE_NORMAL) {
m_pMines[i][j].uState = STATE_EMPTY;
}
else if (m_pMines[i][j].uState == STATE_DICEY) {
m_pMines[i][j].uState = STATE_DICEY_DOWN;
}
}
}
}
void CMyMine::OnLRBtnUp(UINT row, UINT col)
{
UINT i, j;
UINT minRow = (row == 0) ? 0 : row - 1;
UINT maxRow = row + 2;
UINT minCol = (col == 0) ? 0 : col - 1;
UINT maxCol = col + 2;
for (i = minRow; i < maxRow; i++) {
for (j = minCol; j < maxCol; j++) {
if (!IsInMineArea(i, j)) continue;
// if (i == row && j == col) continue;
if (m_pMines[i][j].uOldState == STATE_NORMAL) {
m_pMines[i][j].uState = STATE_NORMAL;
}
else if (m_pMines[i][j].uOldState == STATE_DICEY) {
m_pMines[i][j].uState = STATE_DICEY;
}
}
}
// Invalidate();
三、游戏规则模块设计与实现
游戏规则模块的实现,主要由游戏结束和游戏胜利判断函数组成,通过对游戏的结果进行判断,实现扫雷游戏的规则
BOOL CMyMine::Victory()
{
UINT i, j;
CRect rcBtn(m_uBtnRect[1], 15, m_uBtnRect[2], 39);
for (i = 0; i < m_uYNum; i++) {
for (j = 0; j < m_uXNum; j++) {
if (m_pMines[i][j].uState == STATE_NORMAL) return FALSE;
if (m_pMines[i][j].uState == STATE_DICEY) return FALSE;
}
}
m_uBtnState = BS_VICTORY;
m_uGameState = GS_VICTORY;
Invalidate();
if (m_uTimer != 0) {
KillTimer(ID_TIMER_EVENT);
m_uTimer = 0;
}
AfxMessageBox("恭喜您胜利了,游戏结束");
if(m_uSpendTime < m_uHighTime)
{
CHeroDlg dlg;
dlg.m_time = m_uSpendTime;
dlg.SetWriteFlg(TRUE);
dlg.DoModal();
}
return TRUE;
}
/*打开指定行列周围格子*/
四、游戏绘图模块的设计与实现
在扫雷游戏中,通过绘图模块来实现地雷,格子,地雷个数,当前时间以及控制按钮等图片和信息的显示,由如下几个函数组成
void CMyMine::DrawButton(CPaintDC &dc)
{
CDC cdc;
cdc.CreateCompatibleDC(&dc);
cdc.SelectObject(m_bmpButton);
dc.StretchBlt(m_uBtnRect[0], 16, 24, 24, &cdc, 0, 24 * m_uBtnState, 24, 24, SRCCOPY);
dc.Draw3dRect(m_uBtnRect[1], 15, 26, 26, m_clrDark, m_clrDark);
}
void CMyMine::DrawNumber(CPaintDC &dc)
{
CDC cdc;
cdc.CreateCompatibleDC(&dc);
cdc.SelectObject(m_bmpNumber);
dc.Draw3dRect(16, 15, 41, 25, m_clrDark, COLOR_WHITE);
dc.Draw3dRect(m_uNumRect[0], 15, 41, 25, m_clrDark, COLOR_WHITE);
int num;
// draw remaining mine numbers
num = (m_nLeaveNum < 0) ? 11 : m_nLeaveNum / 100;
dc.StretchBlt(17, 16, 13, 23, &cdc, 0, 276 - 23 * (num+1), 13, 23, SRCCOPY);
num = (m_nLeaveNum < 0) ? -(m_nLeaveNum - num * 100) / 10 : (m_nLeaveNum - num * 100) / 10;
dc.StretchBlt(30, 16, 13, 23, &cdc, 0, 276 - 23 * (num+1), 13, 23, SRCCOPY);
num = (m_nLeaveNum < 0) ? -m_nLeaveNum % 10 : m_nLeaveNum % 10;
dc.StretchBlt(43, 16, 13, 23, &cdc, 0, 276 - 23 * (num+1), 13, 23, SRCCOPY);
// draw take seconds
num = m_uSpendTime / 100;
dc.StretchBlt(m_uNumRect[0], 16, 13, 23, &cdc, 0, 276 - 23 * (num+1), 13, 23, SRCCOPY);
num = (m_uSpendTime - num * 100) / 10;
dc.StretchBlt(m_uNumRect[0] + 13, 16, 13, 23, &cdc, 0, 276 - 23 * (num+1), 13, 23, SRCCOPY);
num = m_uSpendTime % 10;
dc.StretchBlt(m_uNumRect[0] + 26, 16, 13, 23, &cdc, 0, 276 - 23 * (num+1), 13, 23, SRCCOPY);
}
/*void CMyMine::DrawShell(CPaintDC &dc)
{
// draw side
dc.FillSolidRect(0, 0, m_uShellRcX[0], LINE_WIDTH_0, COLOR_WHITE);
dc.FillSolidRect(0, 0, LINE_WIDTH_0, m_uShellRcY[0], COLOR_WHITE);
// draw small shell
dc.Draw3dRect(SHELL_S_START_X, SHELL_S_START_Y,
m_uShellRcX[1], SHELL_S_H, m_clrDark, COLOR_WHITE);
dc.Draw3dRect(SHELL_S_START_X + 1, SHELL_S_START_Y + 1,
m_uShellRcX[1] - 2, SHELL_S_H - 2, m_clrDark, COLOR_WHITE);
// draw large shell
dc.Draw3dRect(SHELL_L_START_X, SHELL_L_START_Y,
m_uShellRcX[1], m_uShellRcY[1], m_clrDark, COLOR_WHITE);
dc.Draw3dRect(SHELL_L_START_X + 1, SHELL_L_START_Y + 1,
m_uShellRcX[1] - 2, m_uShellRcY[1] - 2, m_clrDark, COLOR_WHITE);
dc.Draw3dRect(SHELL_L_START_X + 2, SHELL_L_START_Y + 2,
m_uShellRcX[1] - 4, m_uShellRcY[1] - 4, m_clrDark, COLOR_WHITE);
}*/
void CMyMine::DrawMineArea(CPaintDC &dc)
{
CDC cdc;
cdc.CreateCompatibleDC(&dc);
cdc.SelectObject(m_bmpMine);
for (UINT i = 0; i<m_uYNum; i++) {
for (UINT j = 0; j<m_uXNum; j++) {
dc.StretchBlt(MINEAREA_FRAME_X + 16 * j, MINEAREA_FRAME_Y + 16 * i,
16, 16, &cdc, 0, 16 * m_pMines[i][j].uState, 16, 16, SRCCOPY);
}
}
}
void CMyMine::DrawDownNum(MINEWND* mine, UINT num)
{
mine->uState = 15 - num;
mine->uOldState = 15 - num;
CRect rcMine(mine->uCol * 16, mine->uRow * 16, (mine->uCol+1) *16, (mine->uRow+1) * 16);
InvalidateRect(rcMine);
}
void CMyMine::DrawSpecialMine(UINT row, UINT col)
{
CRect rcMine(col * 16, row * 16, (col+1) * 16, (row+1) * 16);
InvalidateRect(rcMine);
}
五、玩家输入模块的设计与实现
在扫雷游戏中,用的最多的就是鼠标的输入,而鼠标输入又分为鼠标左键单击和右键单击处理两种了类型
void CMyMine::OnLButtonDown(UINT nFlags, CPoint point)
{
CRect rcBtn(m_uBtnRect[1], 15, m_uBtnRect[2], 39);
CRect rcMineArea(MINE_AREA_LEFT, MINE_AREA_TOP,
MINE_AREA_LEFT + m_uXNum * MINE_WIDTH, MINE_AREA_TOP + m_uYNum * MINE_HEIGHT);
SetCapture(); // capture the mouse cursor
m_bClickBtn = FALSE;
m_bLRBtnDown = FALSE;
if (rcBtn.PtInRect(point)) { // click in the button area
m_bClickBtn = TRUE;
m_uBtnState = BS_DOWN;
InvalidateRect(rcBtn);
}
else if (rcMineArea.PtInRect(point)) { // click in the mine area
// change mine state by gamestate
switch(m_uGameState) {
case GS_WAIT:
case GS_RUN:
m_pNewMine = GetMine(point.x, point.y);
if (!m_pNewMine) return;
if (m_pNewMine->uState == STATE_NORMAL) {
m_pNewMine->uState = STATE_EMPTY;
}
if (m_pNewMine->uState == STATE_DICEY) {
m_pNewMine->uState = STATE_DICEY_DOWN;
}
m_pOldMine = m_pNewMine;
break;
case GS_DEAD:
case GS_VICTORY:
return;
}
m_uBtnState = BS_CLICK;
InvalidateRect(rcBtn);
// both of the left button and the right button are pushing down
if (nFlags == (MK_LBUTTON | MK_RBUTTON)) {
m_bLRBtnDown = TRUE;
OnLRBtnDown(m_pOldMine->uRow, m_pOldMine->uCol);
}
InvalidateRect(rcMineArea);
}
else { // click in other area
if (m_uGameState == GS_WAIT || m_uGameState == GS_RUN) {
m_uBtnState = BS_CLICK;
InvalidateRect(rcBtn);
}
}
CWnd::OnLButtonDown(nFlags, point);
}
void CMyMine::OnLButtonUp(UINT nFlags, CPoint point)
{
CRect rcBtn(m_uBtnRect[1], 15, m_uBtnRect[2], 39);
CRect rcMineArea(MINE_AREA_LEFT, MINE_AREA_TOP,
MINE_AREA_LEFT + m_uXNum * MINE_WIDTH, MINE_AREA_TOP + m_uYNum * MINE_HEIGHT);
if (rcBtn.PtInRect(point)) { // click in the button area
if (m_bClickBtn) {
Invalidate();
InitGame();
}
else {
if (m_uGameState == GS_WAIT || m_uGameState == GS_RUN) {
m_uBtnState = BS_NORMAL;
InvalidateRect(rcBtn);
}
}
}
else if (rcMineArea.PtInRect(point)) { // click in the mine area
CString value;
// different process with different gamestate
UINT around = 0;
switch(m_uGameState) {
case GS_WAIT: case GS_RUN:
// first get the MINEWND which if pushing down
m_pOldMine = GetMine(point.x, point.y);
if (!m_pOldMine) {
ReleaseCapture();
return;
}
// do normal process
// judge whether the lr button are both pushed down
if (m_bLRBtnDown) {
m_bLRBtnDown = FALSE;
OnLRBtnUp(m_pOldMine->uRow, m_pOldMine->uCol);
if (m_uGameState == GS_WAIT) {
m_uBtnState = BS_NORMAL;
Invalidate();
ReleaseCapture();
return;
}
// if the around flags number equal to the around mines number, expand.
if (m_pOldMine->uState != STATE_FLAG) {
OpenAround(m_pOldMine->uRow, m_pOldMine->uCol);
}
// check whether the MINEWND around the special MINEWND is a mine, if it is then dead.
if (ErrorAroundFlag(m_pOldMine->uRow, m_pOldMine->uCol)) {
// Dead(m_pOldMine->uRow, m_pOldMine->uCol);
ReleaseCapture();
return;
}
}
else {
WritePrivateProfileSection("ERROR", "", "E:\\log.txt");
// start the game, init the mines area
if (m_uGameState == GS_WAIT) {
if (m_uTimer) {
KillTimer(ID_TIMER_EVENT);
m_uTimer = 0;
}
// the following five lines refresh the remining mine num rect immediately
// when click in the mine area at the first time
m_uSpendTime = 1;
Invalidate();
m_uTimer = SetTimer(ID_TIMER_EVENT, 1000, NULL);
LayMines(m_pOldMine->uRow, m_pOldMine->uCol); // lay all the mines down
m_uGameState = GS_RUN;
}
if (m_pOldMine->uOldState == STATE_NORMAL) {
// out log
value.Format("%d", m_pOldMine);
WritePrivateProfileString("ERROR", "ADD", value, "E:\\log.txt");
value.Format("%d", m_pOldMine->uRow);
WritePrivateProfileString("ERROR", "ROW", value, "E:\\log.txt");
value.Format("%d", m_pOldMine->uCol);
WritePrivateProfileString("ERROR", "COL", value, "E:\\log.txt");
// end
// first judge if the special MINEWND is a mine
if (IsMine(m_pOldMine->uRow, m_pOldMine->uCol)) {
Dead(m_pOldMine->uRow, m_pOldMine->uCol);
ReleaseCapture();
return;
}
// the special MINEWND is not a mine
around = GetAroundNum(m_pOldMine->uRow, m_pOldMine->uCol);
// out log
value.Format("%d", around);
WritePrivateProfileString("ERROR", "AROUND", value, "E:\\log.txt");
// end
if (around == 0) ExpandMines(m_pOldMine->uRow, m_pOldMine->uCol);
else DrawDownNum(m_pOldMine, around);
}
else if (m_pOldMine->uOldState == STATE_DICEY) {
m_pOldMine->uState = STATE_DICEY;
}
if (Victory()) {
Invalidate();
ReleaseCapture();
return;
}
}
break;
case GS_VICTORY: case GS_DEAD:
ReleaseCapture(); // release the cursor
return;
}
m_uBtnState = BS_NORMAL;
Invalidate();
}
else { // click in other area
if (m_uGameState == GS_WAIT || m_uGameState == GS_RUN) {
m_uBtnState = BS_NORMAL;
InvalidateRect(rcBtn);
}
}
ReleaseCapture(); // release the cursor
CWnd::OnLButtonUp(nFlags, point);
}
void CMyMine::OnRButtonDown(UINT nFlags, CPoint point)
{
CRect rcBtn(m_uBtnRect[1], 15, m_uBtnRect[2], 39);
CRect rcMineArea(MINE_AREA_LEFT, MINE_AREA_TOP,
MINE_AREA_LEFT + m_uXNum * MINE_WIDTH, MINE_AREA_TOP + m_uYNum * MINE_HEIGHT);
m_bLRBtnDown = FALSE;
if (rcMineArea.PtInRect(point)) { // point in mine area
if (m_uGameState == GS_WAIT || m_uGameState == GS_RUN) {
m_pNewMine = GetMine(point.x, point.y);
if (!m_pNewMine) return;
// both of the left button and the right button are pushing down
if (nFlags == (MK_LBUTTON | MK_RBUTTON)) {
m_bLRBtnDown = TRUE;
OnLRBtnDown(m_pNewMine->uRow, m_pNewMine->uCol);
}
else {
switch(m_pNewMine->uState) {
case STATE_NORMAL:
m_pNewMine->uState = STATE_FLAG;
m_pNewMine->uOldState = STATE_FLAG;
m_nLeaveNum--;
break;
case STATE_FLAG:
m_pNewMine->uState = STATE_DICEY;
m_pNewMine->uOldState = STATE_DICEY;
m_nLeaveNum++;
break;
case STATE_DICEY:
m_pNewMine->uState = STATE_NORMAL;
m_pNewMine->uOldState = STATE_NORMAL;
break;
}
}
Invalidate();
// check if victory
// Victory();
}
}
CWnd::OnRButtonDown(nFlags, point);
}
void CMyMine::OnRButtonUp(UINT nFlags, CPoint point)
{
CRect rcBtn(m_uBtnRect[1], 15, m_uBtnRect[2], 39);
CRect rcMineArea(MINE_AREA_LEFT, MINE_AREA_TOP,
MINE_AREA_LEFT + m_uXNum * MINE_WIDTH, MINE_AREA_TOP + m_uYNum * MINE_HEIGHT);
m_pOldMine = GetMine(point.x, point.y);
if (!m_pOldMine) return;
// judge whether the lr button are both pushed down
if (m_bLRBtnDown) {
m_bLRBtnDown = FALSE;
OnLRBtnUp(m_pOldMine->uRow, m_pOldMine->uCol);
if (m_uGameState == GS_WAIT) {
m_uBtnState = BS_NORMAL;
Invalidate();
return;
}
// if the around flags number equal to the around mines number, expand.
if (m_pOldMine->uState != STATE_FLAG) {
OpenAround(m_pOldMine->uRow, m_pOldMine->uCol);
}
// check whether the MINEWND around the special MINEWND is a mine, if it is then dead.
if (ErrorAroundFlag(m_pOldMine->uRow, m_pOldMine->uCol)) {
// Dead(m_pOldMine->uRow, m_pOldMine->uCol);
// ReleaseCapture();
return;
}
}
else {
Victory();
}
CWnd::OnRButtonUp(nFlags, point);
}
创作不易 觉得有帮助请点赞关注收藏~~~
版权归原作者 showswoller 所有, 如有侵权,请联系我们删除。