C++實(shí)現(xiàn)俄羅斯方塊源碼
更新時(shí)間:2021年06月18日 11:35:02 作者:網(wǎng)絡(luò)
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)俄羅斯方塊源碼完整版,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
本文實(shí)例為大家分享了C++實(shí)現(xiàn)俄羅斯方塊的具體代碼,供大家參考,具體內(nèi)容如下
先是效果圖:
主菜單:

游戲:

設(shè)置:

錯(cuò)誤處理:

代碼:
#include <iostream.h>
#include <conio.h>
#include <stdio.h>
#include <windows.h>
#include <fstream.h>
#include <time.h>
#include <cstring>
#pragma comment( lib,"winmm.lib" )
//定義
//方塊
#define NO 0
#define SQR 1
//碰撞檢測(cè)
#define OK 0
#define CANTMOVE 1
//方向
#define UP 0
#define DOWN 1
#define LEFT 2
#define RIGHT 3
//錯(cuò)誤碼
#define no_enough_memory 0
#define set_no_found 1
#define dat_no_found 2
#define error_argument 3
//函數(shù)聲明
//模塊
void play();//開始游戲
void sets();//設(shè)置
void highscores();//排行榜
void copyright();//作者
//功能
void mapsetup();//準(zhǔn)備地圖
bool newsqr();//放置方塊,返回是否游戲結(jié)束
int move(int direction);//移動(dòng)方塊,返回定義表
void movetomap();//把當(dāng)前方塊移動(dòng)到地圖上
int wholeline();//檢查是否組成了一層,返回層數(shù),-1表示沒(méi)有
void deleteline(int which);//刪除一行
void endup();//結(jié)束游戲,清理內(nèi)存
//顯示
void show();//刷新畫面
void showmenu(char* menu);//顯示菜單
//文件
void loadset();//加載設(shè)置
void saveset();//保存設(shè)置
void loadhs();//加載排行榜
bool addscores(int score,char name[50]);//增加一個(gè)分?jǐn)?shù),返回是否是高分
void savehs();//保存排行榜
//坐標(biāo)變換
int get(int x,int y);
void set(int x,int y,int date);
//結(jié)構(gòu)
//設(shè)置
struct{
int xs,ys;//屏幕大小
int speed;//速度
char sqr[3],no[3],frame[3];//方塊、空白處、邊框的樣式
}gameset;
//排行榜
struct{
char name[50];
int score;
}rating[10];
//全局變量
//變量
int* map=NULL;//地圖
bool now[4][4];//當(dāng)前方塊
int xnow,ynow;//當(dāng)前位置
int guide;//分?jǐn)?shù)
//常量
const bool shap[7][4][4]={//形狀
{\
0,0,0,0,\
0,0,0,0,\
1,1,1,1,\
0,0,0,0,\
},\
{\
0,0,0,0,\
0,1,1,0,\
0,1,1,0,\
0,0,0,0,\
},\
{\
0,0,0,0,\
0,1,1,1,\
0,0,1,0,\
0,0,0,0,\
},\
{\
0,0,0,0,\
1,0,0,0,\
1,1,1,0,\
0,0,0,0,\
},\
{\
0,0,0,0,\
0,0,0,1,\
0,1,1,1,\
0,0,0,0,\
},\
{\
0,1,0,0,\
0,1,1,0,\
0,0,1,0,\
0,0,0,0,\
},\
{\
0,0,1,0,\
0,1,1,0,\
0,1,0,0,\
0,0,0,0,\
}\
};
const char errword[4][50]={"程序沒(méi)能取得足夠的內(nèi)存","無(wú)法打開或找不到設(shè)置文件set.ini","無(wú)法打開或找不到排行榜數(shù)據(jù)highscore.dat","您設(shè)置的參數(shù)太大或者太小"};
//控制臺(tái)
HANDLE hout;//控制臺(tái)句柄
COORD curpos={0,0};//光標(biāo)坐標(biāo)
//主函數(shù)
int main()
{
start1:
try
{
hout = GetStdHandle(STD_OUTPUT_HANDLE);//獲取控制臺(tái)句柄,以便移動(dòng)光標(biāo)
srand(time(0));//用當(dāng)前時(shí)間初始化隨機(jī)數(shù)生成器
loadset();//加載
loadhs();
start2:
while(1)
{
showmenu("俄羅斯方塊\n請(qǐng)選擇菜單:\n1.開始游戲\n2.設(shè)置\n3.排行榜\n4.幫助\n5.保存并退出\n");
switch(getch())
{
case '1':
system("cls");//play函數(shù)覆蓋界面而不是清屏,所以需要先清屏
play();
break;
case '2':
sets();
break;
case '3':
highscores();
break;
case '4':
copyright();
break;
case '5':
savehs();//保存數(shù)據(jù)
saveset();
return 0;
}
}
}
catch(int errnum)//錯(cuò)誤處理
{
system("cls");
printf("o(>﹏<)o 出錯(cuò)啦!\n程序收到了一條錯(cuò)誤信息,錯(cuò)誤碼是:%d(%s)\n您可以聯(lián)系我們解決這個(gè)問(wèn)題。\n",errnum,errword[errnum]);
printf("\n你可以選擇以下操作:\n1.重啟程序\n2.以默認(rèn)設(shè)置重啟程序\n3.向設(shè)置和數(shù)據(jù)文件寫入默認(rèn)設(shè)置然后重啟\n4.退出\n");
switch(getch())
{
case '1':
goto start1;
case '2':
gameset.xs=20;
gameset.ys=20;
gameset.speed=100;
strcpy(gameset.sqr,"[]");//無(wú)法直接給數(shù)組復(fù)制數(shù)據(jù)
strcpy(gameset.no," ");
strcpy(gameset.frame,"::");
int i;
for(i=0;i<10;i++)
strcpy(rating[i].name,"未命名"),rating[i].score=0;
goto start2;
case '3':
{
ofstream fout;
fout.open("set.ini");
fout<<"20\n20\n100[]\n \n::\n";
fout.close();
fout.clear();
fout.open("highscore.dat");
int j;
for(j=0;j<10;j++)
fout<<"未命名\n0\n";
goto start1;
}
default:
return -1;//返回異常退出
}
}
return 0;
}
void play()
{
mapsetup();//初始化
/*for(int i=0;i<20;i++)
set(i,19,SQR);*/
while(newsqr())//不斷新建方塊,直到返回NO
{
while(move(DOWN)!=CANTMOVE)//每次向下移動(dòng)方塊,直到不能移動(dòng)
{
guide+=1;//向下移動(dòng)一次加1分
show();//顯示
while(kbhit())//不斷處理鍵盤,直到?jīng)]有按鍵
{
switch(getch())//獲取按鍵
{
case 'w':
move(UP);
break;
case 's':
move(DOWN);
break;
case 'a':
move(LEFT);
break;
case 'd':
move(RIGHT);
break;
}
}
Sleep(gameset.speed);//延時(shí)
}
movetomap();//退出循環(huán)時(shí)無(wú)法向下移動(dòng),把當(dāng)前方塊移動(dòng)到地圖上
int line;
while((line=wholeline())!=-1);//不斷檢查是否出現(xiàn)整行,直到?jīng)]有
deleteline(line);//刪除整行
}
endup();//無(wú)法新建方塊,游戲結(jié)束
return;//結(jié)束
}
//函數(shù)定義
void mapsetup()
{
map=new int[gameset.xs*gameset.ys];//申請(qǐng)內(nèi)存
if(!map)//如果申請(qǐng)到0
throw no_enough_memory;//拋出異常
//初始化地圖
int i,j;
for(i=0;i<gameset.xs;i++)
{
for(j=0;j<gameset.ys;j++)
{
set(i,j,NO);
}
}
guide=0;//分?jǐn)?shù)清零
return;
}
int get(int x,int y)
{
if(y<0)//上方虛擬為空
return NO;
if(x>=0&&x<gameset.xs&&y>=0&&y<gameset.ys)//是否在地圖范圍內(nèi)
return *(map+y*gameset.xs+x);//提取數(shù)據(jù)
else
return SQR;//虛擬地圖側(cè)面和底部有方塊
}
void set(int x,int y,int date)
{
if(x>=0&&x<gameset.xs&&y>=0&&y<gameset.ys)//if(x>0&&x<gameset.xs&&y>0&&y<gameset.ys)//是否在地圖范圍內(nèi)
*(map+y*gameset.xs+x)=date;//寫入
return;
}
bool newsqr(){
int i,j;
for(i=0;i<4;i++)//檢查下一個(gè)方塊要出現(xiàn)的地方是否有方塊
if(get(gameset.xs/2+i,0)==SQR)
return false;//有方塊,創(chuàng)建失敗
int which=rand()%7;//隨機(jī)選擇形狀
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
now[i][j]=shap[which][i][j];//復(fù)制形狀
}
}
for(i=rand()%4;i>0;i--)//旋轉(zhuǎn)隨機(jī)0-3次
move(UP);
xnow=gameset.xs/2;//設(shè)置坐標(biāo)
ynow=-4;
return true;
}
int move(int direction){
int x,y;//儲(chǔ)存坐標(biāo)偏移量
int i,j;
switch(direction)
{
case UP://上鍵是旋轉(zhuǎn)
bool newshap[4][4];//儲(chǔ)存旋轉(zhuǎn)后的圖形
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
newshap[i][j]=now[j][3-i];//坐標(biāo)變換
}
}
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
if(newshap[i][j]==true&&get(xnow+i,ynow+j)==SQR)//對(duì)新圖形碰撞檢測(cè)
return CANTMOVE;//不能旋轉(zhuǎn)
}
}
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
now[i][j]=newshap[i][j];//檢測(cè)完畢,復(fù)制形狀
}
}
return OK;
case DOWN://先記錄坐標(biāo)的偏移量,確定沒(méi)有碰撞以后移動(dòng)
x=0,y=1;
break;
case LEFT:
x=-1;y=0;
break;
case RIGHT:
x=1,y=0;
break;
}
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
if(now[i][j]==true&&get(i+x+xnow,j+y+ynow)==SQR)//如果和地圖上的方塊重合(邊緣以外get函數(shù)也返回SQR,不必單獨(dú)處理)//if(get(i+x,j+y)==SQR)//if(now[i+x][j+y]==SQR)
{
return CANTMOVE;//無(wú)法移動(dòng)
}
}
}
xnow+=x;//檢測(cè)完畢,更改坐標(biāo)
ynow+=y;
return OK;
}
void movetomap(){
guide+=10;//成功放置方塊,加10分
int i,j;
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
if(now[i][j]==true)
set(xnow+i,ynow+j,SQR);//復(fù)制方塊到地圖
}
}
return;
}
int wholeline(){
int i,j;
bool whole;//儲(chǔ)存是否是整行
for(j=0;j<gameset.ys;j++)//for(i=0;i<gameset.ys;i++)
{
whole=true;//假設(shè)是整行
for(i=0;i<gameset.xs;i++)//for(j=0;j<gameset.xs;j++)
{
if(get(i,j)==NO)
whole=false;//有空,不是整行
}
if(whole)
return j;//是整行,返回
}
return -1;//沒(méi)找到整行,返回
}
void deleteline(int which){
int i,j;
guide+=1000;//消方塊,獎(jiǎng)勵(lì)分?jǐn)?shù)
for(i=which;i>=0;i--)
{
for(j=0;j<gameset.xs;j++)
{
set(j,i,get(j,i-1));//移動(dòng)上面的所有方塊,覆蓋這一行。最上面虛擬成了空,不必特殊處理
}
}
return;
}
void endup(){
delete map;//清理內(nèi)存
system("cls");
while(kbhit())//清除所有未處理的按鍵
getchar();
showmenu("游戲結(jié)束,請(qǐng)輸入您的姓名:");
char name[50]="noname";
scanf("%s",&name[0]);//輸入
char word[1000];//儲(chǔ)存格式化以后的字符串
sprintf(&word[0],"游戲結(jié)束!\n\n您(%s)的積分是:%d\n\n%s\n\n請(qǐng)按任意鍵繼續(xù)···\n",name,guide,((addscores(guide,name))?"你進(jìn)入了排行榜":"你沒(méi)有進(jìn)入排行榜"));
showmenu(&word[0]);
getch();
highscores();//顯示排行榜
savehs();//保存排行榜
return;
}
void show(){
int i,j;
SetConsoleCursorPosition(hout,curpos);//system("cls");//光標(biāo)移至左上角,覆蓋之前的圖案
printf("當(dāng)前積分:%d\n",guide);
for(i=0;i<gameset.xs+2;i++)//輸出上邊框
printf(gameset.frame);
printf("\n");
for(j=0;j<gameset.ys;j++)
{
printf(gameset.frame);//左邊框
for(i=0;i<gameset.xs;i++)
{
if(i>=xnow&&i<(xnow+4)&&j>=ynow&&j<(ynow+4))//if(i>=xnow&&i<(xnow+1)&&j>=ynow&&j<(ynow+1))//在當(dāng)前方塊范圍內(nèi)
{
if(now[i-xnow][j-ynow]==true)//如果有方塊
printf(gameset.sqr);
else if(get(i,j)==SQR)//如果地圖有方塊
printf(gameset.sqr);
else//否則,空白
printf(gameset.no);
}
else//不在當(dāng)前方塊范圍內(nèi),輸出地圖
{
if(get(i,j)==SQR)//有方塊
printf(gameset.sqr);
else//否則,沒(méi)方塊
printf(gameset.no);
}
}
printf("::\n");//右邊框和換行
}
for(i=0;i<gameset.xs+2;i++)//下邊框
printf(gameset.frame);
printf("\n");
return;
}
void showmenu(char* menu)
{
int i,j;
char output[100];//儲(chǔ)存本行的文字
system("cls");
for(i=0;i<gameset.xs;i++)
printf(gameset.frame);//輸出上邊框
printf("\n");
i=0,j=0;
while(*menu!='\0')
{
printf(gameset.frame);//左邊框
for(i=0,j=0;*(menu+i)!='\n'&&*(menu+i)!='\0';i++,j++)//復(fù)制本行
{
if(*(menu+i)=='\t')//如果是制表符,輸出空格直到列數(shù)是6的倍數(shù)
{
for(;j%6!=5;j++)
output[j]=gameset.no[0];
j--;
}
else
output[j]=*(menu+i);//直接復(fù)制
}
menu=menu+i+1;//移動(dòng)指針到下一行
for(;j<gameset.xs*2-6;j++)//用空格填充本行的后面
output[j]=gameset.no[0];
output[j]='\0';//結(jié)束標(biāo)記
printf(gameset.no);//行首空格,讓界面更好看
printf(output);//輸出內(nèi)容
printf(gameset.frame);//右邊框
printf("\n");//換行
Sleep(100);//延時(shí),顯示漸漸出現(xiàn)的效果
}
for(i=0;i<gameset.xs;i++)
printf(gameset.frame);//輸出下邊框
printf("\n");
return;
}
void sets()
{
char word[1000];//要顯示的文字
while(1)
{//使用符號(hào)'\'告訴編譯器下一行應(yīng)該和本行連起來(lái)再編譯
sprintf(&word[0],"\
設(shè)置菜單\n\
請(qǐng)選擇你要更改的選項(xiàng):\n\
屏幕大小:\n\
\t1.寬度:%d\n\
\t2.高度:%d\n\
速度:\n\
\t3.方塊下落速度:%d\n\
顯示:\n\
\t4.方塊形狀:\"%s\"\n\
\t5.空白區(qū)域形狀:\"%s\"\n\
\t6.邊框形狀:\"%s\"\n\
7.返回\n\
",gameset.xs,gameset.ys,gameset.speed,gameset.sqr,gameset.no,gameset.frame);
showmenu(&word[0]);
char choice=getch();
showmenu("請(qǐng)輸入改變后的參數(shù):");//顯示提示
switch(choice)//分情況輸入
{
case '1':
scanf("%d",&gameset.xs);
if(gameset.xs<15||gameset.xs>70)
throw error_argument;
break;
case '2':
scanf("%d",&gameset.ys);
if(gameset.ys<15||gameset.ys>70)
throw error_argument;
break;
case '3':
scanf("%d",&gameset.speed);
if(gameset.speed<0)
throw error_argument;
break;
case '4':
cin.getline(&gameset.sqr[0],3);//scanf("%s",&gameset.sqr[0]);
cout<<endl;
//gameset.sqr[3]='\0';
break;
case '5':
cin.getline(&gameset.no[0],3);//scanf("%s",&gameset.no[0]);
cout<<endl;
//gameset.no[3]='\0';
break;
case '6':
cin.getline(&gameset.frame[0],3);//scanf("%s",&gameset.frame[0]);
cout<<endl;
//gameset.frame[3]='\0';
break;
case '7':
saveset();//保存設(shè)置并返回
return;
}
}
}
void highscores()
{
int i;
char word[1000]="排行榜\n排名\t姓名\t積分\n\0";//抬頭
for(i=0;i<10;i++)
{
sprintf(&word[0],"%s%d\t%s\t%d\n",&word[0],i+1,rating[i].name,rating[i].score);//追加名單
}
sprintf(&word[0],"%s請(qǐng)按任意鍵繼續(xù)···\n",&word[0]);//追加提示
showmenu(&word[0]);
getch();//等待按鍵
return;
}
void copyright()
{
showmenu("\
請(qǐng)使用a,s,d,w鍵,\n\
a,s,d分別為\n\
向左下右移動(dòng),\n\
w為旋轉(zhuǎn)\n\
\n\
移動(dòng)速度是越小越快\n\
\n\
請(qǐng)按任意鍵繼續(xù)···\n\
");
getch();
return;
}
void loadset()
{
ifstream fin;
fin.open("set.ini",ios::in|ios::nocreate);//輸入文件流
if(!fin)
throw set_no_found;
fin>>gameset.xs>>gameset.ys>>gameset.speed;
fin.getline(gameset.sqr,4);//獲取整行,因?yàn)榭赡苡锌崭?
fin.getline(gameset.no,4);
fin.getline(gameset.frame,4);
return;
}
void saveset()
{
ofstream fout;//輸出文件流
fout.open("set.ini",ifstream::out|ios::nocreate);
if(!fout)
throw set_no_found;
fout<<gameset.xs<<'\n'<<gameset.ys<<'\n'<<gameset.speed<<gameset.sqr<<'\n'<<gameset.no<<'\n'<<gameset.frame<<'\n';
return;
}
void loadhs()
{
int i;
ifstream fin;
fin.open("highscore.dat",ifstream::in|ios::nocreate);//打開文件,不存在則錯(cuò)誤
if(!fin)//如果錯(cuò)誤
throw dat_no_found;
for(i=0;i<10;i++)//讀取文件
fin>>rating[i].name>>rating[i].score;
return;
}
bool addscores(int score,char name[50])
{
int i,j;
for(i=0;i<10;i++)//枚舉
{
if(rating[i].score<score)//如果排行榜的積分比新積分小
{
for(j=9;j>i;j--)//移動(dòng)數(shù)據(jù)空出位置
{
for(int k=0;k<50;k++)
rating[j].name[k]=rating[j-1].name[k];
rating[j].score=rating[j-1].score;
}
rating[i].score=score;//插入數(shù)據(jù)
strcpy(rating[i].name,name);
return true;//返回進(jìn)入排行
}
}
return false;//返回沒(méi)有進(jìn)入
}
void savehs()
{
int i;
ofstream fout;
fout.open("highscore.dat",ifstream::out|ios::nocreate);
if(!fout)
throw dat_no_found;
for(i=0;i<10;i++)
fout<<rating[i].name<<'\n'<<rating[i].score<<'\n';
return;
}
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
C語(yǔ)言實(shí)現(xiàn)掃雷小游戲(擴(kuò)展版可選擇游戲難度)
游戲目標(biāo)是找出所有沒(méi)有地雷的方格,完成游戲;要是按了有地雷的方格,游戲失?。煌婕铱蓸?biāo)記雷的位置,游戲以完成時(shí)間來(lái)評(píng)高低,并且用戶可以選擇游戲難度2019-10-10
Opencv Hough算法實(shí)現(xiàn)圖片中直線檢測(cè)
這篇文章主要為大家詳細(xì)介紹了Opencv Hough算法實(shí)現(xiàn)圖片中直線檢測(cè),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-12-12
Qt圖片繪圖類之QPixmap/QImage/QPicture詳解
這篇文章主要為大家詳細(xì)介紹了Qt圖片繪圖類中QPixmap、QImage和QPicture的使用方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-03-03
C語(yǔ)言實(shí)現(xiàn)十六進(jìn)制轉(zhuǎn)換為十進(jìn)制的方法詳解
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)十六進(jìn)制轉(zhuǎn)換為十進(jìn)制的方法,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,需要的可以參考一下2022-11-11

