双人版俄罗斯方块游戏实验报告双人版俄罗斯方块游戏实验报告
西安科技大学
《Visual C++程序设计》
实验报告
题 目 双人版俄罗斯方块游戏
院、系(部) 计算机科学与技术学院 专业及班级 软件工程1101班 姓 名 张XX 日 期 2012/12/14
一( 功能需求:
1. 能进行双人模式:
这是程序的主要功能。
2. 能进行下一砖块的预测:
这也是俄罗斯方块游戏的基本功能,可以在这个基础上进行扩展其他功能,如不同
于经典模式的砖块显示等来增加难度。
二( 总体设计计:
1.矩形框类的设计:
设计CBin类描述Tetri...
双人版俄罗斯方块游戏#实验
#
西安科技大学
《Visual C++程序设计》
实验报告
题 目 双人版俄罗斯方块游戏
院、系(部) 计算机科学与技术学院 专业及班级 软件
1101班 姓 名 张XX 日 期 2012/12/14
一( 功能需求:
1. 能进行双人模式:
这是程序的主要功能。
2. 能进行下一砖块的预测:
这也是俄罗斯方块游戏的基本功能,可以在这个基础上进行扩展其他功能,如不同
于经典模式的砖块显示等来增加难度。
二( 总体设计计:
1.矩形框类的设计:
设计CBin类描述Tetris游戏的矩形框,用image的二维数组来描述这
。 个矩形框。设置不同的值显示不同颜色的矩形,若没有砖块则为02.砖块的设计:
设计CBrick抽象类来设计砖块,应用多态性的原理,其他不同类型的砖
块类继承CBrick,来设计不同的砖块。
3.砖块在面板中的显示设计:
在视图类中设计并显示砖块。
三( 详细设计:
1.矩形框类的设计:
设计CBin类描述Tetris游戏的矩形框,用image的二维数组来描述这个矩形框。设置不同的值显示不同颜色的矩形,若没有砖块则为0。 CBin类的五个成员函数:
(1) CBin(unsigned int unsigned int h)
构造函数,用来初始化数据成员,width和height,并为image
分配空间并初始化。
(2) ~CBin()
析构函数,删除在构造函数中为image分配的空间。
(3) Void getImage(unsigned char*destImage)
将image的数据拷贝到destImage,你可以假设destimage指向的
空间足够容纳image的空间。
(4) Void setImage(unsigned char**srcImage)
把srcImage中的数据拷贝到image,你可以假设srcImage是一个
合法的指针。
(5) Unsigned int removeFullLines()
检查image,如果任何一行完全填满,则删除这一行,并让上面一
行的数据下移,返回删除的总行数。
设计代码如下:
class CBin {
private:
unsigned char** image;
unsigned int width;
unsigned int height;
public:
CBin(unsigned int w, unsigned int h);
~CBin();
unsigned int getWidth() { return width; };
unsigned int getHeight() { return height; };
void getImage(unsigned char** destImage);
void setImage(unsigned char** srcImage);
unsigned int removeFullLines(); };
CBin::CBin(unsigned int w, unsigned int h) {
width=w;
height=h;
image = new unsigned char* [height];
for (unsigned int i = 0; i
0; m--)
{
for (j=0; j>,通过设置映射到游戏矩形的二维数组binImage,
设置砖块的颜色,这里假设binimage是一个合法的大侠合适的二
维数组。
(7) void operator>>(unsigned char *binimage)
(8) putAtTop(unsigned int newOrient,unsigned int newPosX)
通过设置砖块特定点的Y坐标(posY)是的砖块位于矩形的最上方,
砖块的X坐标和砖块的状态由newPosX和newOrient确定。注意
posY的值依赖于砖块的状态
(9) putAtMid(unsigned int newOrient,unsigned int newPosX)
与putAtTop一致,只是将坐标设置在面板中间。
下面是一个具体的砖块设计代码:
class CCBrick : public CBrick {
public:
int shiftLeft(CBin* bin);
int shiftRight(CBin* bin);
int shiftDown(CBin* bin);
int rotateClockwise(CBin* bin);
int checkCollision(CBin* bin);
void operator>>(unsigned char** binImage);
void putAtTop(int newOrient, int newPosX);
void putAtMid(int newOrient, int newPosX);
};
/////////////////////////
int CCBrick::shiftLeft(CBin* bin)
{
int posX;
posX=getPosX();
setPosX(posX-1);
if (checkCollision(bin)== 0) {
setPosX(posX);
return 0;
}
return 1;
}
int CCBrick::shiftDown(CBin* bin)
{
int posY;
posY=getPosY();
setPosY(posY+1);
if (checkCollision(bin)== 0) {
setPosY(posY);
return 0;
}
return 1;
}
int CCBrick::shiftRight(CBin* bin)
{
int posX;
posX=getPosX();
setPosX(posX+1);
if (checkCollision(bin)==0) {
setPosX(posX);
return 0;
}
return 1;
}
int CCBrick::rotateClockwise(CBin* bin)
{
int orientation,oldOrientation;
orientation=getOrientation();
oldOrientation=orientation;
if (orientation==3)
orientation=0;
else
orientation=orientation+1;
setOrientation(orientation);
if (checkCollision(bin)== 0) {
setOrientation(oldOrientation);
return 0;
}
return 1;
}
int CCBrick::checkCollision(CBin* bin) {
int width;
int height;
unsigned char** image;
int orientation;
int posX;
int posY;
width=bin->getWidth();
height=bin->getHeight();
image = new unsigned char* [height];
for (int i = 0; igetImage(image);
orientation=getOrientation();
posX=getPosX();
posY=getPosY();
if (orientation==0)
{
if((posX<0)||
((posX+1)>width-1)||
(posY<1)||
(posY+1>height-1))
return 0;
if ( (image[posY-1][posX]!=0)||
(image[posY-1][posX+1]!=0)||
(image[posY][posX]!=0)||
(image[posY+1][posX]!=0)||
(image[posY+1][posX+1]!=0))
return 0;
}
if (orientation==1)
{
if( (posX<1)||
((posX+1)>width-1)||
(posY<0)||
((posY+1)>height-1))
return 0;
if ( (image[posY+1][posX+1]!=0)||
(image[posY][posX+1]!=0)||
(image[posY][posX]!=0)||
(image[posY][posX-1]!=0)||
(image[posY+1][posX-1]!=0))
return 0;
}
if (orientation==2)
{
if((posX<1)||
(posX>width-1)||
(posY<1)||
((posY+1)>height-1))
return 0;
if ( (image[posY-1][posX-1]!=0)||
(image[posY-1][posX]!=0)||
(image[posY][posX]!=0)||
(image[posY+1][posX]!=0)||
(image[posY+1][posX-1]!=0))
return 0;
}
if (orientation==3)
{
if( (posX<1)||
(posX+1>width-1)||
(posY<1)||
((posY)>height-1))
return 0;
if ( (image[posY-1][posX+1]!=0)||
(image[posY][posX+1]!=0)||
(image[posY][posX]!=0)||
(image[posY][posX-1]!=0)||
(image[posY-1][posX-1]!=0))
return 0;
}
return 1;
}
void CCBrick::operator>>(unsigned char** binImage)
{
int orientation;
int posX;
int posY;
unsigned char colour;
posX=getPosX();
posY=getPosY();
orientation=getOrientation();
colour=getColour();
if (orientation==0)
{
binImage[posY-1][posX+1]=colour;
binImage[posY-1][posX]=colour;
binImage[posY][posX]=colour;
binImage[posY+1][posX]=colour;
binImage[posY+1][posX+1]=colour;
}
if (orientation==1)
{
binImage[posY+1][posX+1]=colour;
binImage[posY][posX+1]=colour;
binImage[posY][posX]=colour;
binImage[posY][posX-1]=colour;
binImage[posY+1][posX-1]=colour;
}
if (orientation==2)
{
binImage[posY-1][posX-1]=colour;
binImage[posY][posX]=colour;
binImage[posY-1][posX]=colour;
binImage[posY+1][posX]=colour;
binImage[posY+1][posX-1]=colour;
}
if (orientation==3)
{
binImage[posY-1][posX+1]=colour;
binImage[posY][posX+1]=colour;
binImage[posY][posX]=colour;
binImage[posY][posX-1]=colour;
binImage[posY-1][posX-1]=colour;
}
}
void CCBrick::putAtTop(int newOrient, int newPosX)
{
setPosX(newPosX);
setOrientation(newOrient);
switch(newOrient)
{
case 0: setPosY(1); break;
case 1: setPosY(0); break;
case 2: setPosY(1); break;
case 3: setPosY(1); break;
}
}
void CCBrick::putAtMid(int newOrient, int newPosX)
{
setPosX(newPosX-3);
setOrientation(newOrient);
switch(newOrient)
{
case 0: setPosY(9); break;
case 1: setPosY(8); break;
case 2: setPosY(9); break;
case 3: setPosY(9); break;
}
}
3.砖块在面板中的显示设计:
在视图类中设计并显示砖块。
(1).定义相关的变量并在构造函数中初始化。
(2).添加DrawImage(CBin*bin,unsigned char**image,CDC*pDC)
函数,用来绘制游戏砖块。
这其中要绘制四个面板,传递四个参数。两个主面板,两个与侧面板。
部分代码如下:
void CNewTerisView::DrawImage(CBin *bin,CBin *bin1,CBin
*bin2,CBin *bin3, unsigned char **image, unsigned char
**image1, unsigned char **image2, unsigned char **image3,CDC
*pDC)
CRect rect;
//创建背景位图画刷
CBitmap bitmap;
bitmap.LoadBitmap(IDB_BITMAP24);
CBrush brush;
brush.CreatePatternBrush(&bitmap);
GetClientRect(&rect);
pDC->FillRect(rect,&brush);
//右边玩家分数的输出
CRect re;
pDC->FillSolidRect(re,RGB(210,255,255));
char buf[100];
sprintf(buf," %d ",numLines*10);
pDC->TextOut(330,90,buf);
//左边玩家分数的输出
CRect re1;
pDC->FillSolidRect(re1,RGB(230,255,100));
char buf1[100];
sprintf(buf1," %d ",numLines1*10);
pDC->TextOut(440,90,buf1);
CRect rc,rc1,rc2,rc3;
//将载入的位图资源放在数组中
int
Bit[8]={IDB_BITMAP11,IDB_BITMAP12,IDB_BITMAP13,IDB_BITMAP14
,IDB_BITMAP15,IDB_BITMAP16,IDB_BITMAP17,IDB_BITMAP18};
int b,b1,b2;
for(i=0;iFillRect(rc1,&brush1);
}
}
}
for(i=0;iFillRect(rc,&brush1);
}
}
}
(3).在菜单中添加“开始”、“难度”、“暂停”、“游戏模式”等菜单,
A(为“开始”菜单添加消息响应函数。
初始化面板,并设置定时器。
代码如下:
void CNewTerisView::OnGameStart()
{
// TODO: Add your command handler code here
gameOver=0;
brickInFlight=0;
numLines=0;
//------------
gameOver1=0;
brickInFlight1=0;
numLines1=0;
for(unsigned int i=0;i<20;i++)
{
for(unsigned int j=0;j<10;j++)
{
outputImage[i][j]=0;
outputImage1[i][j]=0;
outputImage2[i][j]=0;
outputImage3[i][j]=0;
}
}
bin->setImage(outputImage);
bin1->setImage(outputImage1);
bin2->setImage(outputImage2);
bin3->setImage(outputImage3);
/////////////加背景音乐
res=FindResource(::AfxGetApp()->m_hInstance,MAKEINTRESOURCE
(IDR_WAVE1),"WAVE");
hSound1=LoadResource(::AfxGetApp()->m_hInstance,res);
lpSound1=(LPSTR)LockResource(hSound1);
sndPlaySound(lpSound1,SND_LOOP|SND_ASYNC|SND_MEMORY);
//
SetTimer(0,difficulty,NULL);
}
B.“难度”菜单中有容易、中等与高级三个等级。通过设置砖块下落的速
度来设置难度。
C.“暂停”菜单中设置标志变量,是程序执行时,不执行shiftDown()函
数即可。
void CNewTerisView::OnPause() //暂停
{
// TODO: Add your command handler code here
if(!p) //原先没有暂停则暂停
{
Pause1=TRUE; //设置暂停为真
Pause2=TRUE;
p=TRUE;
}
else //若原先暂停,按下后继续游戏
{
Pause1=FALSE;
Pause2=FALSE;
p=FALSE;
}
}
D(“游戏模式”菜单可以设置游戏为“经典模式”或“奇幻模式”。 用于设定两大不同类的砖块。
(4).为视图类添加WM_TIMER的消息响应函数。(此相当于C++中所执行
的主函数中的代码)
A在此函数中,随机产生不同的砖块,并显示出来,还要判断是否冲突
或游戏是否结束,若游戏没结束也不冲突则砖块下移一格,之后还要
判断是否应消行等。
B.预测功能的实现,是将预测面板上一次随机产生的砖块类型值赋给本
次的主程序面板。
C(双人模式的实现很简单,只是重新绘制了一个矩形框(CBin),并绘
制一个面板,将其显示在不同的区域。预测与此类似,只不过预测没
有判断冲突等,只是显示即可。
具体代码如下:
if(!brickInFlight&&!gameOver) //判断左边游戏是否结束及砖块
是否在飞
{
if(!RandomFlag) //若是第一次产生主界面砖块类型,则执行下面
语句(第一次产生的砖块不是预测的)下面语句只执行一次
{
brickType=((unsigned int)rand()%NUM_BRICK_TYPES)+1;
initOrientation=(unsigned int)(rand()%4);
RandomFlag=TRUE;
}
else //第二次以后,主界面的砖块都是上一次预测砖块的类型
{
brickType=brickType1;
initOrientation=initOrientation1;
}
CTime time=CTime::GetCurrentTime(); //预测砖块类型的产生
int q=int(time.GetSecond());
brickType1=(q%NUM_BRICK_TYPES)+1;
initOrientation1=(unsigned int)(q%4);
if(!modal) //若不是经典模式,则为奇幻模式
{
if(brickType==1) //左边主界面砖块的动态产生
activeBrick=new CtBrick;
else if(brickType==2)
activeBrick=new CsBrick;
else if(brickType==3)
activeBrick=new CCBrick;
else if(brickType==4)
activeBrick=new CPointBrick;
else if(brickType==5)
activeBrick=new CiBrick;
else if(brickType==6)
activeBrick=new C10Brick;
else if(brickType==7)
activeBrick=new C7Brick;
/////////000000
if(brickType1==1)
activeBrick1=new CtBrick;//左边预测界面砖块的动态产生
else if(brickType1==2)
activeBrick1=new CsBrick;
else if(brickType1==3)
activeBrick1=new CCBrick;
else if(brickType1==4)
activeBrick1=new CPointBrick;
else if(brickType1==5)
activeBrick1=new CiBrick;
else if(brickType1==6)
activeBrick1=new C10Brick;
else if(brickType1==7)
activeBrick1=new C7Brick;
}
else //若不是奇幻模式,则为经典模式
{
if(brickType==1)
activeBrick=new CTBrick;
else if(brickType==2)
activeBrick=new CABrick;
else if(brickType==3)
activeBrick=new CSBrick;
else if(brickType==4)
activeBrick=new CLBrick;
else if(brickType==5)
activeBrick=new COBrick;
else if(brickType==6)
activeBrick=new CIBrick;
else if(brickType==7)
activeBrick=new CJBrick;
/////////////////
if(brickType1==1)
activeBrick1=new CTBrick;
else if(brickType1==2)
activeBrick1=new CABrick;
else if(brickType1==3)
activeBrick1=new CLBrick;
else if(brickType1==4)
activeBrick1=new CSBrick;
else if(brickType1==5)
activeBrick1=new COBrick;
else if(brickType1==6)
activeBrick1=new CIBrick;
else if(brickType1==7)
activeBrick1=new CJBrick;
}
activeBrick->setColour((unsigned char)brickType); //左边主
界面设置颜色
activeBrick->putAtTop(initOrientation,binWidth/2);//将产生
的砖块置顶
//-----
activeBrick1->setColour((unsigned char)brickType1); //左边
预测砖块设置颜色
activeBrick1->putAtMid(initOrientation1,binWidth1/2);//将
预测产生的砖块放置在面板中间
///******************************************
notCollide=activeBrick->checkCollision(bin); //判断是否冲突
if(notCollide) //判断是否冲突
{
brickInFlight=1;
bin->getImage(outputImage);
activeBrick->operator>>(outputImage);
bin1->getImage(outputImage1);
activeBrick1->operator>>(outputImage1);
Invalidate(FALSE);
}
else //冲突则游戏设置游戏结束变量,删除new的东西
{
gameOver=1;
delete activeBrick;
delete activeBrick1;
brickInFlight=0;
}
}
////////////////////////////////////////////////////
if(brickInFlight&&!gameOver)
{
if(!Pause1)
notCollide=activeBrick->shiftDown(bin); //砖块下移一格
if(notCollide){
bin->getImage(outputImage); //不冲突获得画面
activeBrick->operator>>(outputImage); //显示画面
}
else
{
brickInFlight=0;
bin->getImage(outputImage);
activeBrick->operator>>(outputImage);
bin->setImage(outputImage);
Invalidate(FALSE);
numLines=numLines+bin->removeFullLines(); //消行分数增
加
bin->getImage(outputImage);
}
Invalidate(FALSE);
}
//////////////////////////////
if(gameOver){ //左边游戏是否结束
KillTimer(0);
res1=FindResource(::AfxGetApp()->m_hInstance,MAKEINTRESOUR
CE(IDR_WAVE2),"WAVE");
hSound2=LoadResource(::AfxGetApp()->m_hInstance,res1);
lpSound2=(LPSTR)LockResource(hSound2);
sndPlaySound(lpSound2,SND_ASYNC|SND_MEMORY);
if(MessageBox("左边的兄弟,得加油啊~还玩吗?","提示
",MB_YESNO)==IDYES)
OnGameStart();
else
exit(0);
}
(6) 在OnDraw()函数中调用DrawImage()函数,即可显示面板。
(7) 当然还得添加WM_KEYDOWON的消息响应函数,以响应用户按键。
代码如下:
void CNewTerisView::OnKeyDown(UINT nChar, UINT nRepCnt,
UINT nFlags)
{
// TODO: Add your message handler code here and/or call
default
////////左边玩家的控制键
if(nChar==VK_NUMPAD0)
OnPause();
if(nChar==VK_RIGHT)
activeBrick->shiftRight(bin);
else if(nChar==VK_LEFT)
activeBrick->shiftLeft(bin);
else if(nChar==VK_UP)
activeBrick->rotateClockwise(bin);
else if(nChar==VK_DOWN)
activeBrick->shiftDown(bin);
//////////右边玩家的控制键
if(nChar==VK_NUMPAD6)
activeBrick2->shiftRight(bin2);
else if(nChar==VK_NUMPAD4)
activeBrick2->shiftLeft(bin2);
else if(nChar==VK_NUMPAD8)
>rotateClockwise(bin2); activeBrick2-
else if(nChar==VK_NUMPAD5)
activeBrick2->shiftDown(bin2);
Invalidate(FALSE);
CView::OnKeyDown(nChar, nRepCnt, nFlags);
}
四(测试与实现:
奇幻模式:
经典模式:
单人模式:
游戏结束:
五( :
通过本次双人版俄罗斯方块游戏的开发,使我对VC可视化编程产生了更大的兴趣,也激发了我开发游戏的强烈兴趣。以前在dos环境下编写的俄罗斯方块游戏与此相比,能够充分体现出可视化编程的优势,界面比dos下的好看多了。而且其操作简便,用户体验很好。
这次的开发过程没有前几次那么曲折,可能是我的编程能力真的有了提高,当然,这也主要是因为老师已经把俄罗斯方块的实现写好了,我们只是做一些修改。你想要修改成自己想要的东西,首先,你得看懂程序,否则你不知道在那里修改,怎么修改。通过修改程序,实现双人版俄罗斯方块,在这一过程中,我们也学到了很多东西,有技巧性的代码,也有思维上的模式与创新等。只有你不断的改,不断地练习,你的编程能力在不知不觉中提高。
通过自己的修修改改,不知不觉就实现了你所想要的东西。当然,这其中一定会有挫折,会有BUG,当你真的编出你所想要的东西时,这种成就感将以前的所有痛苦、bug都化为乌有。就是在不断的出现问题,解决问题的过程中学习。 很多人都知难而退,也许只有坚持到底,你才会解决解决所遇到的困难,你才会成功。
本程序的优点:具有较好的界面,实现了双人版俄罗斯方块的同时,实现了预测及不同于经典模式砖块的选择,还加了音乐。
本程序的缺点:游戏的控制不够灵活,反应较慢,还有很多有待提高的地方。
本文档为【双人版俄罗斯方块游戏实验报告】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑,
图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。