테트리스 개발 6일차

나묘쿠·2022년 1월 18일
0

테트리스

목록 보기
6/8
post-thumbnail

저번 글을 올리고 그냥 개발을 계속하였다. 그래서 글을 쓰고 있는 지금 두 시간 밖에 자지 못하여 꽤나 비몽사몽한 상태다. 5일차 글을 쓰고 난 뒤에 바로 줄이 완성될 시 사라지는 것과 줄의 맨 위에 닿을 시 게임오버되는 코드를 구현하였다. 그리고 시작화면을 간단하게 만드는 등 UI도 조금 손 보았다. 그리고 전체적인 변수도 적당히 손 보았다.

첫째로 줄이 완성되어 한 줄 씩 땡겨 게임화면의 데이터를 gameblock에 저장할 때 색깔을 유지하려면 단순히 0과 1이 아닌 그 블록을 나타낼 수 있는 값을 저장하여 특정 블록의 값일 때 그 블록의 색깔을 출력할 수 있게 만들었다.

currentblock 이라는 전역변수를 선언해주고

main함수의 텍스트 색깔 설정 구문 바로 위에 currentblock=setcolor(acblock);이라 해준다.
그리고 그 밑의 텍스트 색 설정 구문의 색상코드부분을 currentblock으로 고쳐준다.

블록을 고정시키는 setgameblock()안에서도

gameblock[yset()+i][(x-10)/2+j]=1;

gameblock[yset()+i][(x-10)/2+j]=currentblock;
로 고쳐준다.

그 다음엔 화면을 갱신해주는 함수이다.

void printgameblock(void)		//게임화면 갱신 
{
	int i, j;
	
	for(i=4; i<24; i++)
	{
		gotoxy(12, 7+i);
		for(j=1; j<11; j++)
		{
			if(gameblock[i][j]==0)
				printf("  ");
			
			else if(gameblock[i][j]==11)		//I
			{
				SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), gameblock[i][j]);
				printf("▣");
			}
			
			else if(gameblock[i][j]==13)		//T
			{
				SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), gameblock[i][j]);
				printf("▣");
			}
			
			else if(gameblock[i][j]==14)		//O
			{
				SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), gameblock[i][j]);
				printf("▣");
			}
			
			else if(gameblock[i][j]==4)		//L
			{
				SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), gameblock[i][j]);
				printf("▣");
			}
			
			else if(gameblock[i][j]==9)		//J
			{
				SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), gameblock[i][j]);
				printf("▣");
			}
			
			else if(gameblock[i][j]==10)		//S
			{
				SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), gameblock[i][j]);
				printf("▣");
			}
			
			else if(gameblock[i][j]==12)		//Z
			{
				SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), gameblock[i][j]);
				printf("▣");
			}
		}
	}
}

줄이 완성되어 당겨졌을 때 색상을 유지하면서 줄도 당기게 하였다.

이렇게 말이다.

void finishedgameblock(int a)		//줄이 완성되었을 때 
{
	int i, j;
	
	for(i=a; i>0; i--)
	{
		for(j=1; j<11; j++)
			gameblock[i][j]=gameblock[i-1][j];		//완성된 줄의 윗줄부터 하나씩 아랫줄로 이동 
	}
}

줄을 당기는 함수는 이렇게 만들었고, 줄이 완성되었는지 체크하는 함수는

void scangameblock(void)		//완성된 줄이 있는지 검사 
{
	int i, j;
	
	for(i=23; i>3; i--)		
	{
		for(j=1; j<11; j++)
		{
			if(gameblock[i][j]==0)		//완성이 되지 않은 부분이 있다면 다음 줄로 
				break; 
		}
		
		if(j==11)		//완성이 되었다면 한 줄씩 땡기기 
			finishedgameblock(i++);
	}
	printgameblock();		//게임화면 갱신 
	return; 
}

이렇게 만들었다.
그리고 이 함수는 main함수에서 setgameblock()바로 밑에 선언해주었다.

두번째로, 지금까지 만든 게임화면을 나타낸 변수는 y좌표의 길이가 21인데 이는 너무 짧다. 블록 하나가 더 들어갈 수 있게 25로 바꿔주었다. 그리고 블록이 시작되는 좌표도 6으로 바꿔주었다. 그래서 모든 y좌표를 사용하는 블록이 오류가 나길래 (y-10)부분도 따로 계산하는 함수를 만들었다. y좌표가 10보다 작으면 음수가 반환되어 오류가 나더라.

int yset(void)
{
	if(y>=7)
		return y-7;
	
	else
		return 0;
}

로 바꿔주고 모든 y-10부분에 yset()를 넣어주었다. 그리고 moveac에서 y좌표를 6으로 바꿔주어 블록이 y좌표 6에서부터 출력되게 하였다. 글의 순서가 조금 이상하긴 한데 버그를 고쳐가면서 여기로 갔다 저기로 갔다 하면서 완성한 코드라 그렇다. 어쨌든 좌표체계가 완성되었으니 게임오버를 체크하는 함수를 만들 것이다.

int scangameover(void)		//게임오버됐는지 체크 
{
	int i=0; 
	
	for(i=1; i<11; i++)
	{
		if(gameblock[3][i]!=0) //오버됐을시 1 반환
			return 1;
	}
}

이렇게 만들어주고

if(scangameover()==1)
break;
를 main함수 안의 scangameblock();밑에 선언해준다
그 다음 while문 밖에

system("cls");		//화면 초기화 
	gotoxy(20, 20);
	SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 7);
	printf("game over");
	Sleep(5000);

를 선언해준다.

위에서 블록이 y좌표 6에서부터 내려오기 시작함으로써 게임 화면에서 한참 벗어나게 된다. 그래서 이를 가려주는 함수를 만들었다.

void topgameline(void)		//상단 가림막 
{
	int i, j;
	SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 7);		//텍스트 색 흰색으로 지정 
	
	for(i=0; i<5; i++)
	{
		gotoxy(10, 6+i);
		
		for(j=0; j<12; j++)
		{
			printf("◈");
		}
	}
	SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), currentblock);		//텍스트 색 다시 원래 블록 색으로 지정 
	return;
}

이렇게 만들어주고 moveac()안의 for문 제일 첫 줄에 선언해주었다.
그럼 게임의 상단에
이렇게 나타나게 된다.

그리고 나서 대기중인 블록을 미리 보여주는 UI를 개선하자면

void blockprintwall(void)
{
	int i, j;
	
	SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), 7);
	
	gotoxy(38, 6);
	printf("◈N E  X T◈");
		
	for(i=0; i<5; i++)
	{
		gotoxy(38, 11+i*5);
		
		for(j=0; j<6; j++)
		{
			printf("◈");
		}
	}
	
	for(i=0; i<26; i++)
	{	
		gotoxy(38, 6+i);
		printf("◈");
		gotoxy(48, 6+i);
		printf("◈");
	}
}

void blockprint(void)		//대기중인 블록 출력 
{
	x=40;
	y=7;	
	SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), setcolor(blocksetprint[0]));	
	printsq(blocksetprint[0]);		//첫번째 대기 
	
	y=12;
	SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), setcolor(blocksetprint[1]));
	printsq(blocksetprint[1]);
	
	y=17;
	SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), setcolor(blocksetprint[2]));
	printsq(blocksetprint[2]);
	
	y=22;
	SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), setcolor(blocksetprint[3]));
	printsq(blocksetprint[3]);
	
	y=27;
	SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), setcolor(blocksetprint[4]));
	printsq(blocksetprint[4]);		//다섯번째 대기 
}

void rvblockprint(void)		//대기중인 잔상 제거 
{
	x=40;
	y=7;
	rvprintsq(blocksetprint[0]);		//첫번째 대기 
	
	y=12;
	rvprintsq(blocksetprint[1]);
	
	y=17;
	rvprintsq(blocksetprint[2]);
	
	y=22;
	rvprintsq(blocksetprint[3]);
	
	y=27;
	rvprintsq(blocksetprint[4]);		//다섯번째 대기 
}

이렇게 작성해준다음 acblock()의 안에서 잔상 제거 후 바로 printblockwall()을 선언해주면

이런 모양이 된다.

그리고 그 다음엔 간단한 게임 스타트 화면을 만들어 줄 것이다. 이것은 내가 예전에 사용한 코드를 붙여넣기 한 것이다.

void start(void)		//스타트 화면 
{
	srand(time(NULL));		//시간에서 시드값 끌어오기
	system("mode con cols=160 lines=40");		//콘솔창 크기 지정 
	cursorview();		//커서 숨기기 
	system("title Tetris by namaek");		//타이틀 명 변경 

	int i = 0;
	
	system ("cls");		//화면 초기화 
	gotoxy(18, 20);
	printf("Tetris by namaek");	
	
	gotoxy(18, 25);
	printf("Press any key to start");
	gotoxy(3, 35);
	printf("made by namaek");
	
	getch();
	
	for(i = 0; i<5; i++)		//키보드 입력시 반짝거림 
	{
		gotoxy(18, 25);
		printf("                      ");
		Sleep(100);
		gotoxy(18, 25);
		printf("Press any key to start");
		Sleep(100);
	}
	system ("cls");		//화면 초기화 
}

이렇게 하고 main 함수 첫 줄에 넣어주면

이런 스타트 화면이 뜬다.
아무 키나 누르면 반짝거린다.

이렇게 테트리스를 대강 완성하였다. 시간이 남으면 음악과 효과음을 넣는 작업을 할것 같다. 시간도 오래 걸리고 힘들었지만 그만큼 실력도 많이 늘고 이렇게 블로그에 개발일지도 쓰는 것이 재밌었다. 무엇보다 이렇게 완성도를 높이려 고민하고 해결하는 것이 즐겁다. 앞으로도 이것저것 해봐야지

profile
사고의 흐름을 따라가 보자.

0개의 댓글