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

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

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

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

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

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

 

 

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

猜你喜欢

转载自blog.csdn.net/jiebaoshayebuhui/article/details/129545388
今日推荐