我在一篇的博客上面说到扫雷游戏的编写,我因为实习和毕业答辩的一些事情耽搁了这么多天所以今天我就是加班也要这篇博客给大家呈上去,也让我言而有信。好了就说一下这个小游戏的的编写思路吧!一、咱们要编写一下资源,定义一下变量。二、画出界面。三、编写功能模块。四、测试一下就可以了。好了开始上代码:
定义变量和添加资源
int leftnum;//剩下雷数 int leinum; //雷数 int jieshu;//结束 short second;//计时 int secondstart;//开始计时
CBitmap m_Bitmap[12]; //位图数组 CBitmap m_anniu[4];//按扭位图数组 int m_RowCount;//雷区行数 int m_ColCount; //雷区列数 Lei lei[50][50]; //最大雷区 资源就是那个扫雷的几个位图我在这里就不说明了
绘制界面:
1、把状态条工具条去掉(只要是把OnCreate的代码删除就行)。
2、设置窗口的大小:
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
cs.dwExStyle=cs.dwExStyle|WS_EX_TOPMOST; //
cs.style=WS_SYSMENU|WS_OVERLAPPED|WS_MINIMIZEBOX;//;
//设置窗口大小:400*340
cs.cx=400;
cs.cy=340;
return TRUE;
}
3、界面的绘制:
void CMy2_1View::OnDraw(CDC* pDC)
{
CMy2_1Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
CBrush mybrush1;
mybrush1.CreateSolidBrush(RGB(192,192,192));
CRect myrect1(0,0,1200,800);
pDC->FillRect(myrect1,&mybrush1); //背景的绘制
CBrush mybrush;
mybrush.CreateSolidBrush(RGB(0,0,0));
CRect myrect(20,10,70,40);
pDC->FillRect(myrect,&mybrush);
CRect myrect2(325,10,375,40);
pDC->FillRect(myrect2,&mybrush); //显示时间和剩余雷数的黑框
CPen mypen;
CPen*myoldPen;
mypen.CreatePen(PS_SOLID,2,RGB(255,255,255));
myoldPen=pDC->SelectObject(&mypen);
pDC->MoveTo(20,40);
pDC->LineTo(70,40);
pDC->LineTo(70,10);
pDC->MoveTo(325,40);
pDC->LineTo(375,40);
pDC->LineTo(375,10);//画黑框的白线
for(int i=0;i<m_RowCount;i++)
for(int j=0;j<m_ColCount;j++)
{
pDC->MoveTo(10+i*15,50+j*15+14);
pDC->LineTo(10+i*15,50+j*15);
pDC->LineTo(10+i*15+14,50+j*15);
}
pDC->SelectObject(myoldPen);//画雷区边线 左上角是白线,右下角是黑线,以显示立体感:)
CPen mypen2;
CPen*myoldPen2;
mypen2.CreatePen(PS_SOLID,1,RGB(0,0,0));
myoldPen2=pDC->SelectObject(&mypen2);
for(int ii=0;ii<m_RowCount;ii++)
for(int jj=0;jj<m_ColCount;jj++)
{
pDC->MoveTo(10+ii*15,50+jj*15+14);
pDC->LineTo(10+ii*15+14,50+jj*15+14);
pDC->LineTo(10+ii*15+14,50+jj*15);
}
pDC->SelectObject(myoldPen2);
CDC Dc;
if(Dc.CreateCompatibleDC(pDC)==FALSE)
AfxMessageBox("Can't create DC");
Dc.SelectObject(m_anniu[0]);
pDC->BitBlt(180,10,160,160,&Dc,0,0,SRCCOPY);//显示按钮
//判断显示什么位图
//weitu=1已按下的数字区||weitu=2显示旗||weitu=3显示问号
for(int a=0;a<m_RowCount;a++)
for(int b=0;b<m_ColCount;b++)
{
if(lei[a][b].weitu==1)
{
Dc.SelectObject(m_Bitmap[lei[a][b].shumu]);
pDC->BitBlt(a*15+10,b*15+50,160,160,&Dc,0,0,SRCCOPY);
}
if(lei[a][b].weitu==2)
{
Dc.SelectObject(m_Bitmap[9]);
pDC->BitBlt(a*15+10,b*15+50,160,160,&Dc,0,0,SRCCOPY);
}
if(lei[a][b].weitu==3)
{
Dc.SelectObject(m_Bitmap[10]);
pDC->BitBlt(a*15+10,b*15+50,160,160,&Dc,0,0,SRCCOPY);
}
if(jieshu==1&&lei[a][b].shumu==-1)
{
Dc.SelectObject(m_Bitmap[11]);
pDC->BitBlt(a*15+10,b*15+50,160,160,&Dc,0,0,SRCCOPY);
Dc.SelectObject(m_anniu[3]);
pDC->BitBlt(180,10,160,160,&Dc,0,0,SRCCOPY);
}//结束
}
int nOldDC=pDC->SaveDC();//显示黑框里的数字
pDC->SetTextColor(RGB(255,0,0));
pDC->SetBkColor(RGB(0,0,0));
CFont font;
if(0==font.CreatePointFont(160,"Comic Sans MS"))
{
AfxMessageBox("Can't Create Font");
}
pDC->SelectObject(&font);
CString str;
if(leftnum<10)//利用判断显示位数,不够三位前面加0
str.Format("00%d",leftnum);
else
str.Format("0%d",leftnum);
pDC->TextOut(25,10,str);
if(second<10)
str.Format("00%d",second);
else if(second<100)
str.Format("0%d" ,second);
else
str.Format("%d" ,second);
pDC->TextOut(330,10,str);
pDC->RestoreDC(nOldDC);
}
功能模块的编写:
1、初始化一下变量和位图:
CMy2_1View::CMy2_1View()
{
// TODO: add construction code here
for(int ii=0;ii<16;ii++)
m_Bitmap[ii].LoadBitmap(IDB_BITMAP14+ii);
for(int jj=0;jj<4;jj++)
m_anniu[jj].LoadBitmap(IDB_ANNIU1+jj);
second=0;//计时
secondstart=0; //1时开始计时
m_RowCount=25;//行数
m_ColCount=16;//列数
leinum=80;//雷数
leftnum=leinum;//剩余雷数
jieshu=0;//jieshu=1时停止
int aa=0;
for(int i=0;i<m_RowCount;i++)
{
for(int j=0;j<m_ColCount;j++)
{
lei[i][j].shumu=0; //初始化为0
lei[i][j].weitu=0;
}
}
CTime time=GetCurrentTime();//获取当前时间
int s;
s=time.GetSecond();//获取秒数
//设置40个雷
do
{
int k=(rand()*s)%m_RowCount; //以当前秒数为产生随机算法
int l=(rand()*s)%m_ColCount;
if(lei[k][l].shumu!=-1) //为了避免一个位置同时算两个雷只允许当前位置不是雷时赋值为雷
{
lei[k][l].shumu=-1;
aa++;
}
}while(aa!=leinum);
for(int a=0;a<m_RowCount;a++) //给方格赋值,计算雷数
for(int b=0;b<m_ColCount;b++)
if(lei[a][b].shumu==0)
{
for(int c=a-1;c<a+2;c++)
for(int d=b-1;d<b+2;d++)
if(c>=0&&c<m_RowCount&&d>=0&&d<m_ColCount)
if(lei[c][d].shumu==-1)
lei[a][b].shumu++;
}
}
2、鼠标左键按下模块:
如果在按钮上面,则显示按钮按下位图;如果在扫雷区,先把按钮位图改为张口位图,再判断按下的是否是雷,是就结束,重画,以显示所有的雷;否则,重画相应格子以显示数字
void CMy2_1View::OnLButtonDown(UINT nFlags, CPoint point)
{
CDC *pDC=GetDC();//获取指针pdc
CDC Dc;
if(Dc.CreateCompatibleDC(pDC)==FALSE)
AfxMessageBox("Can't create DC");
if(point.x>180&&point.x<210&&point.y>10&&point.y<40)
{
Dc.SelectObject(m_anniu[3]);
pDC->BitBlt(180,10,160,160,&Dc,0,0,SRCCOPY); //显示按下按钮
}
if((point.x>=10)&&(point.x<=385)&&(point.y>=50)&&(point.y<=290))
{
if(jieshu==1)
return;
Dc.SelectObject(m_anniu[1]);
pDC->BitBlt(180,10,160,160,&Dc,0,0,SRCCOPY); //显示张口按钮
secondstart=1; // secondstart为1时计时有效
int a=(point.x-10)/15;
int b=(point.y-50)/15; //鼠标坐标转换为数组坐标
if(lei[a][b].weitu==0||lei[a][b].weitu==3)
{
if(lei[a][b].shumu==-1)
{
jieshu=1;
KillTimer(1); //结束时,释放Timer
Invalidate();//重画,因为这次重画将显示全部的雷,不能用部分重画
}
else
{
lei[a][b].weitu=1;
CRect rect;
rect.left=a*15+10;
rect.right=a*15+25;
rect.top=b*15+50;
rect.bottom=b*15+65;
InvalidateRect(&rect);
}
}
} CView::OnLButtonDown(nFlags, point);
}
3鼠标左键抬起模块:
因为如果左键按下以后位图需要显示按下的状态,如果没有抬起的这个模块,那么位图就要显示按下的状态了
void CMy2_1View::OnLButtonUp(UINT nFlags, CPoint point)
{
CDC *pDC=GetDC();
CDC Dc;
if(Dc.CreateCompatibleDC(pDC)==FALSE)
AfxMessageBox("Can't create DC");
Dc.SelectObject(m_anniu[0]);
pDC->BitBlt(180,10,160,160,&Dc,0,0,SRCCOPY); //显示按钮
if(jieshu==1)
{
Dc.SelectObject(m_anniu[2]);//显示按扭位图
pDC->BitBlt(180,10,160,160,&Dc,0,0,SRCCOPY);
}
if(point.x>180&&point.x<210&&point.y>10&&point.y<40) //如果按下的是按扭,重新开始
OnStart();
CView::OnLButtonUp(nFlags, point);
}
4、鼠标右键的模块:
void CMy2_1View::OnRButtonDown(UINT nFlags, CPoint point)
{
if(jieshu==1) //结束,返回
return;
if((point.x>=10)&&(point.x<=385)&&(point.y>=50)&&(point.y<=290))
{
int a=(point.x-10)/15;
int b=(point.y-50)/15;
if(lei[a][b].weitu==0||lei[a][b].weitu==3)
{
lei[a][b].weitu=2;
leftnum--;
}
else
if(lei[a][b].weitu==2)
{
lei[a][b].weitu=3;
leftnum++;
}
CRect rect2;
rect2.left=20;
rect2.right=70;
rect2.top=10;
rect2.bottom=40;
InvalidateRect(&rect2); //重画剩下雷数
CRect rect;
rect.left=a*15+10;
rect.right=a*15+25;
rect.top=b*15+50;
rect.bottom=b*15+65;
InvalidateRect(&rect); //重画打击格子
}
CView::OnRButtonDown(nFlags, point);
}
4、显示没有雷得区域:
void CMy2_1View::leizero()//扫描,如果是已经被按下且雷数为0,显示它周围的八个格,并重画
{
for(int i=0;i<m_RowCount;i++)
for(int j=0;j<m_ColCount;j++)
if(lei[i][j].shumu==0&&lei[i][j].weitu==1)
{
for(int n=i-1;n<i+2;n++)
for(int m=j-1;m<j+2;m++)
if(n>=0&&n<25&&m>=0&&m<m_ColCount)
if(lei[n][m].shumu!=-1&&lei[n][m].weitu==0)
{
lei[n][m].weitu=1;
CRect rect;
rect.left=n*15+10;
rect.right=n*15+25;
rect.top=m*15+50;
rect.bottom=m*15+65;
InvalidateRect(&rect);
}
}
}
5、计时器模块:
int CMy2_1View::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: Add your specialized creation code here
//20次为一秒
SetTimer(1,50,NULL);
return 0;
}
void CMy2_1View::OnTimer(UINT nIDEvent)
{
if(jieshu==1)//结束,返回
return;
leizero(); //显示个数为0的方格
if(secondstart>0)//计时
secondstart++;
if(secondstart==20)//二十次为一秒
{
secondstart=1;
second++;
CRect rect3;
rect3.left=325;
rect3.right=375;
rect3.top=10;
rect3.bottom=40;
InvalidateRect(&rect3); //重画时间
}
CView::OnTimer(nIDEvent);
}
好了以上就是五子棋的精华所在了,如果想要更完美一些就可以在菜单上面在添加重新开始模块(也就是重新初始化一次)。