1. 程式人生 > 程式設計 >C++實現俄羅斯方塊

C++實現俄羅斯方塊

本文例項為大家分享了C++實現俄羅斯方塊的具體程式碼,供大家參考,具體內容如下

工具:vc++2010,相簿:EasyX

先看效果圖片

純手寫,沒有面向物件思想,看全部原始碼

#include <stdio.h>
#include <graphics.h>
#include <time.h>
#include <conio.h>

#define BLOCK_COUNT 5
#define BLOCK_WIDTH 5
#define BLOCK_HEIGHT 5
#define UNIT_SIZE 20
#define START_X  130

#define START_Y  30
#define KEY_UP  72
#define KEY_RIGHT 77
#define KEY_LEFT  75
#define KEY_SPACE 32
#define KEY_DOWN  76
typedef enum{
 BLOCK_UP,BLOCK_RIGHT,BLOCK_DOWN,BLOCK_LEFT
}block_dir_t;
typedef enum{
 MOVE_DOWN,MOVE_LEFT,MOVE_RIGHT

}move_dir_t;
int speed = 500;
int NextIndex = -1;//下一個方塊種類
int BlockIndex = -1;//當前方塊種類
int score = 0;//分數
int rank = 0;//等級
int visit[30][15];//訪問陣列
int markcolor[30][15];//表示顏色
int minX = 30;
int minY = 30;
int color[BLOCK_COUNT]={
 GREEN,CYAN,MAGENTA,BROWN,YELLOW
};
int block[BLOCK_COUNT*4][BLOCK_HEIGHT][BLOCK_WIDTH] = {
 //條形方塊
 {
 0,1,0},{
 0,//L形方塊
 {
 0,//田字型
 {
 0,//T字形方塊
 {
 0,//Z字形方塊
 {
 0,0}
};

//歡迎介面
void welcome(){
 //初始化畫布
 initgraph(550,660);

 //設定視窗標題
 HWND window = GetHWnd();//獲取視窗
 SetWindowText(window,_T("俄羅斯方塊 GWF"));//設定視窗標題


 //設定文字字型樣式
 setfont(0,30,_T("微軟雅黑"));
 setcolor(YELLOW);
 outtextxy(150,200,_T("俄羅斯方塊"));
 setfont(0,10,_T("微軟雅黑"));
 outtextxy(175,300,_T("IT程式設計從俄羅斯方塊開始"));
 Sleep(3000);
 
}
//初始化遊戲螢幕
void initGameScene(){
 char str[16];
 //清除螢幕
 cleardevice();

 rectangle(27,27,336,635);
 rectangle(29,29,334,633);
 rectangle(370,50,515,195);
 setfont(24,_T("楷體"));
 setcolor(LIGHTGRAY);
 outtextxy(405,215,_T("下一個"));
 setcolor(RED);
 outtextxy(405,280,_T("分數"));
 sprintf(str,"%d",score);
 outtextxy(415,310,str);
 outtextxy(405,375,_T("等級"));
 sprintf(str,rank);
 outtextxy(415,405,str);
 setcolor(LIGHTBLUE);
 outtextxy(390,475,"操作說明");
 outtextxy(390,500,"↑:旋轉");
 outtextxy(390,525,"↓:下降");
 outtextxy(390,550,"→:向右");
 outtextxy(390,575,"←:向左");
 outtextxy(390,600,"空格:暫停");



}
void drawBlock(int x,int y){//右上角畫出方塊
 setcolor(color[NextIndex]);
 setfont(23,"楷體");
 for(int i= 0;i<BLOCK_HEIGHT;i++){
 for(int j= 0;j<BLOCK_WIDTH;j++){
 if(block[NextIndex*4][i][j] == 1){
 outtextxy(x+UNIT_SIZE*j,y+UNIT_SIZE*i,"■");
 }
  }
 }
}
void drawBlock(int x,int y,int blockIndex,block_dir_t dir){//按索引畫出什麼方塊指定位置方塊指定方向
 setcolor(color[blockIndex]);
 setfont(23,"楷體");
 int id = blockIndex*4+dir;
 for(int i= 0;i<BLOCK_HEIGHT;i++){
 for(int j= 0;j<BLOCK_WIDTH;j++){
 if(block[id][i][j] == 1){
 outtextxy(x+UNIT_SIZE*j,"■");
 }
  }
 }
}

void clearBlock(int x,int y){
 setcolor(BLACK);
 setfont(23,"楷體");
 for(int i= 0;i<BLOCK_HEIGHT;i++){
 for(int j= 0;j<BLOCK_WIDTH;j++){
 outtextxy(x+UNIT_SIZE*j,"■");
  }
 }
}
void clearBlock(int x,block_dir_t dir){
 setcolor(BLACK);
 int id = BlockIndex *4+dir;
 y+=START_Y;
 for(int i= 0;i<BLOCK_HEIGHT;i++){
 for(int j= 0;j<BLOCK_WIDTH;j++){
 if(block[id][i][j] == 1){
 outtextxy(x+UNIT_SIZE*j,"■");
 }
  }
 }
}
void nextblock(){
 clearBlock(391,71);//清除右上角方塊
 //隨機選擇一種方塊
 srand(time(NULL));//時間函式的返回值產生隨機數種子
 NextIndex = rand()%BLOCK_COUNT;
 drawBlock(391,71);//畫出方塊

}
//如果在指定位置可以向方向移動
int moveable(int x0,int y0,move_dir_t moveDir,block_dir_t blockDir){
 int x = (y0 - minY)/UNIT_SIZE;
 int y = (x0 - minX)/UNIT_SIZE;
 int id = BlockIndex * 4+blockDir;
 int ret = 1;
 if(moveDir == MOVE_DOWN){
 for(int i = 0;i<5;i++){
 for(int j = 0;j<5;j++){
 if(block[id][i][j] == 1 &&(x+i+1>=30 || visit[x+i+1][y+j]==1)){
  ret=0;
 }
 }
 }
 }else if(moveDir == MOVE_LEFT){
 for(int i = 0;i<5;i++){
 for(int j = 0;j<5;j++){
 if(block[id][i][j] == 1 &&(y+j==0 || visit[x+i][y+j-1]==1)){
  ret=0;
 }
 }
 }
 }else if(moveDir == MOVE_RIGHT){
 for(int i = 0;i<5;i++){
 for(int j = 0;j<5;j++){
 if(block[id][i][j] == 1 &&(y+j+1>=15 || visit[x+i][y+j+1]==1)){
  ret=0;
 }
 }
 }
 }
 return ret;
}
void failCheck(){//遊戲是否結束
 if(!moveable(START_X,START_Y,MOVE_DOWN,BLOCK_UP)){
 setcolor(WHITE);
 setfont(45,"隸體");
 outtextxy(75,"GAME OVER!");
 Sleep(1000);
 system("pause");
 closegraph();
 exit(0);
 }
}
int wait(int interval){//等待
 int count = interval/5;
 for(int i = 0;i<count;i++){
 Sleep(5);
 if(kbhit()){
 return 0;
 }
 }
}//判斷當前方向是否可以轉到指定方向
int rotatable(int x,block_dir_t dir){
 int id= BlockIndex * 4 +dir;
 int xIndex = (y-minY)/20;
 int yIndex = (x-minX)/20;

 if(!moveable(x,y,dir)){
 return 0 ;
 }
 for(int i = 0;i<5;i++){
 for(int j = 0;j<5;j++){
 if(block[id][i][j] ==1&&(yIndex+j<0||yIndex+j>=15||visit[xIndex+i][yIndex+j] ==1)){
 return 0 ;
 }
 }
 }
 return 1;
}
void mark(int x,block_dir_t dir){
 int id = blockIndex*4+dir;
 int x2 = (y-minY)/20;
 int y2 = (x-minX)/20;
 for(int i=0;i<5;i++){
 for(int j=0;j<5;j++){
 if(block[id][i][j] ==1){
 visit[x2+i][y2+j]=1;
 markcolor[x2+i][y2+j]=color[blockIndex];
 }
 }
 }
}
void clear_down(int x){//消除第x行,並把上面的行都下移
 for(int i = x;i>0;i--){
 for(int j=0;j<15;j++){
 if(visit[i-1][j]){//上面有東西
 visit[i][j]=1;
 markcolor[i][j]=markcolor[i-1][j];
 setcolor(markcolor[i][j]); 
 outtextxy(20*j+minX,20*i+minY,"■");
 }else{
 visit[i][j] =0;
 setcolor(BLACK);
 outtextxy(20*j+minX,"■");
 }
 }
 }
 //清除最頂層那一行,就是行標位0的哪一行
 setcolor(BLACK);
 for(int j = 0;j<15;j++){
 visit[0][j] = 0;
 outtextxy(20*j+minX,minY,"■");
 }
}
void updataGrade(){
//更新等級提示
//假設:50分一級
 char str[10];
 rank = score/50;
 sprintf(str,rank);
 outtextxy(425,str);
 //更新速度,等級越高速度越快,speed越小
 //最慢是500,最快是50
 speed = 500-rank*50;
 if(speed<=0){
 speed = 50;
 }
}
void addScore(int lines){//更新分數,line表示消除的行數
 char str[32];
 setcolor(RED);
 score+=lines*10;
 sprintf(str,str);
}
void check(){//消去方塊
 int i,j;
 int clearLines =0;
 for(i=29;i>=0;i--){
 for(j=0;j<15 && visit[i][j];j++);
 //執行到此處有兩種情況,//1.第I行沒有滿,即表示有空位,此時j<15
 //2.第i行已經滿了,j就大於等於15
 if(j>=15){
 //此時第i行已經滿了,就需要消除第i行
 clear_down(i);//清除第i行,並把上面的行都下移動
 i++;
 clearLines++;
 }
 }
 //更新分數
 addScore(clearLines);
 //更新等級
 updataGrade();
}
void move(){
 int x = START_X;
 int y = START_Y;
 int k = 0;
 int curSpeed = speed;
 block_dir_t blockDir = BLOCK_UP;

 //檢查遊戲是否結束
 failCheck();
 while(1){
 if(kbhit()){
 int key = getch();
 if(KEY_SPACE == key){
 getch();
 }
 }
 //清除當前方塊
 clearBlock(x,k,blockDir);
 if(kbhit()){
 int key = getch();
 
 if(KEY_UP == key){//變形
 block_dir_t nextDir = (block_dir_t)((blockDir+1)%4);
 if(rotatable(x,y+k,nextDir)){
  blockDir= nextDir;
 }
 }else if(KEY_DOWN == key){//鄉下加速
 curSpeed = 50;
 }else if(KEY_RIGHT == key){//右移動
 if(moveable(x,y+k+20,MOVE_RIGHT,blockDir)){
  x+=20;
 }
 }else if(KEY_LEFT == key){//左移動
 if(moveable(x,blockDir)){
  x-=20; 
 }
 }
 }
 k+=20;
 //繪製當前方塊
 drawBlock(x,BlockIndex,blockDir);
 wait(curSpeed);
 
 //方塊降落到底層的固化處理
 if(!moveable(x,blockDir)){
 mark(x,blockDir);
 break;
 }
 }
}
void newblock(){
 //確定即將使用的方塊
 BlockIndex = NextIndex;
 //繪製方塊從頂部掉下來
 drawBlock(START_X,START_Y);
 //新出現的方塊等一下
 Sleep(100);
 //右上角繪製下一個方塊
 nextblock();
 //向下降落的動作
 move();
}

int main (void){
 welcome(); 
 initGameScene();
 //產生新方塊 
 nextblock();
 Sleep(500);
 memset(visit,sizeof(visit));
 while(1){
 newblock();
 //消除滿行,並更新分數和速度
 check();
 }
 
 system("pause");
 closegraph();
 
 return 0;
}

分析專案:

1.必須要有歡迎介面
2.搭建合理的邊界,就是遊戲範圍
3.邏輯1:先出現右上方的方塊樣式,等待一段時間,將右上方的樣式在遊戲區打印出
4.邏輯2,方塊降落,要擦除原先印記,將1改為0
5.邏輯3,熱鍵控制移動方向,暫停及變形,且不能移動出界,判斷方塊是否還能移動
6.邏輯4,方塊凝固在下方不出界
7.邏輯5,最下面一行方塊疊滿了,消去它並把上面的行都下移(分兩種情況),並且再次檢查這一行
8.邏輯6,計算消除行數次數,統計分數,控制休眠時間長度
9.邏輯7,每次移動先判斷是否能移動,預設結束程式,在合理遊戲區返回false,結束介面

總結:從介面開始到完整的架構,功能後實現,一步一步,邏輯嚴謹,思路清晰,註釋在程式碼裡。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。