深圳幻海软件技术有限公司 欢迎您!

Visual C++实现推箱子游戏的核心算法设计与实现(附源码和和资源)

2023-04-14

需要源码和资源请点赞关注收藏后评论区留言私信~~~在前面的博客中已经讲解了推箱子游戏的菜单和各种对话框的实现,下面对推箱子游戏的核心算法设计和实现进行讲解一、地图文件读取模块的设计与实现地图文件读取模块,主要负责将地图文件进行读取,并把相应的文件数据转换成地图显示出来,其设计步骤如下1:读取当前文件

需要源码和资源请点赞关注收藏后评论区留言私信~~~

在前面的博客中已经讲解了推箱子游戏的菜单和各种对话框的实现,下面对推箱子游戏的核心算法设计和实现进行讲解

一、地图文件读取模块的设计与实现

地图文件读取模块,主要负责将地图文件进行读取,并把相应的文件数据转换成地图显示出来,其设计步骤如下

1:读取当前文件夹中的地图文件

2:判断当前选择关口是否在文件中存在

3:如果存在则把当前关口的地图信息放置到地图数组中

其实现代码如下

  1. void CBoxManDlg::loadMap(int iMissionNum)
  2. {
  3. CString str;
  4. str.Format("[%d]", iMissionNum);
  5. FILE *pFile = fopen("map.txt", "rb");
  6. if (pFile == NULL)
  7. return;
  8. char cTmp[20];
  9. fgets(cTmp, 20, pFile);
  10. while (strncmp(cTmp, str, 3) != 0)
  11. {
  12. fgets(cTmp, 20, pFile);
  13. }
  14. for (int i = 0; i < 14; i++)
  15. fgets(m_cMap[i], 20, pFile);
  16. fclose(pFile);
  17. }

二、地图绘制模块的设计与实现

绘制地图模块主要负责将地图数组中的数据绘制成地图图像,其设计分为如下几个步骤

1:根据要求,实现不同类型格子的绘制函数,地图数组以及地图文件中各个字符代表的意思如下

2:读取地图数据,根据不同的数据调用不同的绘图函数

代码如下

  1. void CBoxManDlg::drawMap(CDC *pDC)
  2. {
  3. int i, j, x, y;
  4. for (i = 0; i < 14; i++)
  5. {
  6. for (j = 0; j < 16; j++)
  7. {
  8. x = j * 20;
  9. y = i * 20;
  10. switch (m_cMap[i][j])
  11. {
  12. case MAP_BACK://0
  13. drawBack(x, y, pDC);
  14. break;
  15. case MAP_WHITEWALL://1
  16. drawWhiteWall(x, y, pDC);
  17. break;
  18. case MAP_BLUEWALL://2
  19. drawBlueWall(x, y, pDC);
  20. break;
  21. case MAP_BALL://3
  22. drawBall(x, y, pDC);
  23. break;
  24. case MAP_BOX://4
  25. drawBox(x, y, pDC);
  26. break;
  27. case MAP_REDBOX://5
  28. drawRedBox(x, y, pDC);
  29. break;
  30. case MAP_MAN://6
  31. drawMan(x, y, pDC);
  32. break;
  33. case MAP_MANBALL://7
  34. drawManBall(x, y, pDC);
  35. break;
  36. }
  37. }
  38. }
  39. COLORREF crText = pDC->GetTextColor();
  40. COLORREF crBack = pDC->GetBkColor();
  41. pDC->SetTextColor(RGB(255, 0, 0));
  42. pDC->SetBkColor(RGB(255, 255, 255));
  43. CString str;
  44. str.Format("当前等级: %02d", g_level);
  45. pDC->TextOut(330, 50, str);
  46. str.Format("已走步数: %03d", passtime);
  47. pDC->TextOut(330, 100, str);
  48. }
  49. void CBoxManDlg::drawBack(int x, int y, CDC *pDC)
  50. {
  51. COLORREF clr = RGB(0, 0, 0);
  52. pDC->FillSolidRect(x, y, 20, 20, clr);
  53. }
  54. void CBoxManDlg::drawWhiteWall(int x, int y, CDC *pDC)
  55. {
  56. COLORREF clr1 = RGB(255, 255, 255);
  57. COLORREF clr2 = RGB(48, 48, 48);
  58. COLORREF clr3 = RGB(192, 192, 192);
  59. pDC->FillSolidRect(x, y, 19, 19, clr1);
  60. pDC->FillSolidRect(x + 1, y + 1, 19, 19, clr2);
  61. pDC->FillSolidRect(x + 1, y + 1, 18, 18, clr3);
  62. pDC->MoveTo(x, y + 10);
  63. pDC->LineTo(x + 20, y + 10);
  64. pDC->MoveTo(x + 10, y + 10);
  65. pDC->LineTo(x + 10, y + 20);
  66. }
  67. void CBoxManDlg::drawBlueWall(int x, int y, CDC *pDC)
  68. {
  69. COLORREF clr = RGB(0, 0, 255);
  70. pDC->FillSolidRect(x, y, 20, 20, clr);
  71. pDC->MoveTo(x, y + 10);
  72. pDC->LineTo(x + 20, y + 10);
  73. pDC->MoveTo(x + 10, y + 10);
  74. pDC->LineTo(x + 10, y + 20);
  75. }
  76. void CBoxManDlg::drawBall(int x, int y, CDC *pDC)
  77. {
  78. COLORREF clr = RGB(0, 0, 255);
  79. pDC->FillSolidRect(x, y, 20, 20, clr);
  80. pDC->MoveTo(x, y + 10);
  81. pDC->LineTo(x + 20, y + 10);
  82. pDC->MoveTo(x + 10, y + 10);
  83. pDC->LineTo(x + 10, y + 20);
  84. pDC->Ellipse(x, y, x + 20, y + 20);
  85. pDC->Ellipse(x + 5, y + 5, x + 15, y + 15);
  86. }
  87. void CBoxManDlg::drawBox(int x, int y, CDC *pDC)
  88. {
  89. COLORREF clr = RGB(255, 255, 0);
  90. pDC->FillSolidRect(x, y, 20, 20, clr);
  91. COLORREF clr2 = RGB(255, 192, 0);
  92. pDC->FillSolidRect(x + 2, y + 2, 16, 16, clr2);
  93. COLORREF clr3 = RGB(0, 0, 0);
  94. pDC->SetPixel(x + 3, y + 3, clr3);
  95. pDC->SetPixel(x + 17, y + 3, clr3);
  96. pDC->SetPixel(x + 3, y + 17, clr3);
  97. pDC->SetPixel(x + 17, y + 17, clr3);
  98. }
  99. void CBoxManDlg::drawRedBox(int x, int y, CDC *pDC)
  100. {
  101. COLORREF clr = RGB(255, 255, 0);
  102. pDC->FillSolidRect(x, y, 20, 20, clr);
  103. COLORREF clr2 = RGB(255, 0, 0);
  104. pDC->FillSolidRect(x + 2, y + 2, 16, 16, clr2);
  105. COLORREF clr3 = RGB(0, 0, 0);
  106. pDC->SetPixel(x + 3, y + 3, clr3);
  107. pDC->SetPixel(x + 17, y + 3, clr3);
  108. pDC->SetPixel(x + 3, y + 17, clr3);
  109. pDC->SetPixel(x + 17, y + 17, clr3);
  110. }
  111. void CBoxManDlg::drawMan(int x, int y, CDC *pDC)
  112. {
  113. COLORREF clr = RGB(0, 0, 255); //蓝色墙
  114. pDC->FillSolidRect(x, y, 20, 20, clr);
  115. pDC->MoveTo(x, y + 10);
  116. pDC->LineTo(x + 20, y + 10);
  117. pDC->MoveTo(x + 10, y + 10);
  118. pDC->LineTo(x + 10, y + 20);
  119. pDC->Ellipse(x + 6, y + 2, x + 14, y + 10); //人头
  120. pDC->MoveTo(x + 2, y + 11); //人手
  121. pDC->LineTo(x + 18, y + 11);
  122. pDC->MoveTo(x + 10, y + 10); //人身体
  123. pDC->LineTo(x + 10, y + 12);
  124. pDC->MoveTo(x + 2, y + 20); //人脚
  125. pDC->LineTo(x + 10, y + 12);
  126. pDC->LineTo(x + 18, y +20);
  127. }
  128. void CBoxManDlg::drawManBall(int x, int y, CDC *pDC)
  129. {
  130. COLORREF clr = RGB(0, 0, 255); //球
  131. pDC->FillSolidRect(x, y, 20, 20, clr);
  132. pDC->MoveTo(x, y + 10);
  133. pDC->LineTo(x + 20, y + 10);
  134. pDC->MoveTo(x + 10, y + 10);
  135. pDC->LineTo(x + 10, y + 20);
  136. pDC->Ellipse(x, y, x + 20, y + 20);
  137. pDC->Ellipse(x + 5, y + 5, x + 15, y + 15);
  138. pDC->Ellipse(x + 6, y + 2, x + 14, y + 10); //人头
  139. pDC->MoveTo(x + 2, y + 11); //人手
  140. pDC->LineTo(x + 18, y + 11);
  141. pDC->MoveTo(x + 10, y + 10); //人身体
  142. pDC->LineTo(x + 10, y + 12);
  143. pDC->MoveTo(x + 2, y + 20); //人脚
  144. pDC->LineTo(x + 10, y + 12);
  145. pDC->LineTo(x + 18, y +20);
  146. }

三、键盘操作模块的设计与实现

键盘操作模块主要负责接收玩家键盘输入并进行箱子移动等处理,其设计比较简单,只需要通过如下几步即可实现

1:通过截获当前窗口键盘按下消息来判断玩家按下的按键

2:根据玩家标下的按键把主角的相关坐标进行加减,

3:增加后的数据与地图数组中的数据进行比较,只要不是白墙就可以移动,如果是箱子还需要将箱子的坐标进行移动

4:但要注意,要判断箱子移动后的坐标是否可以移动

代码如下

  1. BOOL CBoxManDlg::PreTranslateMessage(MSG* pMsg)
  2. {
  3. if(pMsg->message == WM_KEYDOWN)
  4. {
  5. updateMap(pMsg->wParam);
  6. Invalidate(false);
  7. if (isFinish())
  8. {
  9. AfxMessageBox("您获得胜利,将进入下一关!");
  10. g_level = g_level +1;
  11. if (g_level > g_maxlevel)
  12. g_level = 1;
  13. GameStart();
  14. }
  15. }
  16. return CDialog::PreTranslateMessage(pMsg);
  17. }
  18. void CBoxManDlg::updateMap(UINT nChar)
  19. {
  20. int x1, y1, x2, y2, x3, y3;
  21. x1 = m_ptManPosition.x;
  22. y1 = m_ptManPosition.y;
  23. switch (nChar)
  24. {
  25. case VK_UP:
  26. x2 = x1;
  27. y2 = y1 - 1;
  28. x3 = x1;
  29. y3 = y1 - 2;
  30. ReDrawMap(x1, y1, x2, y2, x3, y3);
  31. break;
  32. case VK_DOWN:
  33. x2 = x1;
  34. y2 = y1 + 1;
  35. x3 = x1;
  36. y3 = y1 + 2;
  37. ReDrawMap(x1, y1, x2, y2, x3, y3);
  38. break;
  39. case VK_LEFT:
  40. x2 = x1 - 1;
  41. y2 = y1;
  42. x3 = x1 - 2;
  43. y3 = y1;
  44. ReDrawMap(x1, y1, x2, y2, x3, y3);
  45. break;
  46. case VK_RIGHT:
  47. x2 = x1 + 1;
  48. y2 = y1;
  49. x3 = x1 + 2;
  50. y3 = y1;
  51. ReDrawMap(x1, y1, x2, y2, x3, y3);
  52. break;
  53. default:
  54. break;
  55. }
  56. }
  57. void CBoxManDlg::ReDrawMap(int x1, int y1, int x2, int y2, int x3, int y3)
  58. {
  59. switch (m_cMap[y2][x2])
  60. {
  61. case MAP_BACK: //地图有问题
  62. MessageBox("地图有问题");
  63. break;
  64. case MAP_WHITEWALL:
  65. break;
  66. case MAP_BLUEWALL:
  67. m_cMap[y2][x2] = MAP_MAN;
  68. if (m_cMap[y1][x1] == MAP_MAN)
  69. m_cMap[y1][x1] = MAP_BLUEWALL;
  70. else if (m_cMap[y1][x1] == MAP_MANBALL)
  71. m_cMap[y1][x1] = MAP_BALL;
  72. m_ptManPosition.x = x2;
  73. m_ptManPosition.y = y2;
  74. passtime++;
  75. break;
  76. case MAP_BALL:
  77. m_cMap[y2][x2] = MAP_MANBALL;
  78. if (m_cMap[y1][x1] == MAP_MAN)
  79. m_cMap[y1][x1] = MAP_BLUEWALL;
  80. else if (m_cMap[y1][x1] == MAP_MANBALL)
  81. m_cMap[y1][x1] = MAP_BALL;
  82. m_ptManPosition.x = x2;
  83. m_ptManPosition.y = y2;
  84. passtime++;
  85. break;
  86. case MAP_BOX:
  87. if (m_cMap[y3][x3] == MAP_BALL)
  88. {
  89. m_cMap[y3][x3] = MAP_REDBOX;
  90. m_cMap[y2][x2] = MAP_MAN;
  91. if (m_cMap[y1][x1] == MAP_MAN)
  92. m_cMap[y1][x1] = MAP_BLUEWALL;
  93. else if (m_cMap[y1][x1] == MAP_MANBALL)
  94. m_cMap[y1][x1] = MAP_BALL;
  95. m_ptManPosition.x = x2;
  96. m_ptManPosition.y = y2;
  97. passtime++;
  98. }
  99. else if (m_cMap[y3][x3] == MAP_BLUEWALL)
  100. {
  101. m_cMap[y3][x3] = MAP_BOX;
  102. m_cMap[y2][x2] = MAP_MAN;
  103. if (m_cMap[y1][x1] == MAP_MAN)
  104. m_cMap[y1][x1] = MAP_BLUEWALL;
  105. else if (m_cMap[y1][x1] == MAP_MANBALL)
  106. m_cMap[y1][x1] = MAP_BALL;
  107. m_ptManPosition.x = x2;
  108. m_ptManPosition.y = y2;
  109. passtime++;
  110. }
  111. break;
  112. case MAP_REDBOX:
  113. if (m_cMap[y3][x3] == MAP_BALL)
  114. {
  115. m_cMap[y3][x3] = MAP_REDBOX;
  116. m_cMap[y2][x2] = MAP_MANBALL;
  117. if (m_cMap[y1][x1] == MAP_MAN)
  118. m_cMap[y1][x1] = MAP_BLUEWALL;
  119. else if (m_cMap[y1][x1] == MAP_MANBALL)
  120. m_cMap[y1][x1] = MAP_BALL;
  121. m_ptManPosition.x = x2;
  122. m_ptManPosition.y = y2;
  123. passtime++;
  124. }
  125. else if (m_cMap[y3][x3] == MAP_BLUEWALL)
  126. {
  127. m_cMap[y3][x3] = MAP_BOX;
  128. m_cMap[y2][x2] = MAP_MANBALL;
  129. if (m_cMap[y1][x1] == MAP_MAN)
  130. m_cMap[y1][x1] = MAP_BLUEWALL;
  131. else if (m_cMap[y1][x1] == MAP_MANBALL)
  132. m_cMap[y1][x1] = MAP_BALL;
  133. m_ptManPosition.x = x2;
  134. m_ptManPosition.y = y2;
  135. passtime++;
  136. }
  137. break;
  138. case MAP_MAN: //地图有问题
  139. MessageBox("地图有问题");
  140. break;
  141. case MAP_MANBALL: //地图有问题
  142. MessageBox("地图有问题");
  143. break;
  144. }
  145. }
  146. void CBoxManDlg::loadMap(int iMissionNum)
  147. {
  148. CString str;
  149. str.Format("[%d]", iMissionNum);
  150. FILE *pFile = fopen("map.txt", "rb");
  151. if (pFile == NULL)
  152. return;
  153. char cTmp[20];
  154. fgets(cTmp, 20, pFile);
  155. while (strncmp(cTmp, str, 3) != 0)
  156. {
  157. fgets(cTmp, 20, pFile);
  158. }
  159. for (int i = 0; i < 14; i++)
  160. fgets(m_cMap[i], 20, pFile);
  161. fclose(pFile);
  162. }

四、游戏规则模块的设计与实现

游戏规则模块,注意负责游戏规则的判断,其设计方法比较简单,需要在每次玩家移动主角后,对当前地图数组进行判断

  1. BOOL CBoxManDlg::isFinish()
  2. {
  3. for (int i = 0; i < 14; i++)
  4. {
  5. for (int j = 0; j < 16; j++)
  6. {
  7. if (m_cMap[i][j] == MAP_BALL || m_cMap[i][j] == MAP_MANBALL)
  8. {
  9. return FALSE;
  10. }
  11. }
  12. }
  13. return TRUE;
  14. }

五、主对话框的设计与实现

主要有如下几个部分

1:游戏初始化处理函数

2:菜单初始化处理函数

3:绘图函数处理

  1. void CBoxManDlg::OnPaint()
  2. {
  3. if (IsIconic())
  4. {
  5. CPaintDC dc(this); // device context for painting
  6. SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
  7. // Center icon in client rectangle
  8. int cxIcon = GetSystemMetrics(SM_CXICON);
  9. int cyIcon = GetSystemMetrics(SM_CYICON);
  10. CRect rect;
  11. GetClientRect(&rect);
  12. int x = (rect.Width() - cxIcon + 1) / 2;
  13. int y = (rect.Height() - cyIcon + 1) / 2;
  14. // Draw the icon
  15. dc.DrawIcon(x, y, m_hIcon);
  16. }
  17. else
  18. {
  19. CPaintDC dc(this);
  20. drawMap(&dc);
  21. CDialog::OnPaint();
  22. }
  23. }

 

 

 创作不易 觉得有帮助请点赞关注收藏~~~

文章知识点与官方知识档案匹配,可进一步学习相关知识
算法技能树首页概览44032 人正在系统学习中