需要源码和资源请点赞关注收藏后评论区留言私信~~~
在前面的博客中已经讲解了扫雷游戏的菜单和各种对话框的实现,下面将对扫雷游戏的核心算法设计与实现进行讲解
新游戏处理模块主要负责游戏中的游戏初始化以及开始游戏,其设计比较简单,只需要通过如下几个步骤即可实现
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);
}



创作不易 觉得有帮助请点赞关注收藏~~~
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数
我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden
当我尝试安装Ruby时遇到此错误。我试过查看this和this但无济于事➜~brewinstallrubyWarning:YouareusingOSX10.12.Wedonotprovidesupportforthispre-releaseversion.Youmayencounterbuildfailuresorotherbreakages.Pleasecreatepull-requestsinsteadoffilingissues.==>Installingdependenciesforruby:readline,libyaml,makedepend==>Installingrub
我真的为这个而疯狂。我一直在搜索答案并尝试我找到的所有内容,包括相关问题和stackoverflow上的答案,但仍然无法正常工作。我正在使用嵌套资源,但无法使表单正常工作。我总是遇到错误,例如没有路线匹配[PUT]"/galleries/1/photos"表格在这里:/galleries/1/photos/1/edit路线.rbresources:galleriesdoresources:photosendresources:galleriesresources:photos照片Controller.rbdefnew@gallery=Gallery.find(params[:galle
目录一.加解密算法数字签名对称加密DES(DataEncryptionStandard)3DES(TripleDES)AES(AdvancedEncryptionStandard)RSA加密法DSA(DigitalSignatureAlgorithm)ECC(EllipticCurvesCryptography)非对称加密签名与加密过程非对称加密的应用对称加密与非对称加密的结合二.数字证书图解一.加解密算法加密简单而言就是通过一种算法将明文信息转换成密文信息,信息的的接收方能够通过密钥对密文信息进行解密获得明文信息的过程。根据加解密的密钥是否相同,算法可以分为对称加密、非对称加密、对称加密和非
华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o
一、引擎主循环UE版本:4.27一、引擎主循环的位置:Launch.cpp:GuardedMain函数二、、GuardedMain函数执行逻辑:1、EnginePreInit:加载大多数模块int32ErrorLevel=EnginePreInit(CmdLine);PreInit模块加载顺序:模块加载过程:(1)注册模块中定义的UObject,同时为每个类构造一个类默认对象(CDO,记录类的默认状态,作为模板用于子类实例创建)(2)调用模块的StartUpModule方法2、FEngineLoop::Init()1、检查Engine的配置文件找出使用了哪一个GameEngine类(UGame
C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.
目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称