2.俄罗斯方块(循环,分支)

又开了一个分组,里面才一篇写数独游戏的文章,怪空的。再写一个吧。

写什么好呢,我想起大一写的第一个游戏:俄罗斯方块。

都是条件分支和循环,没有什么算法知识,比较适合再水一篇

一、俄罗斯方块的初始化

1、头文件包:

#include <windows.h>
#include <ctime>
#include <conio.h>
#include <cstdio>
#include <math.h>

2、俄罗斯方块的坐标和颜色控制:

当初的一大难点(哭),不知道有没有人和我一样

上网查了一下也是看得云里雾里的,不知道如何操作。

感谢一位叫张祺的大佬提供的源代码,才让我明白如何控制坐标和颜色,

下面两个函数都是人家的:

void gotoxy(int x, int y){
    COORD pos;//表示一个字符在控制台屏幕上的坐标
    pos.X = x;
    pos.Y = y;
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);//是API中定位光标位置的函数。
}//光标控制模块

void color(int b){
    HANDLE hConsole = GetStdHandle((STD_OUTPUT_HANDLE)) ;
    SetConsoleTextAttribute(hConsole, b) ;//颜色控制
}//颜色控制模块 

3、俄罗斯方块结构体:

还是张祺大哥的方法,用结构体存放俄罗斯方块的横纵坐标,然后将7大类19小类的俄罗斯方块的相对坐标存入其中

("I Shape"两种,"J Shape"

注意的是横纵坐标长度是不一样的

如俄罗斯方块 "O shape "坐标可以用二维数组表示为 {{0,0,2,2},{1,0,1,0}}, 前一个一维数组是x坐标,后一个是y坐标

二、俄罗斯方块的运行与判断:

1、运行:

设置一个 while(俄罗斯方块能运行==true) 的结构体,每循环一次,检测键盘一次,移动方块一次

(1)方块的移动:显示方块→暂停→清除方块→按操作改变方块坐标→再次显示。。。

当方块停止移动时,不必清除方块

△新建两个参数X,Y,表示对俄罗斯方块横纵坐标的修正,

俄罗斯方块初始化坐标+修正=俄罗斯方块新坐标

(2)方块下落:没有检测到键盘输入,方块下面没有阻挡,直接++Y即可

(3)方块旋转(kbhit检测到“↑”且有地方旋转):删除方块→修改到指定的类→显示修改类过后的方块

比如 T Shape大类按顺时针方向有四种旋转状态(四种小类),被记为类10,类11,类12,类13,

如果当前状态为类12,检测到“↑”时则把类12修改为类13;再检测到“↑”,把类13修改为类10。。。

(4)方块左右移(检测到“←”或“→”,且移动方向没有障碍):X+=2(x与y的长度是不同的),同时停止++Y。

为了做出加速的效果,我缩短了方块移动的暂停时间

(5)方块向下加速(检测到“↓”且方块下面没有障碍):缩短方块移动的暂停时间即可

2、方块的障碍判断

先设置一个二维数组a,数组编号与俄罗斯方块游戏界面的每一个方格坐标一一对应

比如坐标(6,8)对应a[4][5],坐标(8,8)对应a[4][6]

当俄罗斯方块停止运行时,将对应数组上的数字记为1。

循环读取俄罗斯方块四个方格坐标,单个方格坐标记为(x,y),对应数组a[m][n]

(1)、下方障碍判断:

四个方格其中一个满足a[m+1][n]=1,表示该方块下面有障碍,俄罗斯方块停止移动

ps:当无法向下移动,但是还能往左右移动时,怎么办?

当俄罗斯方块无法向下移动时,不用急于设置俄罗斯方块能运行=false。

首先禁止Y++,然后设置一个计时器,比如设置3,表示再循环三次while语句

如果没有检测到键盘输入,计时-1,;当计时为0时,设置俄罗斯方块能运行=false

(2)、左右判断

四个方格其中一个满足a[m][n-1]=1或超出左边界,锁死左移动,即使检测到"←"也不能往左移

右判断同理

(3)、当俄罗斯方块不再运行时,设置其四个方块坐标对应的数组值为1

3、俄罗斯方块的结算:

当一个方块不再运行,我们要做一些结算,才能继续产生下一个方块

(1)、行满判断:检测数组,如果a旗下某些一维数组中的元素全为1,表示这些一维数组对应的行满了,进一步进行结算;

没有,则生成下一个俄罗斯方块

(2)、进一步结算:行满清除等:

至行满的行开始交换数据。比如第Y行满了,对应数组M,

a[M][n]=a[M-1][n],a[M][n-1]=a[M-1][n-1] 。。。a[M-1][0]=a[M-1][0]

a[M-1][n]=a[M-2][n],a[M-1][n-1]=a[M-2][n-1] 。。。a[M-1][0]=a[M-2][0]

a[1][n]=a[0][n],a[1][n-1]=a[0][n-1] 。。。 a[1][0]=a[0][0]

将上面这些数组对应的方格都清掉,再重新检查上面这些数组

如果a[m][n]=1,则在对应坐标显示方格,反之不显示

ps:如果给方格设置颜色,可以将数组a改为三维数组

a[m][n][0]存储0和1,表示有没有方格,a[m][n][1]存储方格颜色

三、代码

#include <windows.h>
#include <ctime>
#include <conio.h>
#include <cstdio>
#include <math.h>

#define Speed 500 //下落速度 
#define buffer 2 //触底缓冲 

int board[30][30][2];
int sort[7]={0,1,3,5,7,11,15};//俄罗斯方块分为7大类19小类 
int mark=0;
int amend_x=10,amend_y=4,speed=Speed;
time_t seed;
int kind=0,next_kind;
int key;//水平锁 
int win=1;
	
struct before{
	int x[4];
	int y[4];
}before; 

struct now{
	int x[4];
	int y[4];
	int color;
}now[19]={                       //□□
	{{0,2,0,2},{-1,-1,-2,-2},10},//□□系列 num:0

    {{0,6,4,2},{-1,-1,-1,-1},11},{{2,2,2,2},{-1,-2,-3,-4},11},//□□□□系列 num:1-2 

	                                                          //□□
	{{0,4,2,2},{-2,-1,-1,-2},12},{{0,2,0,2},{-1,-2,-2,-3},12},//  □□系列 num:3-4;
                                                
	                                                          //  □□
	{{0,4,2,2},{-1,-2,-1,-2},13},{{0,2,2,0},{-2,-1,-2,-3},13},//□□  系列 num:5-6;
	                                                                                                                    //  □
	{{0,4,2,2},{-1,-1,-1,-2},14},{{0,2,0,0},{-1,-2,-2,-3},14},{{0,4,2,2},{-2,-2,-1,-2},14},{{0,2,2,2},{-2,-1,-2,-3},14},//□□□系列 num:7-10

                                                                                                                    //□
	{{0,4,2,0},{-1,-1,-1,-2},9},{{0,2,0,0},{-1,-3,-2,-3},9},{{0,4,2,4},{-2,-1,-2,-2},9},{{0,2,2,2},{-1,-1,-2,-3},9},//□□□系列 num:11-14
                                                                                             
	                                                                                                                //    □
	{{0,4,2,4},{-1,-1,-1,-2},5},{{0,2,0,0},{-1,-1,-2,-3},5},{{0,4,2,0},{-1,-2,-2,-2},5},{{0,2,2,2},{-3,-1,-2,-3},5},//□□□系列 num:15-18
 };//方块形态结构体;
 
void gotoxy(int x, int y){
    COORD pos;//表示一个字符在控制台屏幕上的坐标
    pos.X = x;
    pos.Y = y;
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);//是API中定位光标位置的函数。
    HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
	CONSOLE_CURSOR_INFO cci;
	GetConsoleCursorInfo(hOut,&cci);//获取光标信息
	cci.bVisible = FALSE;//隐藏光标
	SetConsoleCursorInfo(hOut,&cci);//设置光标信息
}//光标控制模块

void color(int b){
    HANDLE hConsole = GetStdHandle((STD_OUTPUT_HANDLE)) ;
    SetConsoleTextAttribute(hConsole, b) ;//颜色控制
}//颜色控制模块 

void boundary(){
	color(7);
    int i=0,j=0;
    gotoxy(2,1);
    for(i=0;i<26;i++){
        printf("□");
	}
    gotoxy(2,27);
    for(i=0;i<26;i++){
        printf("□");
	}
    for(i=0;i<25;i++){
        gotoxy(2,2+i);
        printf("□");
        gotoxy(34,2+i);
        if(i==7||i==13){
			printf("□□□□□□□□□");
		}else{
            printf("□");
		}
        gotoxy(52,2+i);
		printf("□");
	}
    int t=100;
    color(7);
    gotoxy(37,11);
    printf("最高分数:%d",t);
    color(7);
    gotoxy(37,13);
    printf("当前得分:%d",mark);
    gotoxy(37,17);
    printf("↑:旋转");
    gotoxy(37,19);
    printf("↓:加速");
    gotoxy(37,21);
    printf("←:左移 ");
    gotoxy(37,23);
    printf("→:右移");
    gotoxy(37,25);
    printf("空格:停止");
    color(12);  
    gotoxy(23,29);
	printf("俄罗斯方块"); 
	gotoxy(14,31);
	printf("哈蒙森软件工业公司 于1898年出品");
	color(7);
    for(int i=0;i<30;++i){
    	board[26][i][0]=1;
	}
}//界面生成模块

void next(){
	srand(time(&seed));
	next_kind=sort[rand()%7];
	gotoxy(37,3);
	printf("下一个");
	color(now[next_kind].color);
	for(int i=0;i<4;++i){
		gotoxy(now[kind].x[i]+37,now[kind].y[i]+7);
		printf("  ");
	}
	for(int i=0;i<4;++i){
		gotoxy(now[next_kind].x[i]+37,now[next_kind].y[i]+7);
		printf("■");
	}
	color(7);
}

void left_and_rigth(int dir){
	if(now[kind].x[0]+amend_x>=6 && now[kind].x[1]+amend_x<=30){
		if(dir==3){
			for(int i=0;i<4;++i){
				int x=now[kind].x[i]+amend_x;
				int y=now[kind].y[i]+amend_y;
				if(board[y-1][x/2-3][0]==1){
					key=0;
				}
			}
		}
		if(dir==4 || dir==1){
			for(int i=0;i<4;++i){
				int x=now[kind].x[i]+amend_x;
				int y=now[kind].y[i]+amend_y;
				if(board[y-1][x/2-1][0]==1){
					key=0;
				}
			}
		}
	}
	if(now[kind].x[0]+amend_x<6 && dir==3){
		key=0;
	}
	if(now[kind].x[1]+amend_x>30 && (dir==4 || dir==1)){
		key=0;
	}
}//左右障碍判断 

void game_over(){
    for(int i=25;i>=0;i--)
	{			 
        for(int j=0;j<15;j++){	 
			color(7);
            gotoxy(32-j*2,2+i);
            printf("□");
            Sleep(10);
            board[i][j][0]=0;
        }
	}
    for(int j=0;j<25;j++)
	{
        for(int i=0;i<15;i++)
        {
             gotoxy(4+2*i,j+2);
             printf("  ");
             Sleep(10);
         }
	 }
	gotoxy(37,13);
    printf("当前得分:%d  ",mark);
	mark=0;
}//界面清除模块 

int input(){
	int ch1=0;
    int ch2=0;
	if (ch1=getch()){
		ch2=getch();//第一次调用getch(),返回值224
		if(kbhit()){
			ch2=getch();
		}
		switch (ch2)//第二次调用getch()
		{
		//↑↓←→键
		case 72: return 1;  
		case 80: return 2; 
		case 75: return 3;
		case 77: return 4;
		}
	}
}

void move(int fall){
	for(int i=0;i<2;++i){
		for(int j=0;j<4;++j){
			int x=now[kind].x[j]+amend_x;
			int y=now[kind].y[j]+amend_y;
			if(i==0 && y>1){
				gotoxy(x,y);
				color(now[kind].color);
				printf("■");
				gotoxy(x,y+1);
			}
			if(i==1 && fall==1 && y>1){
				gotoxy(x,y);
				printf("  ");
			}
		}
		color(7); 
		Sleep(speed*(1-i));
	}	
	gotoxy(37,13);
	printf("当前得分:%d  ",mark);
}//方块的移动 

bool fall_or_not(){
	for(int i=0;i<4;++i){
		int x=now[kind].x[i]+amend_x;
		int y=now[kind].y[i]+amend_y;
		if(board[y-1][x/2-2][0]==1){
			return false;
		}
	}
	return true;
	
}//垂直障碍模块 

void rotate(){
	if(kind>0 && kind<3){
		kind==1?kind=2:kind=1;
	}
	if(kind>2 && kind<5){
		kind==3?kind=4:kind=3;
	}
	if(kind>4 && kind<7){
		kind==5?kind=6:kind=5;
	}
	if(kind>6 && kind<11){
		kind==10?kind=7:kind++;
	}
	if(kind>10 && kind<15){
		kind==14?kind=11:kind++; 
	}
	if(kind>14){
		kind==18?kind=15:kind++;
	}
}//方块旋转模块 

void line_clear(int n){
	 for(n;n>1;--n){
		 for(int i=0;i<15;++i){
			 gotoxy(4+2*i,n+1);
			 color(0);
			 printf("  ");
			 board[n][i][0]=board[n-1][i][0];
			 board[n][i][1]=board[n-1][i][1];
			 if(board[n][i][0]==1){
				 gotoxy(4+2*i,n+1);
				 color(board[n][i][1]);
				 printf("■");
			 }
		 }
	 }
}//行满清除 

void full_or_not(){
	int line=0;
	for(int i=1;i<26;++i){
		int k=0;
		for(int j=0;j<15;++j){
			if(board[i][j][0]==1){
				++k;
			}
		}
		if(k==15){
			++line;
			line_clear(i); 
		}
	}
	
	if(line>0){
		mark+=pow(3,line-1);
		color(7);
		for(int i=0;i<line*2;++i){
			gotoxy(10,3);
			i%2==0?color(7):color(12);
			if(line==1){
				printf("为不列颠人欢呼!");
			}
			if(line==2){
				printf("维多利亚女王万岁!");
			}
			if(line==3){
				printf("为黄金时代干杯!");
			}
			if(line==4){
				printf("上帝保佑大英帝国!");
			}
			Sleep(100);
			if(i%2==1){
				Sleep(2000);
			}
			
		}
		gotoxy(10,3);
		printf("                        ");
		color(7);
	}

}//判断行满 

void game(){
	int fall=1,dir,time=buffer,stop=0;
	amend_x=10,amend_y=3;
	if(kind==1){
		--amend_y;
	} 
	while(fall==1){
		dir=5;
		key=1;
		if(kbhit()){
			dir=input();
			left_and_rigth(dir);
			gotoxy(2,0);
			if(dir==1 && key==1 && amend_y>4 && stop==0){
				rotate();
				time=2;
			}
			if(dir==2){
				speed=30;
			}
			if(dir==3 && key==1){
				amend_x-=2;
				if(stop==0){
					--amend_y;
				}
				speed=30;
				time=2;
			}
			if(dir==4 && key==1){
				amend_x+=2;
				if(stop==0){
					--amend_y;
				}
				speed=30;
				time=2;
			}
		} 
		++amend_y;
		if(fall_or_not()==false){
			stop=1;
			for(int i=0;i<4;++i){
				if(now[kind].y[i]+amend_y<4){
					win=0;
				}
			}
		}
		if(fall_or_not()==true){
			stop=0;
			time=buffer;
		}
		if(stop==1 && time>0){
			--time;
			--amend_y;
		}
		if(time==0){
			fall=0; 
		}
		move(fall);
		speed=Speed;
		gotoxy(10,0);
	}
	for(int i=0;i<4;++i){
		int x=now[kind].x[i]+amend_x;
		int y=now[kind].y[i]+amend_y;
		board[y-1][x/2-2][0]=1;
		board[y-1][x/2-2][1]=now[kind].color;
	}
	full_or_not();

}//控制一个俄罗斯方块的运行 

int main(){
	srand(time(&seed));
	kind=sort[rand()%7];
	boundary();
	int again=1;
	while(again==1){
		while(win==1){
			next();
			game();
			kind=next_kind;
		}
		game_over();
		boundary();
		gotoxy(5,15);
		printf("Enter 1 begin next game:");
		scanf("%d",&again);
		gotoxy(5,15);
		printf("                           ");
		win=1;
	}

	gotoxy(0,40);
	return 0;
}

 

猜你喜欢

转载自blog.csdn.net/qq_40636117/article/details/82463965
今日推荐