俄罗斯方块source code 请哪位大侠能用MFC封装一下。
scv 2001-07-20 02:21:15 刚学C++不久的人,抱着兴趣总想编一些小游戏来玩玩,俄罗斯方块是我小时候最喜欢玩的游戏了(顺便说一下,文曲星上的俄罗斯方块9-9我能在分数达到70之前把它全部消完:))所以一直以来就想自己做一个,可是都没有时间来研究它,乘着放暑假的机会终于搞了几天把它做了出来,源程序在下面,在Borland C++ 3.1下已经通过,大家不要笑,这个编译器虽然老了些,但我想那些一路从DOS编程中坐过来的程序员们或是初学者们还是很感谢这个小而精的编译器的吧。
我现在有个小小的要求,希望你们哪位能把我的这个程序用MFC封装一下,最好能用CDocument和CView封装起来。因为这个程序中关于键盘的响应部分实在是太落后了,程序中已经用了两个类来对这个程序进行了封装,改起来应该不是很困难,如果有时间的话就做一下吧,俄罗斯方块不止是我最爱的游戏吧,谢谢大家了。Let's share the source code together ,happily......
如果改好了请发到我的信箱里来,谢谢。psionic@163.net
//----------------------
// e Game
// Reserved By Leon
//----------------------
# include <graphics.h>
# include <math.h>
# include <conio.h>
# include <dos.h>
# include <iostream.h>
# include <stdlib.h>
# include <stdio.h>
int WorkSpace[20][10]; // 把WorkSpace[][]]设为是全局变量,
//是为了有利于在各个类中的成员函数中不断地修改它
//也可以把它作为CWorkSpace的私有成员,看你的
int Triada[4][4]={ {0,4,0,0},
{4,4,4,0},
{0,0,0,0},
{0,0,0,0} };
int LCorner[4][4]={ {5,5,5,0},
{5,0,0,0},
{0,0,0,0},
{0,0,0,0} };
int RCorner[4][4]={ {7,7,7,0},
{0,0,7,0},
{0,0,0,0},
{0,0,0,0} };
int LZerg[4][4]={ {6,6,0,0},
{0,6,6,0},
{0,0,0,0},
{0,0,0,0} };
int RZerg[4][4]={ {0,3,3,0},
{3,3,0,0},
{0,0,0,0},
{0,0,0,0} };
int Stick[4][4]= { {2,2,2,2},
{0,0,0,0},
{0,0,0,0},
{0,0,0,0} };
int Box[4][4]= { {1,1,0,0},
{1,1,0,0},
{0,0,0,0},
{0,0,0,0} };
//----------------------------------------------------------------------
// 本程序用了两个类,这两个类各做各的事(我指的是在屏幕上绘画)
// 这样虽然简化了程序,但是在DOS下出现了一个小Bug,因为在同一个时刻
// 或是相差极短的时间内,屏幕被重绘了两次,这样屏幕看上去就有一点地闪烁
// 希望在Windows的环境下没有这个问题。
//----------------------------------------------------------------------
class CWorkSpace{
public:
CWorkSpace(int s,int d){
score=s;
dl=d;
}
~CWorkSpace(){
}
//-------------------------------------------------------
void InitBox(){ //初始化屏幕
setcolor(RED);
rectangle(0,0,202,402);
outtextxy(245,85,"Score: 0");
randomize();
}
//-------------------------------------------------------
void Print(){ // CWorkSpace::Print 在每一个时刻对WorkSpace[][]进行绘画
for(int i=0;i<20;i++) // 0则用BLACK填充,!=0则用WHITE填充
for(int j=0;j<10;j++)
if(WorkSpace[i][j]!=0){
setfillstyle(SOLID_FILL,WHITE);
bar(20*j,20*i,20*j+20,20*i+20);
}
else if(WorkSpace[i][j]==0){
setfillstyle(SOLID_FILL,BLACK);
bar(20*j,20*i,20*j+20,20*i+20);
}
}
//-------------------------------------------------------
int TopBlank(){ // WorkSpace[][]从顶部数有多少空白(都是0的区域)
int p2=0;
for(p2=0;p2<20;p2++)
for(int q2=0;q2<10;q2++)
if(WorkSpace[p2][q2]==0)
continue;
else{
return p2;
}
return 20;
}
int Height(){ // WorkSpace[][]的高度(从底部开始数起)
int h=TopBlank();
return 20-h;
}
//-------------------------------------------------------
void Delete(int i){ //此函数在另一个成员函数Scan()中被调用,当Scan检测到WorkSpace[][]
//有一行全部都是1的时候(就是可以消去的时候),在WorkSpace[][]中消去这一行
for(int p=i;p>0;p--)
for(int q=0;q<10;q++)
WorkSpace[p][q]=WorkSpace[p-1][q];
for(int r=0;r<10;r++)
WorkSpace[0][r]=0;
}
//--------------------------------------------------------
void Scan(){ //每一个时刻检查WorkSpace[][]的每行,若满足消去的条件(这一行都是1)
//就调用Delete(),在WorkSpace[][]中消去那一行
dl=0;
int i;
for(i=19;i>=0;i--){
for(int j=0;j<10;j++)
if(WorkSpace[i][j]==0)
break; //break out of for2
else continue;
if(j==10) { Delete(i);i++; dl++; }
} //end of for1
switch(dl){ //在实际的俄罗斯方块中,加分情况是根据每一次消去的行数来
//确定的,具体的规则如下:
case 1: { score=score+1; break; }//每一次消去一行,加一分
case 2: { score=score+3; break; }//每一次消去两行,加三分
case 3: { score=score+7; break; }//每一次消去三行,加七分
case 4: { score=score+13; break; }//每一次消去四行,加十三分
default : break;
}
PrintScore();
Print();
}
//------------------------------------------------------
void PrintScore(){ //显示当前的分数
char buf[20];
setfillstyle(SOLID_FILL,BLACK);
bar(240,80,320,100);
sprintf(buf,"Score: %d",score);
outtextxy(245,85,buf);
}
protected:
int score; //记录当前的分数
int dl; //记录每一次消去的行数(delete levels)
}; //End of CWorkSpace
//------------------------------------------------------
//------------------------------------------------------
class CFig{ //CFig是当前下落的方块的类,在这个类中定义了一个Source[4][4]记录每一种方块的形状
public:
CFig(int P[4][4],int x,int y){
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
Source[i][j]=P[i][j];
CurX=x;
CurY=y; //CurX,CurY用来记录Source[][]在WorkSpace[][]的位置
}
~CFig(){
}
void PutInto(){ //把当前的方块拷贝到WorkSpace[][]中,
for(int i=0;i<4;i++) // 这个函数在当前方块已经在WorkSpace[][]中死了的时候被调用
for(int j=0;j<4;j++) //成为WorkSpace[][]的一部分了
if(Source[i][j]!=0)
WorkSpace[i+CurY][j+CurX]=Source[i][j];
}
//------------------------------------------------------
void Print(){ //只是把当前方块画到屏幕上去
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
if(Source[i][j]!=0){
setfillstyle(SOLID_FILL,WHITE);
bar(20*(j+CurX),20*(i+CurY),20*(j+CurX)+20,20*(i+CurY)+20);
}
delay(100);
}
void Clear(){ //把当前的方块在屏幕上清除掉
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
if(Source[i][j]!=0){
setfillstyle(SOLID_FILL,BLACK);
bar(20*(j+CurX),20*(i+CurY),20*(j+CurX)+20,20*(i+CurY)+20);
}
}
//-------------------------------------------------------
//-------------------------------------------------------
//-------------------------------------------------------
int LeftBlank(){ //当前方块左边空出多少来(因为是4*4的Source[][],肯定装不满Source[][])
for(int p1=0;p1<4;p1++)
for(int q1=0;q1<4;q1++)
if(Source[q1][p1]==0)
continue;
else{
return p1;
}
}
int RightBlank(){
for(int p3=3;p3>=0;p3--)
for(int q3=0;q3<4;q3++)
if(Source[q3][p3]==0)
continue;
else{
return p3;
}
}
int BottonBlank(){
for(int p4=3;p4>=0;p4--)
for(int q4=0;q4<4;q4++)
if(Source[p4][q4]==0)
continue;
else{
return p4;
}
}
//---------------------------------------------------
int TopBlank(){
for(int p2=0;p2<4;p2++)
for(int q2=0;q2<4;q2++)
if(Source[p2][q2]==0)
continue;
else{
return p2;
}
}
//----------------------------------------------------
void Rotate(){ //此函数是最重要的函数,它相应了旋转这一消息
//int CurXX=CurX;
//int CurYY=CurY;
int Temp[4][4];
int leftBlank,topBlank;
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
Temp[j][3-i]=Source[i][j]; //简单的矩阵转置
Clear();
//下面的代码把当前的方块移到Source[][]的最左边和最上边
for(int ii=0;ii<4;ii++)
for(int jj=0;jj<4;jj++)
Source[ii][jj]=Temp[ii][jj];
leftBlank=LeftBlank();
topBlank=TopBlank();
for(int iii=0;iii<4;iii++)
for(int jjj=0;jjj<4;jjj++)
Source[iii][jjj]=Temp[(iii+topBlank)%4][(jjj+leftBlank)%4];
// 处理方块在WorkSpace[][]的由边缘时的问题
int bb=(Height()>Width()?Height():Width()); //bb取当前方块高度和宽度中大者
if(CurX>10-bb)
CurX=10-bb;
if(CurY>20-bb)
CurY=20-bb;
Print();
}
//-----------------------------------------------------
int Height(){ // 当前方块的高度
int i;
for(i=0;i<4;i++){
for(int j=0;j<4;j++)
if(Source[i][j]!=0)
break;
if(j==4) return i;
}
return 4;
}
//-------------------------------------------------------
int Width(){ // 当前方块的宽度
int j;
for(int i=0;i<4;i++){
for(j=0;j<4;j++)
if(Source[j][i]!=0)
break;
if(j==4) return i;
}
return 4;
}
//-------------------------------------------------------
int CanDown(){ //判断当前方块是否能够下落
int a[4]={0,0,0,0}; //a[]用来记录当前方块按"列"来数时,每一列的长度
int k=0,p=0,q=1;
for(int i=0;i<4;i++)
for(int j=3;j>=0;j--)
if(Source[j][i]!=0){
a[k]=j+1; // cout<<a[k];
if(k<=Width()) k++;
break;
}
//cout<<endl;
while(p<Width()){
if(WorkSpace[CurY+a[p]][CurX+p]!=0){
q=0;
break;
}
p++;
} // end while
return q;
}
int CanLeft(){
int a[4]={0,0,0,0}; int k=0,p=0,q=1;
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
if(Source[i][j]!=0){
a[k]=j; // cout<<a[k];
if(k<=Height()) k++;
break;
}
//cout<<endl;
while(p<Height()){
if(WorkSpace[CurY+p][CurX-1+a[p]]!=0){
q=0;
break;
}
p++;
} // end while
return q;
}
int CanRight(){
int a[4]={0,0,0,0}; int k=0,p=0,q=1;
for(int i=0;i<4;i++)
for(int j=3;j>=0;j--)
if(Source[i][j]!=0){
a[k]=j+1; // cout<<a[k];
if(k<=Height()) k++;
break;
}
//cout<<endl;
while(p<Height()){
if(WorkSpace[CurY+p][CurX+a[p]]!=0){
q=0;
break;
}
p++;
} // end while
return q;
}
//---------------------------------------------------------------------------
void Left(){ // afx_msg OnPressKeyLeft()
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
if(Source[i][j]!=0){
setfillstyle(SOLID_FILL,BLACK);
bar(20*(j+CurX),20*(i+CurY),20*(j+CurX)+20,20*(i+CurY)+20);
}
CurX--;
Print();
}
void Right(){
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
if(Source[i][j]!=0){
setfillstyle(SOLID_FILL,BLACK);
bar(20*(j+CurX),20*(i+CurY),20*(j+CurX)+20,20*(i+CurY)+20);
}
CurX++;
Print();
}
void Down(){
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
if(Source[i][j]!=0){
setfillstyle(SOLID_FILL,BLACK);
bar(20*(j+CurX),20*(i+CurY),20*(j+CurX)+20,20*(i+CurY)+20);
}
CurY++;
Print();
}
void Cout(){ //Debug时用,只是简单的输出当前方块的矩阵表示
for(int i=0;i<4;i++){
for(int j=0;j<4;j++)
cout<<Source[i][j];
cout<<endl;
}
}
//------------------------------------------------------
void DrawNext(){ //画出提示的下一个方块
setfillstyle(SOLID_FILL,BLACK);
bar(240,0,320,80);
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
if(Source[i][j]!=0){
setfillstyle(SOLID_FILL,WHITE);
bar(20*(j+12),20*i,20*(j+12)+20,20*i+20);
}
}
int GetCurX(){
return CurX;
}
int GetCurY(){
return CurY;
}
//------------------------------------------------------
private:
int CurX;
int CurY; //当前方块在WorkSpace[][]中的位置
int Source[4][4];
}; // End of CFig
void main(){
int driver=DETECT;
int mode=0;
initgraph(&driver,&mode,"");
setbkcolor(BLACK);
CWorkSpace* pWS=new CWorkSpace(0,0);
pWS->InitBox();
CFig* pFig=new CFig(Triada,3,0);
while(1){ // main while
CFig* ppFig;
int ran=random(13);
switch(ran){
case 0 : { ppFig=new CFig(LZerg,3,0); break; }
case 1 : { ppFig=new CFig(LZerg,3,0); break; }
case 2 : { ppFig=new CFig(RZerg,3,0); break; }
case 3 : { ppFig=new CFig(RZerg,3,0); break; }
case 4 : { ppFig=new CFig(Triada,3,0); break; }
case 5 : { ppFig=new CFig(Triada,3,0); break; }
case 6 : { ppFig=new CFig(LCorner,3,0); break; }
case 7 : { ppFig=new CFig(LCorner,3,0); break; }
case 8 : { ppFig=new CFig(RCorner,3,0); break; }
case 9 : { ppFig=new CFig(RCorner,3,0); break; }
case 10 : { ppFig=new CFig(Box,3,0); break; }
case 11 : { ppFig=new CFig(Box,3,0); break; }
case 12 : { ppFig=new CFig(Stick,3,0); break; }
} //end of switch
ppFig->DrawNext();
//pWS->PrintScore();
while(1){
// cout<<pFig->Width()<<pFig->Height()<<endl;
// cout<<pWS->Height()<<" ";
pWS->Scan();
if(pWS->Height()>=20) goto end;
if((pFig->GetCurY()<(19-pFig->BottonBlank()))&&(pFig->CanDown()))
pFig->Down();
else{
pFig->PutInto();
break;
}
pFig->Print(); //PutInto(Triada);
while(1){
if(kbhit()){ //Keyboard Message Map
char ch=getch(); //由于DOS下没有VirtualKey,也不知道怎样去响应真正的上下左右
switch(ch){ //只能用字母来代替啦,而且一定要是小写字母哟!
//这就是kbhit()函数的Bug,响应速度太慢了
//在用MFC封装的时候一定要修正这个Bug,你一定会忍受不了的,我好可怜呀
case 'l': if((pFig->CanRight())&&(pFig->GetCurX()<9-pFig->RightBlank()))
pFig->Right();
break;
case 'j': if(pFig->CanLeft()&&pFig->GetCurX()>0)
pFig->Left();
break;
case 'k': if(pFig->CanDown()&&pFig->GetCurY()<19-pFig->BottonBlank())
pFig->Down();
break;
case 'a':
pFig->Rotate();
break;
case 'q': goto end;
default : break;
} //end switch
} //end if
break;
}
}// end while of keyboard message map
pFig=ppFig;
} // end of main while
end:
getch();
closegraph();
getch();
}