俄罗斯方块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();

}


...全文
154 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
scv 2001-09-20
  • 打赏
  • 举报
回复
Done
scv 2001-07-21
  • 打赏
  • 举报
回复
if((pFig->GetCurY()<(19-pFig->BottonBlank()))&&(pFig->CanDown()))
pFig->Down();

就是这一行了,在main()中
rockswang 2001-07-20
  • 打赏
  • 举报
回复
我看了半天还是找不到……
呵呵,我对Dos编程太不熟悉了,
我们多email联系吧,QQ我现在不太常上了
email: rocks_lee@263.net
homepage: http://wannaplay.51.net
scv 2001-07-20
  • 打赏
  • 举报
回复
其实在这个程序中方块是可以自由下落的,代码在主函数中
我的志向是程序员,也想交一些程序员的朋友 rock_lee , can we make friends...

my qq is 9393406 , thanks

to axinist(阿信) 仔细看source code 就什么都知道了,hehe
rockswang 2001-07-20
  • 打赏
  • 举报
回复
对,也可以用GetKeyState。
你要是坚持用Dos,我记得可以调键盘中断,直接得到扫描码的。
另外你的这个方块是不是没有键盘输入,就不会自动下落呀?这是个问题吧:)

想起来我的第一个C++作品也是个俄罗斯方块呢,呵呵,
考完试用一晚上在我的486笔记本上用TC++3编的,不过是字符界面的,
想起来当时所谓C++,不过是用了class简单包了一下,外加cout而已,呵呵。
可惜代码早找不到了。

我编的第三个俄罗斯方块(也是三年前的了),用DirectX,有人工智能,可以人机对战,双人对决(当然也可以单人),感兴趣可以参考一下,源代码available。
http://wannaplay.51.net/products.html
axinist 2001-07-20
  • 打赏
  • 举报
回复
谁能讲一下,方块的编程原理是什么?
scv 2001-07-20
  • 打赏
  • 举报
回复
GetKeyboardState说的是WIN32 API的函数吗?
rockswang 2001-07-20
  • 打赏
  • 举报
回复
在Windows下可以用GetKeyboardState来进行按键的即时响应,每秒钟检测上10几次就行了,不要用OnKeyDown什么的。

16,472

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧