[초보자들 EP.04] 미션 : 테트리스 만들기

bs-newbie-e02

지난시간 초보자들 이야기 – TO-DO List 만들기

진정한 개발자가 되기위해 끝없는 미션을 수행하는 dimanche와 summer. ‘못 할 것은 없다!’라며 미션에 자신감을 붙여보려는 그 때..
이전과는 다른 미션이 등장한다. 당황한 이들의 뇌는 멈춰버렸다. 어떻게 극복할까? 틱틱틱.. 시간만 흘러간다.

멈춰버린 머리

미션을 받을 때마다 멘붕을 느끼며 지냈지만, 이제 뭐부터 하면 좋을지 감이 잡혔다고 자신감이 붙었습니다. 그 자신감으로 타임머신 에디터 버전업도 해볼까하고 한 숨 돌리던 그 날! 2016. 10. 12 오전 10:40. 새로운 미션을 받았습니다.
‘테트리스 만들기’였습니다. 저는 중학생 시절 학교 컴퓨터에 몰래 테트리스를 설치해 점심시간마다 친구들과 게임을 했던 추억이 떠올랐습니다.
tetris02

너무 재밌을 거 같은 상상과 함께 열심히 요구사항을 적었습니다.
이번 미션의 요구사항은 다음과 같습니다.

  • 시작화면, 점수화면, 게임화면 총 3개의 화면이 있다.
  • 시작화면에는 시작하기와 점수보기라는 메뉴 2개가 있다.
  • 점수보기 클릭 시 점수화면으로 이동한다.
  • 시작하기 클릭 시 게임화면으로 이동한다.
  • 점수보기 화면에서는 기존에 기록한 하이스코어 10개를 보여준다.
  • 점수보기 화면에서는 돌아가기 버튼이 있고 클릭 시 시작화면으로 이동한다.
  • 시작화면에서 시작하기를 누르면 게임화면으로 변경된다.
  • 게임화면에는 현재 점수, 제거한 줄 수, 경과한 시간, 현재까지 등장한 블록의 수가 상단에 표시되고, 다음에 등장할 블럭의 모양도 표시된다.
  • 게임화면의 중간에는 테트리스 화면이 나오고, 가로는 10, 세로는 25에 블록을 수용할 수 있는 직사각형이다.
  • 스테이지는 없으며, 최초 하강 속도가 10줄을 없앨 때마다 일정하게 증가한다. 수치는 정해주시진 않았지만, 점진적으로 증가한다.
  • 조작은 키보드 화살표, 좌우는 이동, 위쪽은 시계방향회전, 아래쪽은 반시계방향회전, 스페이스바는 블럭이 꽂힌다.
  • 게임의 종료 조건은 쌓인 블럭이 맞닿거나 넘어가면 종료한다.
  • 게임 종료 시 종료 팝업이 뜬다. 종료팝업에는 플레이 시간, 지운 줄수, 등장한 블럭 수, 처음으로 버튼이 있다.
  • 하이스코어를 갱신한 경우에는 1~10위 사이의 등수를 종료 팝업에 표시한다.
  • 점수 계산은 한번에 지워지는 줄수에 따라 계산된다. 점수는 1줄 100점, 2줄 300점, 3줄 1000점, 4줄 2000점이 추가된다.

‘자, 그럼 이제 시작해 볼까?!’
실습을 통해 배운 것 처럼 먼저 용어집과 설계문서를 만들기로 했습니다. 화면 구성과 화면마다 필요한 요소들.. 전에 했던 미션들보다 꽤 많은 것 같습니다. 용어집을 정리하고 설계문서에 시나리오와 flowchart를 그려나가고 싶은데, 뭐부터 생각해야할지 막막하고 멍해졌습니다. ‘점심때 먹은 붕어빵 탓인가…?’라는 생각도 했습니다. ‘블럭 나오고 블럭 쌓고’라는 것이 테트리스 게임할 땐 당연한 듯 별거 아닌 듯 생각했었습니다. 멈춰버린 저의 머리.. 저한테는 별 거였나 봅니다.
jamjam-1

‘테트리스 재밌는데…재미야 어디갔니?’

tic! tic! tic!

‘무엇이 나의 머리를 멈추게 하는가?’ 전에 했던 미션과 이번 미션의 차이점은 무엇일까? 이벤트 발생입니다. 마우스와 키보드로만 발생하는 이벤트만을 보았습니다. 이번 미션에는 시간이 변하면서 이벤트도 발생합니다. 복잡한 것을 어떻게 구분하고 화면에 보여주지라는 생각에 전 막막했습니다.

멈춰있는 저에게 구세주가 등장하셨습니다. 바로 실장님의 tip!
‘테트리스라는 게임이 그냥 흘러간다고만 생각하지 말고, 그 찰나에 무슨일이 일어나는지 생각해보자! 컴퓨터는 자연세계처럼 무한히 미분되지 않는다. 분해하고 분해하고 분해하면 구분되는 지점이 있다. 그게 틱이야. 그럼 한 틱에서는 무슨일이 일어날까?’
이렇게 주기적으로 발생하는 틱의 존재를 알게되었습니다. 테트리스에서의 한 틱은 블럭이 한 줄씩 내려오는 것입니다. 그래서 틱이 발생하는 전체적인 진행 순서를 flowchart로 그려봅니다.
generalview

한가지 더! 키보드 이벤트에 대한 진행도 flowchart로 그려봅니다.
flow-key
오호~ 진행 순서를 생각할 수 있게 되었습니다. 정리하고 나니 시리얼을 먹은 듯 다시 호랑이 기운이 나기 시작했습니다.

flowchart를 다시 보았습니다. 이벤트가 생길 때 마다 데이터를 변경해주고 화면을 갱신해줍니다. 저는 설계문서를 통해 무엇을 설계해야하는지 정확히 몰랐었던 것 같습니다. 그렇기 때문에 머리가 멈췄었고, 너무 복잡하게만 느꼈습니다. 이제 알게 되었습니다.
설계문서는 이런 저장할 수 있는 데이터(model)를 짜는 과정이라는 것을.
화면은 사실 상 예쁜 데이터 뷰어이고, 화면 갱신(render)는 단지 model을 화면에 표현하는 것을.
키보드 이벤트든, 마우스 이벤트든, 시간에 따라 생기는 이벤트든 모두 model을 갱신하고 화면을 render하면 된다는 것을.
즉, 설계문서를 통해 제가 알아야하는 것은 잘짜여진 model이였습니다.

이제 시나리오와 용어집을 작성하며, model을 만들어 나가봅니다.
1. 용어집
dictionary

  1. 설계문서
    ppt_end

tetriscopic

실장님의 조언이 아니었다면 어떻게 되었을까요? 테트리스를 ‘블럭 나오고 블럭 쌓고’로 밖에 생각하지 못한 저에게 필요한 것은 무엇일까요?

모든 것은 어떻게 바라보느냐에 따라 다릅니다. 거시적으로 바라보거나, 미시적으로 바라보거나. 거시적이란 전체적으로 파악하는 것이고, 미시적이란 전체적인 면에서가 아니라 개별적으로 포착하여 파악 것입니다.
다들 레고 블럭을 조립해 본 적이 있으신가요?
레고 블럭을 거시적으로 바라보면 완성된 제품일 것이고, 미시적으로 바라보면 하나하나의 블럭일 것입니다.
lego02

왼쪽: 완성된 레고 블럭 제품 / 오른쪽 : 레고 블럭 조각

제가 바라본 테트리스는 아주 거시적인 관점이었습니다. 그래서 ‘어떤 작은 조합으로 이루어졌을까’를 생각하기 힘들었습니다.
복잡한 일은 단순한 일의 합입니다. 점진적으로 단순한 일이 합쳐진 것입니다. 우리는 전체 현상을 줌인해서 볼 줄 알아야하고 그 것을 분해할 줄 알아야합니다.
즉, 다음과 같은 과정이 필요합니다.

  1. 전체를 줌인해서 본다.
  2. 부분현상의 합이 보인다.
  3. 분해한다.
  4. 부분현상+부분현상+부분현상…

이렇게 자유롭게 줌인, 줌아웃을 하는 행위를 scopic이라고 합니다. 건담, 레고를 만드는 회사들이 스코픽을 하는 회사인거죠.
우리는 완성품을 분해해 조각조각 개발해 나가야합니다. 즉, 개발자 또한 소프트웨어를 스코픽으로 만드는 사람입니다. 좋은 개발자가 되기 위해선 이러한 능력을 꾸준히 연습해야 할 것입니다. 그래서 저는 이제 밥도 한톨한톨 분해해서 먹..

버전업

전에 summer가 쓴 [초보자들 EP.01] 레벨테스트 : 슬롯머신 만들기 라는 글에 저희의 구세주로 나왔던 <다함께 프로그래밍> 책을 아시나요? 책에는 프로그래밍 작성의 7단계가 있습니다. 그 중 마지막 단계로 버전업이 있습니다. 아직까지 미션을 수행하면서 제대로된 버전업을 해본 적이 없습니다.
버전업은 지금 있는 기능에 뭔가 새로운 기능을 추가하는 작업을 말합니다. 버전업을 실행하는 단계는 처음 프로그램을 만들 때와 동일합니다. 그리고 또 하나 중요한 것이 있죠! 바로 ‘욕심을 부리지 않는 것’입니다.

제가 버전업을 하고 싶은 기능들을 생각해보았습니다. 시작/일지정지 기능, 블록 holding 기능, 블록 위치를 파악하는 그림자 기능, 배경음악, 효과음, 각 종 애니메이션, 스테이지.. 음.. 또..
human_greed

이래서 버전업에서 욕심을 부리지 않는 것을 중요하다 했나봅니다. 추가해보고 싶은 기능들은 많지만, 그 중 몇 가지만 골라보았습니다.

  • 시작/일시정지 기능 : 게임을 진행하고, 일시정지 시키는 기능입니다.
  • hold 기능 : 현재 블록을 저장해놓고, 필요 시 불러올 수 있는 기능입니다.
  • 배경음악 : 게임이 진행되는 동안 배경음악이 나옵니다. 음악을 끌 수 있습니다.

1. 시나리오
1.1 실행/일시정지 기능(enter 키, 실행버튼 이벤트)
up01

1.2 hold 기능(shift 키 이벤트)
up02

1.3 배경음악 재생/일시정지(ESC 키 이벤트 발생, 게임 일시정지 시)
up03

2. script 코드
2.1 실행/일시정지 기능(enter 키, 실행버튼 이벤트)

pause(){
	if(isPlay){ //1. isPlay가 true일 때
		//1.2 진행 버튼의 텍스트를 재생으로 바꾼다.
		getEl('pause', 1)[0].className = 'isPlay play';
		getEl('isPlay', 0).innerHTML = '재생';
		//1.3 isPlay를 false로 변경한다.
		isPlay = false;
		//1.4 actionInterval을 삭제하여 게임 진행을 멈춘다.
		clearInterval(actionInterval);
		//1.5 timeInterval을 삭제하여 경과 시간을 멈춘다.
		clearInterval(timeInterval);
		//1.6 audio를 일시정지 시킨다.
		audio.pause();
	}else{ //2. isPlay가 false일 때
		//2.1 진행 버튼의 텍스트를 일시정지로 바꾼다.
		getEl('play', 1)[0].className = 'isPlay pause';
		getEl('isPlay', 0).innerHTML = '일시정지';
		//2.2 isPlay를 true로 변경한다.
		isPlay = true;
		//2.3 actionTic을 시작한다.
		Tetris.actionTic();
		//2.4 timeTic을 시작한다.
		Tetris.timeTic();
		//2.5 isSound가 true라면 audio를 실행 시킨다.
		if(isSound) audio.play();
	}
}

2.2 hold 기능(shift 키 이벤트)

case SHIFT: {
	if(holdBlo == null){ //1. holdBlo 값이 null일 때,
		//1.1 holdBlo에 currBlo값을 넣는다.
		holdBlo = currBlo;
		//1.2 다음 턴을 시작한다.
		Tetris.startTurn();
	}else if(!Tetris.checkOver(currPos, holdBlo, 0)){ //2. 현재 위치에서 holdBlo이 올 수 있는지 확인한다.
		//2.1 currRot를 0으로 초기화한다.
		currRot = 0;
		//2.2 변수 tempBlo에 holdBlo 값을 넣는다.
		var tempBlo = holdBlo;
		//2.3 holdBlo에 currBlo값을 넣는다.
		holdBlo = currBlo;
		//2.4 currBlo에 tempBlo값을 넣는다.
		currBlo = tempBlo;
	}else { //3. 그렇지 않다면,
		//3.1 경고음을 출력한다.
		warning.play();
		//3.2 빈값을 반환한다.
		return ;
	}
	//hold 블록 박스를 갱신한다.
	Tetris.renderBlockInfo('Hold', holdBlo);
	break;
}

2.3 배경음악 재생/일시정지(ESC 키 이벤트 발생, 게임 일시정지 시)

soundPause(){
	if(isSound){ //1. isSound가 true일 때
		//1.1 isSound를 false로 변경한다.
		isSound = false;
		//1.2 배경음악을 일시정지 한다.
		audio.pause();
	}else{ //2. isSound가 false일 때
		//2.1 isSound를 true로 변경한다.
		isSound = true;
		//2.2 배경음악을 재생한다.
		audio.play();
	}
}

드디어 버전업까지 끝냈습니다.
다른 테트리스와는 달리 특이한 블럭 때문에 테스트 해보는 과정이 가장 힘들었습니다. 나올 때마다 ‘아! 저모양 진짜!!!’라는 생각을 했습니다. 그리고 제 테트리스 이름을 바꿨습니다. Psycho Block으로 말이죠.
그래도 이렇게 제가 만든 테트리스를 해보니 뿌듯합니다.

미션 완료

이번 미션에서도 어김없이 제가 배워야할 것들, 고쳐야할 것들이 많았습니다. 그 중에서 가장 크게 배우게 된 것은 개발해야하는 것에 대한 제 관점일 것입니다. 실시간으로 진행되는 복잡한 일을 단순한 일들의 집합으로 바라보도록 스코픽하는 과정이 있어서 인터벌 진행을 생각할 수 있었고, 설계문서에 진정으로 필요한 것이 model이라는 것까지.

위의 내용에 언급된 것 외에도 알게된 것들이 많습니다.
설계문서 작성에서 블록을 바라볼 때 모양, 색상만 보는 것이 아닌 회전 기준점도 고려할 줄 아는 것이 개발자라는 것.
함수를 사용해 2번이상 반복되는 부분을 분리시키기도 하지만, 어떤 역할을 수행하는 부분으로써 격리시켜 관리를 할 수 있도록 만든다는 것.
패턴을 발견하면 데이터는 알고리즘과 교환할 수 있다는 것.
매번 미션을 하면서 많이 배우게 됩니다. 너무 많아 글에 모든 걸 언급할 수 없는 것이 아쉽네요.

생판 모르는 것도 만들어 내는 것이 우리의 업입니다.
저는 본 적있는 것(테트리스)임에도 불구하고 무엇을 해야할지 얼어버렸지만, 점점 저에게 필요한 능력이 무엇인지 알아가고 있습니다.
특히 스코픽은 잊어버리지 않도록 꾸준한 노력으로 되새김질을 해야겠습니다.

허점이 많을 것이라 부끄럽지만, 제가 만든 테트리스를 보여드리겠습니다.
dimanche의 Psycho Block!
조금 지루하다 싶으신 분들은 아래 링크로 게임 즐겨봐주세요^^
Psycho Block Test버전


dimanche
dimanche | bsidesoft 신입사원
좋은 개발자가 뭔지도 모르고 좋은 개발자가 되고 싶은 초보 개발자입니다.
회사에서는 열심히 교육받고 발전하는 운 좋은 개발자로 일하고 있습니다.

%d 블로거가 이것을 좋아합니다: