需要源码和资源请点赞关注收藏后评论区留言私信~~~
在前面的博客中已经讲解了推箱子游戏的菜单和各种对话框的实现,下面对推箱子游戏的核心算法设计和实现进行讲解
一、地图文件读取模块的设计与实现
地图文件读取模块,主要负责将地图文件进行读取,并把相应的文件数据转换成地图显示出来,其设计步骤如下
1:读取当前文件夹中的地图文件
2:判断当前选择关口是否在文件中存在
3:如果存在则把当前关口的地图信息放置到地图数组中
其实现代码如下
void CBoxManDlg::loadMap(int iMissionNum)
{
CString str;
str.Format("[%d]", iMissionNum);
FILE *pFile = fopen("map.txt", "rb");
if (pFile == NULL)
return;
char cTmp[20];
fgets(cTmp, 20, pFile);
while (strncmp(cTmp, str, 3) != 0)
{
fgets(cTmp, 20, pFile);
}
for (int i = 0; i < 14; i++)
fgets(m_cMap[i], 20, pFile);
fclose(pFile);
}
二、地图绘制模块的设计与实现
绘制地图模块主要负责将地图数组中的数据绘制成地图图像,其设计分为如下几个步骤
1:根据要求,实现不同类型格子的绘制函数,地图数组以及地图文件中各个字符代表的意思如下
2:读取地图数据,根据不同的数据调用不同的绘图函数
代码如下
void CBoxManDlg::drawMap(CDC *pDC)
{
int i, j, x, y;
for (i = 0; i < 14; i++)
{
for (j = 0; j < 16; j++)
{
x = j * 20;
y = i * 20;
switch (m_cMap[i][j])
{
case MAP_BACK://0
drawBack(x, y, pDC);
break;
case MAP_WHITEWALL://1
drawWhiteWall(x, y, pDC);
break;
case MAP_BLUEWALL://2
drawBlueWall(x, y, pDC);
break;
case MAP_BALL://3
drawBall(x, y, pDC);
break;
case MAP_BOX://4
drawBox(x, y, pDC);
break;
case MAP_REDBOX://5
drawRedBox(x, y, pDC);
break;
case MAP_MAN://6
drawMan(x, y, pDC);
break;
case MAP_MANBALL://7
drawManBall(x, y, pDC);
break;
}
}
}
COLORREF crText = pDC->GetTextColor();
COLORREF crBack = pDC->GetBkColor();
pDC->SetTextColor(RGB(255, 0, 0));
pDC->SetBkColor(RGB(255, 255, 255));
CString str;
str.Format("当前等级: %02d", g_level);
pDC->TextOut(330, 50, str);
str.Format("已走步数: %03d", passtime);
pDC->TextOut(330, 100, str);
}
void CBoxManDlg::drawBack(int x, int y, CDC *pDC)
{
COLORREF clr = RGB(0, 0, 0);
pDC->FillSolidRect(x, y, 20, 20, clr);
}
void CBoxManDlg::drawWhiteWall(int x, int y, CDC *pDC)
{
COLORREF clr1 = RGB(255, 255, 255);
COLORREF clr2 = RGB(48, 48, 48);
COLORREF clr3 = RGB(192, 192, 192);
pDC->FillSolidRect(x, y, 19, 19, clr1);
pDC->FillSolidRect(x + 1, y + 1, 19, 19, clr2);
pDC->FillSolidRect(x + 1, y + 1, 18, 18, clr3);
pDC->MoveTo(x, y + 10);
pDC->LineTo(x + 20, y + 10);
pDC->MoveTo(x + 10, y + 10);
pDC->LineTo(x + 10, y + 20);
}
void CBoxManDlg::drawBlueWall(int x, int y, CDC *pDC)
{
COLORREF clr = RGB(0, 0, 255);
pDC->FillSolidRect(x, y, 20, 20, clr);
pDC->MoveTo(x, y + 10);
pDC->LineTo(x + 20, y + 10);
pDC->MoveTo(x + 10, y + 10);
pDC->LineTo(x + 10, y + 20);
}
void CBoxManDlg::drawBall(int x, int y, CDC *pDC)
{
COLORREF clr = RGB(0, 0, 255);
pDC->FillSolidRect(x, y, 20, 20, clr);
pDC->MoveTo(x, y + 10);
pDC->LineTo(x + 20, y + 10);
pDC->MoveTo(x + 10, y + 10);
pDC->LineTo(x + 10, y + 20);
pDC->Ellipse(x, y, x + 20, y + 20);
pDC->Ellipse(x + 5, y + 5, x + 15, y + 15);
}
void CBoxManDlg::drawBox(int x, int y, CDC *pDC)
{
COLORREF clr = RGB(255, 255, 0);
pDC->FillSolidRect(x, y, 20, 20, clr);
COLORREF clr2 = RGB(255, 192, 0);
pDC->FillSolidRect(x + 2, y + 2, 16, 16, clr2);
COLORREF clr3 = RGB(0, 0, 0);
pDC->SetPixel(x + 3, y + 3, clr3);
pDC->SetPixel(x + 17, y + 3, clr3);
pDC->SetPixel(x + 3, y + 17, clr3);
pDC->SetPixel(x + 17, y + 17, clr3);
}
void CBoxManDlg::drawRedBox(int x, int y, CDC *pDC)
{
COLORREF clr = RGB(255, 255, 0);
pDC->FillSolidRect(x, y, 20, 20, clr);
COLORREF clr2 = RGB(255, 0, 0);
pDC->FillSolidRect(x + 2, y + 2, 16, 16, clr2);
COLORREF clr3 = RGB(0, 0, 0);
pDC->SetPixel(x + 3, y + 3, clr3);
pDC->SetPixel(x + 17, y + 3, clr3);
pDC->SetPixel(x + 3, y + 17, clr3);
pDC->SetPixel(x + 17, y + 17, clr3);
}
void CBoxManDlg::drawMan(int x, int y, CDC *pDC)
{
COLORREF clr = RGB(0, 0, 255); //蓝色墙
pDC->FillSolidRect(x, y, 20, 20, clr);
pDC->MoveTo(x, y + 10);
pDC->LineTo(x + 20, y + 10);
pDC->MoveTo(x + 10, y + 10);
pDC->LineTo(x + 10, y + 20);
pDC->Ellipse(x + 6, y + 2, x + 14, y + 10); //人头
pDC->MoveTo(x + 2, y + 11); //人手
pDC->LineTo(x + 18, y + 11);
pDC->MoveTo(x + 10, y + 10); //人身体
pDC->LineTo(x + 10, y + 12);
pDC->MoveTo(x + 2, y + 20); //人脚
pDC->LineTo(x + 10, y + 12);
pDC->LineTo(x + 18, y +20);
}
void CBoxManDlg::drawManBall(int x, int y, CDC *pDC)
{
COLORREF clr = RGB(0, 0, 255); //球
pDC->FillSolidRect(x, y, 20, 20, clr);
pDC->MoveTo(x, y + 10);
pDC->LineTo(x + 20, y + 10);
pDC->MoveTo(x + 10, y + 10);
pDC->LineTo(x + 10, y + 20);
pDC->Ellipse(x, y, x + 20, y + 20);
pDC->Ellipse(x + 5, y + 5, x + 15, y + 15);
pDC->Ellipse(x + 6, y + 2, x + 14, y + 10); //人头
pDC->MoveTo(x + 2, y + 11); //人手
pDC->LineTo(x + 18, y + 11);
pDC->MoveTo(x + 10, y + 10); //人身体
pDC->LineTo(x + 10, y + 12);
pDC->MoveTo(x + 2, y + 20); //人脚
pDC->LineTo(x + 10, y + 12);
pDC->LineTo(x + 18, y +20);
}
三、键盘操作模块的设计与实现
键盘操作模块主要负责接收玩家键盘输入并进行箱子移动等处理,其设计比较简单,只需要通过如下几步即可实现
1:通过截获当前窗口键盘按下消息来判断玩家按下的按键
2:根据玩家标下的按键把主角的相关坐标进行加减,
3:增加后的数据与地图数组中的数据进行比较,只要不是白墙就可以移动,如果是箱子还需要将箱子的坐标进行移动
4:但要注意,要判断箱子移动后的坐标是否可以移动
代码如下
BOOL CBoxManDlg::PreTranslateMessage(MSG* pMsg)
{
if(pMsg->message == WM_KEYDOWN)
{
updateMap(pMsg->wParam);
Invalidate(false);
if (isFinish())
{
AfxMessageBox("您获得胜利,将进入下一关!");
g_level = g_level +1;
if (g_level > g_maxlevel)
g_level = 1;
GameStart();
}
}
return CDialog::PreTranslateMessage(pMsg);
}
void CBoxManDlg::updateMap(UINT nChar)
{
int x1, y1, x2, y2, x3, y3;
x1 = m_ptManPosition.x;
y1 = m_ptManPosition.y;
switch (nChar)
{
case VK_UP:
x2 = x1;
y2 = y1 - 1;
x3 = x1;
y3 = y1 - 2;
ReDrawMap(x1, y1, x2, y2, x3, y3);
break;
case VK_DOWN:
x2 = x1;
y2 = y1 + 1;
x3 = x1;
y3 = y1 + 2;
ReDrawMap(x1, y1, x2, y2, x3, y3);
break;
case VK_LEFT:
x2 = x1 - 1;
y2 = y1;
x3 = x1 - 2;
y3 = y1;
ReDrawMap(x1, y1, x2, y2, x3, y3);
break;
case VK_RIGHT:
x2 = x1 + 1;
y2 = y1;
x3 = x1 + 2;
y3 = y1;
ReDrawMap(x1, y1, x2, y2, x3, y3);
break;
default:
break;
}
}
void CBoxManDlg::ReDrawMap(int x1, int y1, int x2, int y2, int x3, int y3)
{
switch (m_cMap[y2][x2])
{
case MAP_BACK: //地图有问题
MessageBox("地图有问题");
break;
case MAP_WHITEWALL:
break;
case MAP_BLUEWALL:
m_cMap[y2][x2] = MAP_MAN;
if (m_cMap[y1][x1] == MAP_MAN)
m_cMap[y1][x1] = MAP_BLUEWALL;
else if (m_cMap[y1][x1] == MAP_MANBALL)
m_cMap[y1][x1] = MAP_BALL;
m_ptManPosition.x = x2;
m_ptManPosition.y = y2;
passtime++;
break;
case MAP_BALL:
m_cMap[y2][x2] = MAP_MANBALL;
if (m_cMap[y1][x1] == MAP_MAN)
m_cMap[y1][x1] = MAP_BLUEWALL;
else if (m_cMap[y1][x1] == MAP_MANBALL)
m_cMap[y1][x1] = MAP_BALL;
m_ptManPosition.x = x2;
m_ptManPosition.y = y2;
passtime++;
break;
case MAP_BOX:
if (m_cMap[y3][x3] == MAP_BALL)
{
m_cMap[y3][x3] = MAP_REDBOX;
m_cMap[y2][x2] = MAP_MAN;
if (m_cMap[y1][x1] == MAP_MAN)
m_cMap[y1][x1] = MAP_BLUEWALL;
else if (m_cMap[y1][x1] == MAP_MANBALL)
m_cMap[y1][x1] = MAP_BALL;
m_ptManPosition.x = x2;
m_ptManPosition.y = y2;
passtime++;
}
else if (m_cMap[y3][x3] == MAP_BLUEWALL)
{
m_cMap[y3][x3] = MAP_BOX;
m_cMap[y2][x2] = MAP_MAN;
if (m_cMap[y1][x1] == MAP_MAN)
m_cMap[y1][x1] = MAP_BLUEWALL;
else if (m_cMap[y1][x1] == MAP_MANBALL)
m_cMap[y1][x1] = MAP_BALL;
m_ptManPosition.x = x2;
m_ptManPosition.y = y2;
passtime++;
}
break;
case MAP_REDBOX:
if (m_cMap[y3][x3] == MAP_BALL)
{
m_cMap[y3][x3] = MAP_REDBOX;
m_cMap[y2][x2] = MAP_MANBALL;
if (m_cMap[y1][x1] == MAP_MAN)
m_cMap[y1][x1] = MAP_BLUEWALL;
else if (m_cMap[y1][x1] == MAP_MANBALL)
m_cMap[y1][x1] = MAP_BALL;
m_ptManPosition.x = x2;
m_ptManPosition.y = y2;
passtime++;
}
else if (m_cMap[y3][x3] == MAP_BLUEWALL)
{
m_cMap[y3][x3] = MAP_BOX;
m_cMap[y2][x2] = MAP_MANBALL;
if (m_cMap[y1][x1] == MAP_MAN)
m_cMap[y1][x1] = MAP_BLUEWALL;
else if (m_cMap[y1][x1] == MAP_MANBALL)
m_cMap[y1][x1] = MAP_BALL;
m_ptManPosition.x = x2;
m_ptManPosition.y = y2;
passtime++;
}
break;
case MAP_MAN: //地图有问题
MessageBox("地图有问题");
break;
case MAP_MANBALL: //地图有问题
MessageBox("地图有问题");
break;
}
}
void CBoxManDlg::loadMap(int iMissionNum)
{
CString str;
str.Format("[%d]", iMissionNum);
FILE *pFile = fopen("map.txt", "rb");
if (pFile == NULL)
return;
char cTmp[20];
fgets(cTmp, 20, pFile);
while (strncmp(cTmp, str, 3) != 0)
{
fgets(cTmp, 20, pFile);
}
for (int i = 0; i < 14; i++)
fgets(m_cMap[i], 20, pFile);
fclose(pFile);
}
四、游戏规则模块的设计与实现
游戏规则模块,注意负责游戏规则的判断,其设计方法比较简单,需要在每次玩家移动主角后,对当前地图数组进行判断
BOOL CBoxManDlg::isFinish()
{
for (int i = 0; i < 14; i++)
{
for (int j = 0; j < 16; j++)
{
if (m_cMap[i][j] == MAP_BALL || m_cMap[i][j] == MAP_MANBALL)
{
return FALSE;
}
}
}
return TRUE;
}
五、主对话框的设计与实现
主要有如下几个部分
1:游戏初始化处理函数
2:菜单初始化处理函数
3:绘图函数处理
void CBoxManDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CPaintDC dc(this);
drawMap(&dc);
CDialog::OnPaint();
}
}
创作不易 觉得有帮助请点赞关注收藏~~~