U E D R , A S I H C RSS

데블스캠프2005/게임만들기/제작과정예제

데블스캠프2005/게임만들기/제작과정예제


화면에 블럭 출력하기


화면에 블럭을 출력해보자.
start()안에보면, 다양한 색상들 적혀있는color라는 름의 변수가 보일 것다.
그앞의 주석 가르키는데로, 1~10까지의 색상을 지정할 수 있다.
그밑에 보는 block변수가 블럭을 기억하게 된다.
~cpp 
block[0][0]=1;
라고 적고 실행해보자. 아래와 같은 결과가 나올것다.

test01.jpg

~cpp 
block[x좌표][y좌표]=블럭의 종류;
와 같은 형식으로 출력할 블럭을 지정하며, 0은 블럭 없는 것고 그 외의 값은 해당하는 색상의 블록 들어가게 된다.
block_next변수는, 메인창 옆의 next아래에 블럭을 출력하며 가로3세로4의 크기를 출력할 수 있다.
지정형식은 위와 동일하다.
~cpp 
block_next[x좌표][y좌표]=블럭의 종류;


할일 정하기

보다 쉽게 일을 진행하기 위해서 할일을 정해두어야 할 필요가 있다.
테트리스를 떠올려보고, 어떤 과정을 거쳐서만들지 생각해보자.

실습예제
~cpp 
1.출력할 블럭의 모양을 결정한다.
2.랜덤으로 블럭을 생성한 후 next창에 출력한다.
3.next창에 출력된 블럭을 가져온뒤 메인창에 출력한다.
4.블럭을 움직인다.
5.블럭을 회전시킨다.
6.한줄 다 찼을때, 블럭을 삭제한다.
7.점수와 스테지를 변화시킨다.

위의 예제 순서를 따라 진행하면 테트리스를 만들 수 있다.
하지만, 막히는 부분 생기게 되면 아래를 참조하길 바란다.


출력할 블럭의 모양 정하기


모양을 정하는 방법에는 여러가지가 있다.
n칸 띄우고, n칸만큼 블럭을 채우는 식으로,
예를 들어 T는(0,3)(1,1)(1,1)렇게 표시할 수 있다. 방향에 따라, 가로가 아닌 세로부터 시작하거나 해서 바꿔줄 수 있다.
그리고 다른 방법으로는 그냥 편하게 블럭의 크기만큼 배열을 지정해서 있는곳에는 숫자를 넣고 아닌곳에는 0을 넣는 방식 있다.

예제) 일자모양을 배열으로 표시하는 방법. 소스가 길어지므로, 헤더파일에 넣기를 권장한다.
~cpp 
	{{
	{0,0,0,0},
	{2,2,2,2},
	{0,0,0,0},
	{0,0,0,0}}
	,{
	{0,0,2,0},
	{0,0,2,0},
	{0,0,2,0},
	{0,0,2,0}}
	,{
	{0,0,0,0},
	{2,2,2,2},
	{0,0,0,0},
	{0,0,0,0}}
	,{
	{0,0,2,0},
	{0,0,2,0},
	{0,0,2,0},
	{0,0,2,0}}
},

랜덤으로 블럭을 생성한 후 next창에 출력하기


우선 랜덤하게 블럭을 생성하기 위해서 start()함수에 srand((int)time(NULL));라고 적어서, 시간을 용해서 랜덤하게 나오게 한 다음,
블럭을 랜덤하게 호출하는 함수를 만들자. 그리고 그 안에 rand()함수를 사용해서, 임의의 숫자를 얻은후 그 숫자에 맞추어 블럭을 지정하고
next변수에 출력되게 하면 된다.
그리고 출력될 변수를 기억하게 하기 위해서 다음에 나올 블럭을 기억하는 전역변수를 만들고, 거기에 값을 저장시키자.

테스트를 위해서는 key_Right()와 같은 변수안에 넣고, 해당하는 키를 눌러보면 실행 된다.

test02.jpg

예제)
~cpp 
	int block_id;
	block_id=rand()%7;
	for (register int i=0;i<3;++i)
		for (register int j=0; j<4; ++j)
			block_next[i][j]=block_type[block_id][0][i][j];
	prv_block=block_id; //전역변수에 저장.



생성된 블럭을 메인창에 소환하기


정해진 블럭을 메인창에 소환해 보자. 메인창의 맨 위의 가운데쯤 가장 적당할 것다.
또 소환되는 순간, 그 위치에 블럭 있다면, 게임은 종료될 것다.
소환된 후, 진행을 위해 소환된 위치의 x,y값을 기억하는 전역변수를 만들고 소환하면 된다.
그리고, 현제 블럭의 아디를 기억할 전역변수도 만들어서 저장하자.
소환하는 알고리즘은 위에서 next창에 불러오는것과 같은 알고리즘 다.

테스트를 위해서는 key_Left()와 같은 변수안에 넣고, 랜덤으로 만드는 함수를 호출한후, 호출해 보면 된다.

예제)
~cpp 
	for (register int i=0;i<3; ++i)
	{
		for (register int j=0; j<4; ++j)
		{
			if (0!=block_type[prv_block][0][i][j])
			{
				if (0==block[3+i][16+j])
					block[3+i][16+j]=block_type[prv_block][0][i][j];
				else
					game_end();
			}
		}
	}
	x=3;  //전역변수 x
	y=16; //전역변수 y
	shape=0; //전역변수 현재 블록의 회전정도
	now_block=prv_block; //전역변수 현재 블럭의 ID

test03.jpg


생성된 블럭을 움직게 하기


소환된 블럭을 움직게 해보자. 움직게 하는데는 여러가지 알고리즘 있지만, 쉬운 방법은 블럭 내려가면 색깔을 바꾸고, 색깔 있는 블럭만 움직게 하는 방법 있다. 두번째는, 블럭의 끝을 계산해서 그 부분 닿게되면 멈추게 하는 방법 있다. 후자가 연산 더 복잡하나, 좀더 다양한 색상을 볼 수 있다. 움직일 때에는, 좌우의 벽과 다른 블럭을 고려해서 움직여야 한다.

다 만들어 진 후, 왼쪽, 오른쪽 방향키에 알맞은 인자를 넣어서 함수를 넣고, now_time()에 블럭을 아래로 내리는 함수를 호출하도록 하자.

test04.jpg


예제) 두번째 방법을 용한 모습중 하나. -1은 왼쪽 0은 아래, 1은 오른쪽으로 움직인다는 뜻으로 인자를 넘겨받는다.
리팩토링 필요한 모습다.


~cpp 
int move_block(int where)// -1좌 0아래  1우
{
	int temp_x=x+where;
	int temp_y=y-(where+1)%2;
	int temp_block[4][4]={0,};
	int ground[4]={0,};
	int side[2][4]={0,};
	int swit[2][4]={0,};
         
         // 블럭의 끝을 체크한다.         

	for (register int i=0;i<4; ++i)
	{
		for (register int j=0; j<4; ++j)
		{
			if (0!=block_type[now_block][shape][i][j])
			{
				if (i>=side[0][j] && 0==swit[1][j])
				{
					side[0][j]=i;
					swit[1][j]=1;
				}
				side[1][j]=i;
				if (j>=ground[i] && 0==swit[0][i])
				{
					ground[i]=j;
					swit[0][i]=1;
				}
			}
		}
	}

         // 블럭 움직일 수 있는가를 판단한다. 못 움직일 경우에는 1을 리턴하고 종료한다.

	for (i=0;i<4; ++i)
	{
		for (register int j=0; j<4; ++j)
		{
			if (0!=block_type[now_block][shape][i][j])
			{
				if (temp_x+i<0 || temp_x+i>9 )
					return 1;
				else if (temp_y+j<0 || temp_y+j>19 )
					return 1;
				else if (0!=block[temp_x+i][temp_y+j])
				{
					if (ground[i]+1>j && where==0)
						return 1;
					else if (side[0][j]+1>i && where==-1)
						return 1;
					else if (side[1][j]-1<i && where==1)
						return 1;
				}
			}
		}
	}

         // 전의 블럭의 미지를 제거한다.

	for (i=0;i<4; ++i)
		for (register int j=0; j<4; ++j)
			if (0!=block_type[now_block][shape][i][j])
				block[x+i][y+j]=0;

         // 새로운 블럭을 그린다.

	for (i=0;i<4; ++i)
		for (register int j=0; j<4; ++j)
			if (0!=block_type[now_block][shape][i][j])
				block[temp_x+i][temp_y+j]=block_type[now_block][shape][i][j];
	x=temp_x;y=temp_y;
	return 0;
}


블럭을 회전하게 하기


블럭을 회전하기 위해서, 해야할 일은, 좌 우측으로 충분한 공간 있는지를 보고, 벽 막고 있으면 움직여준 뒤에 공간을 확보해서 회전하게 하는 것다. 동보다는 간편한 편며, 전역변수에 움직인 정도를 기억시켜서, 움직일 수 있도록 해야 한다.

예제)

~cpp 
	int temp_x=x;
	int temp_y=y;
	int temp_shape=(shape+1)%4;
	int crash=2;
	int temp_block[4][4]={0,};

         //블럭 벽에 닿는지, 충분한 공간 있는지를 확인한다.

	while (2==crash)
	{
		for (register int i=0;i<4; ++i)
			for (register int j=0; j<4; ++j)
				temp_block[i][j]=0;
		crash=0;
		for (i=0;i<4; ++i)
			for (register int j=0; j<4; ++j)
				if (0!=block_type[now_block][shape][i][j]&& 0<=i+x-temp_x && 3>=i+x-temp_x )
					temp_block[i+x-temp_x][j]=1;
		for (i=0;i<4; ++i)
		{
			for (register int j=0; j<4; ++j)
			{
				if (0!=block_type[now_block][temp_shape][i][j])
				{
					if (temp_x+i<0)
					{
						temp_x+=1;crash=2;
					}
					else if (temp_x+i>9 )
					{
						temp_x-=1;crash=2;
					}
					else if (0!=block[temp_x+i][temp_y+j] && 1!=temp_block[i][j])
						crash=1;
				}
			}
		}
	}

         //블럭 회전할 공간 있으면, 전의 블럭을 삭제한다.

	if (1==crash)
		return 0;
	for (register int i=0;i<4; ++i)
		for (register int j=0; j<4; ++j)
			if (0!=block_type[now_block][shape][i][j])
				block[x+i][y+j]=0;

         //새로운 블럭을 그려넣는다.

	for (i=0;i<4; ++i)
		for (register int j=0; j<4; ++j)
			if (0!=block_type[now_block][temp_shape][i][j])
				block[temp_x+i][temp_y+j]=block_type[now_block][temp_shape][i][j];

         //변화된 값을 저장한다.

	x=temp_x;y=temp_y;shape=temp_shape;
	return 0;


블럭을 삭제하기


블럭 내려오게 되어, 한줄 완성되면 삭제되어야 한다. 또한, 삭제된후 그 윗줄부터는 한칸씩 아래로 내려져야 한다.
일반적으로 for문을 용해서 한줄을 검색할 수 있으나, 같은 내려온 블럭 같은색으로 처리되는 경우는, 더해서 숫자가 일치하는지를 볼 수도 있다.

예제)
~cpp 
void delete_block()
{
	for (register int line=y; line<y+4; ++line)
		for (register int i=0; i<10; ++i)
			if (0==block[i][line])
				i=10;   //빈 블럭 있으면, 그줄의 검사를 끝낸다.
			else
				if (9==i) //블럭 다 차있을 경우에는 한줄을 삭제한다.
				{
					for (register int k=0; k<10; ++k)
						block[k][line]=0;
					for (k=line; k<19; ++k) //블럭을 한줄씩 내린다.
						for (register int l=0; l<10; ++l)
							block[l][k]=block[l][k+1];
					for (k=0; k<10; ++k)
						block[k][19]=0;
					--line;
				}
}


점수와 스테지 변환


점수는 블럭 내려올때, 삭제될때 등으로 증가되는 경우를 정하고, 그 경우마다 알맞은 값을 증가시켜 주면된다.
그리고 그 결과 점수가 일정치에 달하면 스테지를 바꾸고, time_delay 변수의 값을 감소시켜 난도를 증가시키면 된다.

Valid XHTML 1.0! Valid CSS! powered by MoniWiki
last modified 2021-02-07 05:28:59
Processing time 0.0239 sec