VC++打地鼠游戏
- 格式:doc
- 大小:380.50 KB
- 文档页数:16
第五章老鼠和滚球1.1.实现思想老鼠和滚球游戏,是我根据自己的意愿,是为了我将要说明的下面有关内容而设置的。
由于没有经过具体实践,我并不能保证其趣味性和吸引力,我们学习的是它实现过程中的一些思想。
希望对读者有所帮助。
其实,这种游戏,在街头电子游戏中是常见的。
但由于电脑的渐渐普及,大规模游戏的迅速出现,已经不适合玩者的需求了。
但是,我们可以以小见大,在学习小游戏的基础上,慢慢培养设计大游戏的一些方法和技巧。
关于游戏的角色:老鼠,是游戏的主角,它有三条生命,它为了生存,必须能够逃脱灾难性的局面(被滚球撞到),它在经过所谓的适者生存的淘汰之后,学会了使用子弹;而且是一种能够消灭滚球的子弹,以达到防身的目的。
每打中一个球得一分,每被撞一下失去一条生命。
滚球,一共有50个,但为了维持生态平衡,最多只能出来六个。
滚球,是为了消灭老鼠而存在的,它将会在现代科技的伪随机函数中不定向地出现。
红心,生命的象征,只要你能碰到它,你就幸运了,因为由此你会得到一条生命。
当然,生存需要竞争,需要你自己去创造;只要你在消灭了很多滚球之后,你才有可能取得。
正因为这个原因,我把它安排在滚球出现的地方。
关于游戏的实现:游戏,经常都是全屏的,但是由于我们的目的不仅仅在于游戏本身,我们的宗旨是利用游戏的趣味性和吸引力,来增强读者学习程序语言的信心。
所以,在前面我们都没有用到全屏显示,我们不需要。
另外说明:本游戏的全屏只适应于800*600的分辨率。
全屏,是这个游戏的一点要学习的。
多位图的移动,是本游戏要学习的第二个内容,上面的最多只有两个位图可以移动,这是由于游戏本身决定的。
当然,这个游戏的多位图移动,也是游戏本身决定的,但却是我之所以选择它为第五章的原因。
当然,我们没有那么多的手去操作键盘,去移动位图。
我们必须设置我们的程序,让程序自己去执行,去移动,去显示计算机的优越性。
这个游戏,比起上面来,它是一个更加复杂的社会,它不再只是玩者一个人充当角色。
所以,我们新建了各自的类。
新建工程5_1,为单文档默认设置。
2.2.制作位图既然游戏是复杂的,它就需要很多位图,但由于我们在前面已经用了很多位图,我们这里就不多说了。
只是说明一下位图的数量和大小。
背景位图:800*600 1张IDB_BITMAP1老鼠位图:50*50 4张IDB_BITMAP2(两只老鼠两个方向)IDB_BITMAP3IDB_BITMAP7IDB_BITMAP8滚球位图:50*50 1张IDB_BITMAP4红心位图:50*50 1张IDB_BITMAP11子弹位图:50*50 4张IDB_BITMAP5(两种颜色两个方向)IDB_BITMAP6IDB_BITMAP9IDB_BITMAP103.3.变量和函数老鼠:它有位置,分数,方向,生命力,子弹和它自己。
其中它自己的图像及它射出来的子弹都有前后方向。
我们必须为它定义一个类,以让两个老鼠共用。
新建类:CMouse添加变量如下:CPoint point;//位置CBitmap bitmapa;//向后图像CBitmap bitmapb;//向前图像CBitmap shota;//向后子弹CBitmap shotb;//向前子弹int score;//分数short direction;//方向short lifes;//生命滚球:它也有位置,也有它自己的图像。
由于一共有五十个球,最多会显示六个球,我们也定义它为一共类。
新建类:CBall添加变量如下:CPoint point;CBitmap bitmap;//由于对称,我们只要一个位图游戏:由于它的复杂性,程序,由于它的复杂性,为了不使它们更加复杂,我们也为游戏的实现本身建立一个类。
新建类:CGame添加变量如下:CBall ball[6];//六个滚球short ballnum;//滚球数:50CMouse m1,m2;//两只老鼠int yy[16][12];//屏幕数组CBitmap shot;//子弹位图bool heart1,heart2;//两个红心是否显示CBitmap heart;//红心位图既然是游戏本身,它必定要实现很多功能,我们添加如下函数:void GetHeart();//老鼠得到红心void KillBall();//老鼠打中滚球void KillMouse();//滚球杀死老鼠void Draw(CDC*pDC);//画界面void DrawScore(CDC*pDC);//画分数void BallMove();//使球滚动最后,到了主程序,为了实现全屏,我们在CMainFrame 中添加如下变量和函数:CRect m_FullScreenRect;//全屏显示时的窗口位置void OnFullScreen();//全屏显示在CMy5_1View中添加如下变量和函数:CGame game;//游戏对象CBitmap cloud;//背景云图OnTimer(UINT nIDEvent)OnCreate(LPCREATESTRUCT lpCreateStruct)OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)4.4.具体实现全屏显示:首先,我们必须使单文档以全屏形式出现,并设置为不能改动大小,没有工具栏和状态栏,没有菜单。
添加OnFullScreen()函数如下:void CMainFrame::OnFullScreen(){// TODO: Add your command handler code hereCRect WindowRect;GetWindowRect(&WindowRect);CRect ClientRect;RepositionBars(0,0xffff,AFX_IDW_PANE_FIRST,reposQuery,&ClientRect);ClientToScreen(&ClientRect);//获取屏幕的分辨率int nFullWidth=GetSystemMetrics(SM_CXSCREEN);int nFullHeight=GetSystemMetrics(SM_CYSCREEN);m_FullScreenRect.left=WindowRect.left-ClientRect.left;m_FullScreenRect.top=WindowRect.top-ClientRect.top;m_FullScreenRect.right=WindowRect.right-ClientRect.right+nFullWidth;m_FullScreenRect.bottom=WindowRect.bottom-ClientRect.bottom+nFullHeight;//进入全屏显示状态WINDOWPLACEMENT wndpl;wndpl.rcNormalPosition=m_FullScreenRect;SetWindowPlacement(&wndpl);}再改变函数OnCreate(LPCREATESTRUCT lpCreateStruct)和PreCreateWindow(CREATESTRUCT& cs)如下:int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct){if (CFrameWnd::OnCreate(lpCreateStruct) == -1)return -1;OnFullScreen();//全屏显示return 0;}BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs){if( !CFrameWnd::PreCreateWindow(cs) )return FALSE;// TODO: Modify the Window class or styles here by modifying// the CREATESTRUCT cscs.style=WS_SYSMENU;cs.dwExStyle=WS_EX_TOPMOST; //窗口置于最前return TRUE;}这样,全屏就显示出来了。
构造函数:接着,就要把位图显示出来,在CMy5_1View()函数添加语句如下:CMy5_1View::CMy5_1View(){// TODO: add construction code herecloud.LoadBitmap(IDB_BITMAP1);}显示背景:在OnDraw(CDC* pDC)函数里面添加语句如下:void CMy5_1View::OnDraw(CDC* pDC){CMy5_1Doc* pDoc = GetDocument();ASSERT_V ALID(pDoc);// TODO: add draw code for native data hereCDC Dc;if(Dc.CreateCompatibleDC(pDC)==FALSE)AfxMessageBox("Can't create DC");//在不同位置显示位图Dc.SelectObject(cloud);pDC->StretchBlt(0,0,800,600,&Dc,0,0,800,600,SRCCOPY);game.Draw(pDC);}由于真正的画图是在类Game里面实现的,我们添加game.Draw(pDC)函数。
但是,为了防止某些变量的赋值和初始化问题,我们先添加CGame()函数的语句如下:构造函数:CGame::CGame(){int i,j;heart.LoadBitmap(IDB_BITMAP11);m1.bitmapb.LoadBitmap(IDB_BITMAP2);m2.bitmapb.LoadBitmap(IDB_BITMAP3);m1.bitmapa.LoadBitmap(IDB_BITMAP7);m2.bitmapa.LoadBitmap(IDB_BITMAP8);m1.shotb.LoadBitmap(IDB_BITMAP5);m2.shotb.LoadBitmap(IDB_BITMAP9);m1.shota.LoadBitmap(IDB_BITMAP6);m2.shota.LoadBitmap(IDB_BITMAP10);//生命数量为3m1.lifes=3;m2.lifes=3;//红心显示heart1=true;heart2=true;//滚球数量50ballnum=50;for(i=0;i<6;i++)ball[i].bitmap.LoadBitmap(IDB_BITMAP4);//滚球开始出现的位置for(i=0;i<3;i++){ball[i].point.x=4+i;ball[i].point.y=0;ball[i+3].point.x=9+i;ball[i+3].point.y=0;}//老鼠开始出现的位置m1.point.x=0;m1.point.y=10;m2.point.x=15;m2.point.y=10;//老鼠开始的方向m1.direction=1;m2.direction=-1;//清理背景数组,或1或0for(i=0;i<16;i++)for(j=0;j<11;j++)yy[i][j]=0;yy[4][1]=1;yy[5][1]=1;yy[6][1]=1;yy[9][1]=1;yy[10][1]=1;yy[11][1]=1;for(i=0;i<16;i++)yy[i][3]=1;yy[5][3]=0;yy[10][3]=0;for(i=5;i<11;i++)yy[i][5]=1;for(i=4;i<12;i++)yy[i][7]=1;for(i=0;i<5;i++)yy[i][9]=1;for(i=11;i<16;i++)yy[i][9]=1;for(i=0;i<16;i++)yy[i][11]=1;}显示前景:再添加如下函数:void CGame::Draw(CDC *pDC){int i,j;CDC Dc;if(Dc.CreateCompatibleDC(pDC)==FALSE)AfxMessageBox("Can't create DC");//在不同位置显示位图//显示老鼠位图if(m2.lifes>0){Dc.SelectObject(m2.direction==1?m2.bitmapb:m2.bitmapa);pDC->BitBlt(m2.point.x*50,m2.point.y*50,50,50,&Dc,0,0,SRCCOPY);}if(m1.lifes>0){Dc.SelectObject(m1.direction==1?m1.bitmapb:m1.bitmapa);pDC->BitBlt(m1.point.x*50,m1.point.y*50,50,50,&Dc,0,0,SRCCOPY);}//画滚球//大于六个的画六个j=ballnum-m1.score;j=j-m2.score;if(j>6)j=6;for(i=0;i<j;i++){Dc.SelectObject(ball[i].bitmap);pDC->BitBlt(ball[i].point.x*50,ball[i].point.y*50,50,50,&Dc,0,0,SRCCOPY);}//检查界面数组//2表示m2的子弹,3表示m1的子弹for(i=0;i<16;i++)for(j=0;j<12;j++){if(yy[i][j]==2){Dc.SelectObject(m2.direction==1?m2.shotb:m2.shota);pDC->BitBlt(i*50,j*50,50,50,&Dc,0,0,SRCCOPY);}if(yy[i][j]==3){Dc.SelectObject(m1.direction==1?m1.shotb:m1.shota);pDC->BitBlt(i*50,j*50,50,50,&Dc,0,0,SRCCOPY);}}//画老鼠的生命数量for(i=0;i<m1.lifes;i++){Dc.SelectObject(m1.bitmapb);pDC->StretchBlt(i*40+10,0,30,30,&Dc,0,0,50,50,SRCCOPY);}for(i=0;i<m2.lifes;i++){Dc.SelectObject(m2.bitmapa);pDC->StretchBlt(760-i*40,0,30,30,&Dc,0,0,50,50,SRCCOPY);}//显示分数,函数在下面!DrawScore(pDC);//显示红心Dc.SelectObject(heart);if(heart1)pDC->BitBlt(250,0,50,50,&Dc,0,0,SRCCOPY);if(heart2)pDC->BitBlt(500,0,50,50,&Dc,0,0,SRCCOPY);}显示分数信息:由于这个函数在前面已经出现,只是添加如下:void CGame::DrawScore(CDC *pDC){int nOldDC=pDC->SaveDC();//设置字体CFont font;if(0==font.CreatePointFont(250,"Comic Sans MS")){AfxMessageBox("Can't Create Font");}pDC->SelectObject(&font);//设置字体颜色及其背景颜色CString str;pDC->SetTextColor(RGB(0,10,244));pDC->SetBkColor(RGB(0,255,0));//输出数字str.Format("%d",m1.score);if(m2.score>=0)pDC->TextOut(40,28,str);str.Format("%d",m2.score);if(m2.score>=0)pDC->TextOut(740,28,str);pDC->RestoreDC(nOldDC);}滚球实现:老鼠的移动是由我们操作的,我们后面再实现,而滚球是程序驱动的,它们是怎样实现的呢?添加如下函数:void CGame::BallMove(){int i,j,k;j=ballnum-m1.score;j=j-m2.score;if(j>6)j=6;for( i=0;i<j;i++){//其中三个if((i==1)||(i==3)||(i==5)){//向右移动ball[i].point.x++;//到了边界,在左边出现if(ball[i].point.x>15)ball[i].point.x=0;//下面空,下掉if(yy[ball[i].point.x][ball[i].point.y+1]!=1)for(k=ball[i].point.y;k<12;k++)if(yy[ball[i].point.x][k]==1){ball[i].point.y=k-1;break;}//到了最底面if((ball[i].point.x==15)&&(ball[i].point.y==10)){//在上面出现if(i==1){ball[i].point.x=10;ball[i].point.y=-1;}else{ball[i].point.x=5;ball[i].point.y=-1;}}}//同上else if((i==2)||(i==4)||(i==0)){ball[i].point.x--;if(ball[i].point.x<0)ball[i].point.x=15;if(yy[ball[i].point.x][ball[i].point.y+1]!=1)for(k=ball[i].point.y;k<12;k++)if(yy[ball[i].point.x][k]==1){ball[i].point.y=k-1;break;}if((ball[i].point.x==0)&&(ball[i].point.y==10)){if(i==2){ball[i].point.x=5;ball[i].point.y=0;}else{ball[i].point.x=10;ball[i].point.y=0;}}}}}计时器函数:那么,现在应该添加计数器函数了。