C++控制臺實現(xiàn)俄羅斯方塊游戲
更新時間:2020年07月21日 15:32:17 作者:Richard_wx
這篇文章主要為大家詳細介紹了C++控制臺實現(xiàn)俄羅斯方塊游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
之前學了些C++的課程,一直想著說編點小游戲,可是MFC又不想學,所以就只能變成控制臺的小游戲。
俄羅斯方塊一定是很多人小時候玩過的游戲。接下來就說說設(shè)計想法。
主要實現(xiàn),選擇游戲的等級,加速下降,不同形狀不同顏色,暫停和退出功能。
首先是類的設(shè)計。
class Box
{
private:
int map[23][12];//畫面坐標,記錄有方塊的點,也是游戲界面
int hotpoint[2];//當前活動的點,所有圖形都是以此為基準繪制的
int top;//當前最高位置
int point;//分數(shù)
int level;//等級
int ID;//當前活動圖形的ID號
int colorID;//圖形的顏色ID。
public:
Box()//初始化
{
int i,j;
for(i=0;i<23;i++)
for(j=0;j<12;j++)
map[i][j]=0;
hotpoint[0]=0;
hotpoint[1]=5;
point=0;
level=1;
top=99;
ID=0;
}
void SetColor(int color);//顏色
void DrawMap();//畫游戲的大界面
bool Judge(int x,int y);//判斷當前位置能否繪制圖形
void Welcome();//歡迎界面
void DrawBox(int x,int y,int num);//繪制圖形
void Redraw(int x,int y,int num);//擦除圖形
void Run();//運行
void Turn();//轉(zhuǎn)動方塊
void UpdataMap();//更新畫面
void Pause();//暫停
};
接下來就是一些常量和光標函數(shù),便于保存和調(diào)用
#define A1 0//A代表長條型,B為方塊,C為L型,D為閃電型
#define A2 1
#define B 2
#define C11 3
#define C12 4
#define C13 5
#define C14 6
#define C21 7
#define C22 8
#define C23 9
#define C24 10
#define D11 11
#define D12 12
#define D21 13
#define D22 14
void SetPos(int i,int j)//設(shè)定光標位置
{
COORD pos={i,j};
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}
const int sharp[15][8]=
{
{0,0,1,0,2,0,3,0},{0,0,0,1,0,2,0,3},
{0,0,1,0,0,1,1,1},
{0,0,1,0,1,1,1,2},{0,1,1,1,2,0,2,1},{0,0,0,1,0,2,1,2},{0,0,0,1,1,0,2,0},
{1,0,1,1,1,2,0,2},{0,0,0,1,1,1,2,1},{0,0,0,1,0,2,1,0},{0,0,1,0,2,0,2,1},
{0,0,0,1,1,1,1,2},{0,1,1,0,1,1,2,0},
{0,1,0,2,1,0,1,1},{0,0,1,0,1,1,2,1}
};//形狀點的各個坐標,先縱后橫
const int high[15]={4,1,2,2,3,2,3,2,3,2,3,2,3,2,3};//這個數(shù)組是用來保存各個形狀高度的,以上面的坐標相對應(yīng)
類方法的實現(xiàn)
void Box::SetColor(int colorID)
{
int n_color;
switch(colorID)
{
case 0: n_color = 0x08;break;
case 1: n_color = 0x0C;break;
case 2: n_color = 0x0D;break;
case 3: n_color = 0x0E;break;
case 4: n_color = 0x0A;break;
}
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), n_color);
}
void Box::DrawMap()//畫界面
{
int i;
SetColor(0);//界面顏色
for(i=0;i<14;i++)
{
SetPos(i*2,0);
cout<<"■";
}
for(i=1;i<=24;i++)
{
SetPos(0,i);
cout<<"■";
SetPos(13*2,i);
cout<<"■";
}
for(i=0;i<14;i++)
{
SetPos(i*2,24);
cout<<"■";
}
i=15;
for(i=15;i<=25;i++)
{
SetPos(i*2,0);
cout<<"■";
}
for(i=1;i<=8;i++)
{
SetPos(15*2,i);
cout<<"■";
SetPos(25*2,i);
cout<<"■";
}
for(i=15;i<=25;i++)
{
SetPos(i*2,9);
cout<<"■";
}
SetPos(16*2,16);
cout<<"俄羅斯方塊";
SetPos(16*2,17);
cout<<"分數(shù):"<<point;
SetPos(16*2,18);
cout<<"級別:"<<level;
}
void Box::DrawBox(int x,int y,int num)//繪制圖形
{
int i;
int nx,ny;
if (num<2)SetColor(1);//0、1是長條
else if(num<3) SetColor(2);//2 方塊
else if(num<11) SetColor(3);//3、4、5、6、7、8、9、10
else SetColor(4);
for(i=0;i<4;i++)
{
nx=x+sharp[num][i*2];
ny=y+sharp[num][i*2+1];
SetPos((ny+1)*2,nx+1);//利用sharp數(shù)組相對于點x,y繪制形狀
//SetColor(i+1);
cout<<"■";
}
}
void Box::Redraw(int x,int y,int num)//擦除圖形,原理同上
{
int i;
int nx,ny;
for(i=0;i<4;i++)
{
nx=x+sharp[num][i*2];
ny=y+sharp[num][i*2+1];
SetPos((ny+1)*2,nx+1);
cout<<" ";
}
}
void Box::Turn()//轉(zhuǎn)動圖形,單純的該ID而已
{
switch(ID)
{
case A1: ID=A2; break;
case A2: ID=A1; break;
case B: ID=B; break;
case C11: ID=C12; break;
case C12: ID=C13; break;
case C13: ID=C14; break;
case C14: ID=C11; break;
case C21: ID=C22; break;
case C22: ID=C23; break;
case C23: ID=C24; break;
case C24: ID=C21; break;
case D11: ID=D12; break;
case D12: ID=D11; break;
case D21: ID=D22; break;
case D22: ID=D21; break;
}
}
void Box::Welcome()//歡迎界面
{
char x;
while(1)
{
system("cls");
cout<<"■■■■■■■■■■■■■■■■■■■"<<endl;
cout<<"■ 俄羅斯方塊控制臺版 ■"<<endl;
cout<<"■■■■■■■■■■■■■■■■■■■"<<endl;
cout<<"■ A,D左右移動 S向下加速 ■"<<endl;
cout<<"■ W 轉(zhuǎn)動方塊 P暫停游戲 ■"<<endl;
cout<<"■ Q退出游戲 ■"<<endl;
cout<<"■■■■■■■■■■■■■■■■■■■"<<endl;
cout<<"■ ■"<<endl;
cout<<"■ 按1-9選擇等級??! ■"<<endl;
cout<<"■ ■"<<endl;
cout<<"■ ■"<<endl;
cout<<"■■■■■■■■■■■■■■■■■■■"<<endl;
SetPos(16,9);
x=getch();
if(x<='9'&&x>='1')//設(shè)置等級
{
level=x-'0';
break;
}
}
}
void Box::UpdataMap()//更新畫面(關(guān)鍵)
{
int clear;
int i,j,k;
int nx,ny;
int flag;
for(i=0;i<4;i++)//更新map數(shù)組的信息
{
nx=hotpoint[0]+sharp[ID][i*2];
ny=hotpoint[1]+sharp[ID][i*2+1];
map[nx][ny]=1;
}
if(hotpoint[0]<top)//如果熱點高于頂點則更新頂點,這里0表示的是縱向的
top=hotpoint[0];
clear=0;//消除的格數(shù)
for(i=hotpoint[0];i<hotpoint[0]+high[ID];i++)
{
flag=0;
for(j=0;j<12;j++)//檢測是否可以消除此行
{
if(map[i][j]==0)//代表有空格,不能消除
{
flag=1;//1表示不能消除
break;
}
}
if(flag==0)//可以消除
{
for(k=i;k>=top;k--)//從當前位置向上所有的點下移一行
{
if(k==0)//最高點特殊處理
for(j=0;j<12;j++)
{
map[k][j]=0;
SetPos((j+1)*2,k+1);
cout<<" ";
}
else
{
for(j=0;j<12;j++)
{
map[k][j]=map[k-1][j];
SetPos((j+1)*2,k+1);
if(map[k][j]==0)
cout<<" ";
else
cout<<"■";
}
}
}
top++;//消除成功,最高點下移
clear++;
point+=clear*10*level;
}
}
SetColor(0);
SetPos(16*2,17);
cout<<"分數(shù):"<<point;
}
void Box::Run()//運行游戲
{
int i=0;
char x;
int Count;//計數(shù)器
int nextID;
int temp;
srand((int)time(0));//將隨機數(shù)的起點設(shè)置為time(0):不帶秒
ID=rand()%15;//隨機生成ID和下一個ID
nextID=rand()%15;//這里為了方便,其實每個形狀不是等概率生成的
DrawBox(hotpoint[0],hotpoint[1],ID);//繪制圖形
DrawBox(3,17,nextID);
Count=1000-level*100;//等級決定計數(shù),這里是用Count控制時間,來控制下落的速度
while(1)
{
if(i>=Count)
{
i=0;//計數(shù)器清零
if(Judge(hotpoint[0]+1,hotpoint[1]))//如果下個位置無效(即到底)
{
UpdataMap();//更新畫面
ID=nextID;//生成新ID,用原等待ID替換為當前ID
hotpoint[0]=0;//熱點更新
hotpoint[1]=5;
Redraw(3,17,nextID);
nextID=rand()%15;
DrawBox(hotpoint[0],hotpoint[1],ID);
DrawBox(3,17,nextID);
if(Judge(hotpoint[0],hotpoint[1]))//無法繪制開始圖形,游戲結(jié)束
{
//getch();
system("cls");
SetPos(25,15);
cout<<"游戲結(jié)束!??!最終得分為:"<<point<<endl;
system("pause");//就是在命令行上輸出一行類似于“Press any key to exit”
exit(0);//關(guān)閉所有文件,退出正在執(zhí)行的程序,返回0代表正常結(jié)束
}
}
else
{
Redraw(hotpoint[0],hotpoint[1],ID);//沒有到底,方塊下移一位
hotpoint[0]++;//熱點下移
DrawBox(hotpoint[0],hotpoint[1],ID);
}
}
if(kbhit())//讀取鍵盤信息
{
x=getch();
if(x=='a'||x=='A')//左移
{
if(Judge(hotpoint[0],hotpoint[1]-1)==0)
{
Redraw(hotpoint[0],hotpoint[1],ID);
hotpoint[1]-=1;
DrawBox(hotpoint[0],hotpoint[1],ID);
}
}
if(x=='d'||x=='D')//右移
{
if(Judge(hotpoint[0],hotpoint[1]+1)==0)
{
Redraw(hotpoint[0],hotpoint[1],ID);
hotpoint[1]+=1;
DrawBox(hotpoint[0],hotpoint[1],ID);
}
}
if(x=='s'||x=='S')//向下加速?。。。。。。?!此處可以改進,可以改進加速效果。改成+3之后,會出現(xiàn)BUG,最后幾個無法加速
{
if(Judge(hotpoint[0]+3,hotpoint[1])==0)
{
Redraw(hotpoint[0],hotpoint[1],ID);
hotpoint[0]+=1;
DrawBox(hotpoint[0],hotpoint[1],ID);
}
}
if(x=='w'||x=='W')//轉(zhuǎn)動方塊
{
temp=ID;
Turn();
if(!Judge(hotpoint[0],hotpoint[1]))
{
Redraw(hotpoint[0],hotpoint[1],temp);
DrawBox(hotpoint[0],hotpoint[1],ID);
}
else
ID=temp;
}
if(x=='p'||x=='P')
{
//getch();
//system("cls");
Pause();
}
if(x=='q'||x=='Q')
{
system("cls");
SetPos(25,15);
cout<<"游戲結(jié)束?。?!最終得分為:"<<point<<endl;
system("pause");
exit(0);
}
while(kbhit())//讀掉剩下的鍵盤信息
getch();
}
Sleep(1);//等待1毫秒
i++;//計數(shù)器加1
}
}
int Box::Judge(int x,int y)//判斷當前是否可以繪制方塊
{
int i;
int nx,ny;
for(i=0;i<4;i++)
{
nx=x+sharp[ID][i*2];
ny=y+sharp[ID][i*2+1];
if(nx<0||nx>=23||ny<0||ny>=12||map[nx][ny]==1)//不能,返回1
return 1;
}
return 0;
}
void Box::Pause()
{
system("cls");
while(1)
{
SetPos(30,13);
cout<<"暫停等待,咖啡時間^-^"<<endl;
if(getch()=='p'||getch()=='P')
break;
}
SetPos(30,13);
cout<<" "<<endl;
DrawMap();
int i ,j;
for(i=0;i<23;i++)
for(j=0;j<12;j++)
if(map[i][j]==1)
{
SetPos((j+1)*2,i+1);
cout<<"■";
}
}
void main()//主函數(shù)
{
Box game;
game.Welcome();
system("cls");
game.DrawMap();
game.Run();
}
待改進的點:
1、加速下降的時候,從代碼中也可以發(fā)現(xiàn),最后幾格沒法加速。
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
C++數(shù)據(jù)結(jié)構(gòu)哈希表詳解
C++標準庫中使用的unordered_map底層實現(xiàn)是哈希表,下面這篇文章主要給大家介紹了關(guān)于C++中使用哈希表(unordered_map)的一些常用操作方法,需要的朋友可以參考下2022-07-07
帶你用C語言實現(xiàn)strtok和字符串分割函數(shù)
下面小編就為大家?guī)硪黄猚語言中字符串分割函數(shù)及實現(xiàn)方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2021-09-09

