📄 vc++saoleigame.txt
字号:
1. 游戏实现
扫雷,是附带在Window里面的游戏,是个简单的游戏。因此我们就从扫雷开始我们的游戏旅程。很多人都玩过这个游戏,只是不知道怎么用程序实现。不过还有人不知道怎么玩,下面就先说说游戏的规则:
● 开始:按左键开始游戏,按按钮或菜单重新开始。
● 左键:按下时,是雷则结束,非雷则显示数字。
● 数字:代表此数字周围一圈八格中雷的个数。
● 右键:奇次按下表示雷,偶数按下表示对上次的否定。
● 结束:左键按到雷结束,找出全部雷结束。
接下来就该介绍游戏的编程过程了。不过要先交代一下一些内容。
● 添加位图。
● 添加全局变量。
● 画初始界面。
● 添加函数。
为什么要按这种次序呢?因为我们在画初始界面时,可能要用到位图或变量,而变量的定义又可能要对位图进行定义。这样的步骤的好处还有:在做一步之后都可以运行,有错就改,无错就做下一步。
上图是扫雷的一个画面。
下面就一步一步地演示,以编程的思路进行,当然,由于编程过程中有一些函数中的代码是分成两三次写的,我们就不重复,全部代码在第一次讲到时列出,而后面讲到时就只是提一下。
新建单文档工程2_1。
2. 资源编辑
添加位图:
前十二幅是在雷区的,后四幅是按钮。为了便于加载,必须各自保证其连续性。另外,为什么不添加一个按钮而用位图呢?是因为即使我们添加了按钮也要添加四幅位图!
位图的ID号:
按扭位图: 30*30 IDB_ANNIU1、IDB_ANNIU 2、IDB_ANNIU3、 IDB_ANNIU4
雷区位图: 14*14 ID号按下图依次为:IDB_BITMAP14。。。。。。IDB_BITMAP25
位图:下图(图2-1)。
图2-1
3. 变量函数
定义新类:
对于雷,我们是单独定义一个类,这样有利于程序的操作。
class Lei
{
public:
//显示哪一个位图
int weitu;
//这个位置相应的值
int shumu;
};
并有如下规定(图2-2):
图2-2
视图类变量:
接着是在View类添加变量和函数:
//剩下雷数
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];
//这个位置周围雷数为0
void leizero();
//计时器函数
afx_msg void OnTimer(UINT nIDEvent);
//鼠标按下左键
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
//鼠标按下右键
afx_msg void OnRButtonDown(UINT nFlags, CPoint point);
//初始化函数
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
//鼠标左键松开
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
4. 具体实现
删去状态栏和工具栏:
开始执行程序,就能见到一个有状态栏和工具栏的大的单文档,与上图不同,所以我们第一步就是整理框架:
打开下面函数,把里面的一些语句去掉。如下所示:
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
/* if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
{
TRACE0("Failed to create toolbar\n");
return -1; // fail to create
}
if (!m_wndStatusBar.Create(this) ||
!m_wndStatusBar.SetIndicators(indicators,
sizeof(indicators)/sizeof(UINT)))
{
TRACE0("Failed to create status bar\n");
return -1; // fail to create
}
// TODO: Delete these three lines if you don't want the toolbar to
// be dockable
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);
*/
return 0;
}
设置窗口大小:
运行附加的代码,还能看到扫雷游戏的框架是不能调大小的,而且总是显示在最前面,这又是怎么实现的呢?
在下面函数里添加语句,你能说出前三句是什么意思吗?注释已经被我去掉了,如果不知道,不如按一下F1。
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;
}
构造函数:
由于构造函数是程序运行时就执行的,所以,除了对变量赋值之外,我们还可以把游戏的核心结构即内部数组赋值:先是把全部格子的位图和雷数赋值为0,然后调用随机函数按指定雷数赋值为-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;
//1时开始计时
secondstart=0;
//行数
m_RowCount=25;
//列数
m_ColCount=16;
//雷数
leinum=80;
//剩余雷数
leftnum=leinum;
//jieshu=1时停止
jieshu=0;
int aa=0;
//初始化为0
for(int i=0;i<m_RowCount;i++)
{
for(int j=0;j<m_ColCount;j++)
{
lei[i][j].shumu=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++;
}
}
界面函数:
现在,可以开始画界面了。如下函数:
很明显,前面部分是用画的方法画出整个界面,但是,后面for循环显示的位图并不是现在画界面的内容,为什么要写呢?
这是为了用户框重画的需要,当我们的游戏玩了一半后最小化,或是把部分窗口移出屏幕,或是执行了新的应用程序覆盖了原来的程序时,必须重画。我们调用重画函数,它都要重新执行OnDraw(CDC* pDC)函数,那么,此时它就必须把已经显示出来的位图也显示出来。而开始时雷区位图是不可见的,并不影响界面的初始化。
void CMy2_1View::OnDraw(CDC* pDC)
{
CMy2_1Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
//画背景
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);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -