一  画刷,画笔

Windows 图像用户接口(GUI)通过在设备场景上绘制来提高可视化的性能。这需要了解如何创建和使用画刷与画笔。在实现这一经典游戏需要多种画刷,实现界面的绘制。

python 简易俄罗斯方块 俄罗斯方块编程思路_ci


二 俄罗斯方块要点


游戏中用4*4来表示各种方块(1表示绘制,0表示空),中通过数组来来判断绘制方块,先定义好画刷和画笔,再遍历4*4的方块区域。

 

for(int i=0; i<4; i++)
                   {
                            for(int j=0; j<4; j++)
                            {
                                     if(block_form[j][i]&& block_rect<4)
                                     {
                                               m_myBlockRect[block_rect].top    = (location_y+j)*LENGHT;
                                               m_myBlockRect[block_rect].bottom =LENGHT*(j+1+ location_y);
                                               m_myBlockRect[block_rect].left   = m_GameRect.left+ LENGHT*(i+location_x-2);
                                               m_myBlockRect[block_rect].right  = m_GameRect.left + LENGHT*(i+location_x-1);
                                               ++block_rect;
                                     }
                            }
                   }



                                                                                               *注: 具体方法见代码(下载链接已给出)

 

然后用20*12的数组表示,游戏区域。在区域中表示有方块(1表示绘制,0表示空)。同时可以从这个数组中判断是否有消行,是否游戏结束。


三 音乐播放

游戏中一般都会有配音,本程序使用“mid”文件,优点文件较小适合小型游戏。给程序配了6首音乐,不断的循环。

python 简易俄罗斯方块 俄罗斯方块编程思路_及代码下载_02


图1 效果

音乐播放,可以在定时时判断音乐是否播放完,若播放完毕则播放下一首。同时也可实现手动选择歌曲。

void CRussiaView::OnPlaymid(int which)
{
	CString mid_name("");
	static int mid_state=0;

	if(which!=6)
	{
		mid_length=0;
		char time_length[60]={0};
		char errBuf[100];
		memset(errBuf, 0, 60* sizeof(char));
		HWND hWnd;
		MCIERROR mciError;
		if(mid_state==0)
		{	
			mid_name.Format(".\\music\\%d.mid",which);
			// TODO: 在此添加命令处理程序代码	
			hWnd = GetSafeHwnd();	
			mid_name.Format("open %s type sequencer alias bkMusic",mid_name);

			//打开设备
			mciError=mciSendString(mid_name, errBuf, sizeof(errBuf), NULL);
			if (mciError == 0)
			{//如果打开成功则播放
				mciSendString(_T("play bkMusic notify"),NULL,0, hWnd);
				//根据播放操作是否成功决定是否关闭设备				
			}
			else mciSendString(_T("close bkMusic"),NULL,0,NULL);
			mid_state=1;
		}
		mciSendString("set bkMusic time format TMSF",errBuf,50,NULL);//设置时间格式为分秒格
		mciSendString("status bkMusic length ",time_length,sizeof(time_length),NULL);	//获取歌曲长度信息
		mid_length= atoi(time_length);//把时间转
		mciSendString("play bkMusic",errBuf,50,NULL);//如果要单首歌曲循环播放。"play 设备1 repeat"

		///   repeat
		mciSendString("status bkMusic position",errBuf,sizeof(errBuf),NULL);//获取播放歌曲的进度,
		int position=atoi(errBuf);//转化为整型数据

		if(position>=mid_length-7)
		{
			mciSendString("close bkMusic",errBuf,sizeof(errBuf),NULL);
			//OnPlaymid(which_mid);
			mciSendString(_T("close bkMusic"),NULL,0,NULL);
			mid_name.Format(".\\music\\%d.mid",which);

			hWnd = GetSafeHwnd();
			mid_name.Format("open %s type sequencer alias bkMusic",mid_name);

			//打开设备
			mciError=mciSendString(mid_name, errBuf, sizeof(errBuf), NULL);
			if (mciError == 0)
			{//如果打开成功则播放
				mciSendString(_T("play bkMusic notify"),NULL,0, hWnd);
				//根据播放操作是否成功决定是否关闭设备
			}
			else
				mciSendString(_T("close bkMusic"),NULL,0,NULL);

			++which_mid;
			if(which_mid==6)
				which_mid=0;
		}
	}
	else
		mciSendString(_T("close bkMusic"),NULL,0,NULL);
}



四 窗口设计

窗口绘制时考虑到当窗口尺寸变化时,必须重画窗口。所以在游戏中所有区域,和游戏方块的长度都是由变量组成这些变量会随着窗口的变化而变化。在最小化的时候,程序会继续运行但绘制的画面不保存,所以在最大化后重新绘制窗口。

游戏运行效果。

python 简易俄罗斯方块 俄罗斯方块编程思路_ci_03



图2 效果


python 简易俄罗斯方块 俄罗斯方块编程思路_python 简易俄罗斯方块_04

图3 效果

按键响应:


void CRussiaView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
		// TODO: 在此添加消息处理程序代码和/或调用默认值
	CDC *dc= GetDC();
	switch(nChar)
	{
	case VK_UP:
		m_Block->OnUpKey(*dc);
		break;
	case VK_DOWN:
		m_Block->OnDownKey(*dc);
		break;
	case VK_LEFT:
		m_Block->OnLeftKey(*dc);
		break;
	case VK_RIGHT:
		m_Block->OnRightKey(*dc);
		break;
	}
	//dc->ReleaseDC
	CView::OnKeyDown(nChar, nRepCnt, nFlags);
}



其中较为重要的是数组的处理, 以及画刷的利用,在使用画刷是要记得每次窗口变化时都应该重新绘制窗口。 具体方法看本程序代码, 下载链接在文章开头处已经给出(免积分下载)。


说明程序目前还有些小bug,主要是窗口绘制的问题, 例如下一个方块的预览绘制有点问题,这是我以前写的小程序,框架有参考别人的。对于这个小bug可自行修改。


一路向南,   希望共同学习。