본문 바로가기
자바스크립트와 캔버스

자바스크립트와 캔버스 7, 테트리스를 만들어봐-3

1. HTML 표준 CANVAS 기술 소개 / https://itadventure.tistory.com/130

2. 자바스크립트와 CANVAS 두번째시간. 캔바스에 눈을 내리자 / https://itadventure.tistory.com/131

3. 자바스크립트와 캔버스 3번째 시간, 공튀기기 놀이 / https://itadventure.tistory.com/132

4. 자바스크립트와 캔버스 4번째 시간, 마우스의 파동을 느껴봐! | https://itadventure.tistory.com/133

5. 자바스크립트와 캔버스, 테트리스를 만들어봐-1 | https://itadventure.tistory.com/136

6. 자바스크립트와 캔버스, 테트리스를 만들어봐-2 https://itadventure.tistory.com/139

◐ 7. 자바스크립트와 캔버스, 테트리스를 만들어봐-3 


전에 장학일 목사님의 부흥회를 다녀 왔었는데 재치 있고 은혜로운 말씀이 연상됩니다.

기독교는 여타 종교와는 사뭇 다른 부분이 있습니다.
보통의 종교의 경우 나의 노력으로 "훌륭한 사람이 되는 것", "선한 사람이 되는 것"이 목표라면,
기독교는 "신의 전적인 은혜"로 말미암아 , "구원받고 천국 백성이 되어지는 것"입니다.

"신의 전적인 은혜"로 말미암아 "내가 할수 없다"고 신에게 항복하고
"예수 그리스도"를 나의 주인으로 인정하는 것부터 시작하는 것이지요.
그것은 기독교에서 누구든지 스스로 자랑할 수 없게 하려는 신의 뜻이기도 합니다.

그것을 "하나님의 선행은혜"라고 합니다. 신이신 하나님께서 친히 나를 먼저 찾아와 주시는 것이지요.
모든 분들에게 "
신의 선행은혜"가 베풀어지시길 소망합니다 :)


이번 시간에는 지난 시간에 이어 테트리스 블럭이 쌓이는 부분을 다뤄보도록 하겠습니다.

지난 시간 아쉽게도 메모리 블록이 점점 내려가더니 벽을 통과하여 한없이 추락하는 것은 울타리가 없어서 그렇습니다.

울타리를 벗어나면 거긴 위험하니까 가지 말라고 붙잡아주면 딱 멈추게 될텐데 말이죠.

블록조각이 하강을 멈추어야 할 조건은 무엇이 있을까요?

첫번째는 블럭조각이 블럭박스의 경계를 넘어서려고 할 때입니다.

그리고 두번째는 블럭박스 내에 이미 쌓여 있는 블럭과 겹치려고 할때 입니다.

이런 움직임이 감지되면 바로 이전 단계로 되돌리고 블럭조각의 모양을 블럭박스에 블럭이 쌓이도록 고정한 다음, 다시 새로운 블록조각을 위에서 떨어뜨리면 됩니다.

한번 코딩으로 살펴보도록 하겠습니다.

이해를 돕기 위해 이제까지 다루었던 변수의 구성를 한번 메모리 맵(지도)를 통해 보도록 하지요. 녹색으로 표시된 글자가 변수명입니다.

만일 블럭조각이 블럭 박스 밖으로 빠져나갔는지를 판단하려면 어떤 조건을 사용해야 할까요?

블럭조각의 현재 x, y 좌표와 4개의 사각형 지점의 상대좌표를 블럭박스를 지나고 있는 좌표와 비교해보면 됩니다.

만일 y 좌표가 20 이상이면 블럭박스를 벗어난 것입니다.

관련 조건을 코딩하면 아래와 같습니다.

먼저 Run() 함수에서 블럭조각을 한칸 아랫방향으로 떨어뜨렸던 코드 직후에 바로 검사하도록 합니다.

function Run()
{
	// 블럭을 한칸 떨어뜨리고
	tetrix_block_y++;

겹침을 검사하기 위해 현재 블럭조각의 각 사각형을 검사할 반복문을 구성합니다.

	// 겹침검사	
	var size=(tetrix_block[tetrix_block_number]).length;
	for(k=0;k<size;k+=2)
	{
          :
	}

그리고 반복문 내에서 사각형 개개의 y좌표를 계산해 놓습니다.

		check_y = tetrix_block_y + tetrix_block[tetrix_block_number][k];

그리고 그 y 위치가 20이상인지 판단합니다. 제일 아랫 부분에 도달했는지를 판단하는 것이지요.

		if(check_y >= 20)
		{
                :
		}

20을 넘어서는 경우 블럭조각을 다시 위로 올려준 다음에,

			tetrix_block_y--;

블럭박스에 블럭조각의 모양에 따라 각각의 블럭을 1로 새깁니다.

그러면 이제 그 모양대로 존재하는 블럭이 되는 거지요.

			for(k=0;k<size;k+=2)
			{
				check_y = tetrix_block_y + tetrix_block[tetrix_block_number][k];
				check_x = tetrix_block_x + tetrix_block[tetrix_block_number][k+1];
				tetrix_blockbox[check_y][check_x]=1;
			}

그리고 다시 새로운 블럭을 위에서 생성해주는 겁니다.

블럭번호는 현재 번호에서 1을 증가시켜 다음 번호로 정해주고 좌표값을 바꿔주면 됩니다.

			// 블럭을 다시 제일 위로 생성시키고
			tetrix_block_y=0;
			// 블럭번호도 바꿔 주자
			tetrix_block_number++;
			if(tetrix_block_number>=5)tetrix_block_number=0;			
			break;

그러면 아래와 같은 그림의 작동이 되는 것이지요.

블럭끼리 겹치지 않게 쌓는 부분은 어떻게 하면 될까요?

간단합니다. 앞의 조건에서 20이상을 넘어가는 조건 검사 부분에 추가적으로 현재 블럭박스 내 블럭이 존재하는지 검사해주면 됩니다. 이를 위해 check_x라는 검사할 x좌표도 추가 정의가 필요합니다

	check_x = tetrix_block_x + tetrix_block[tetrix_block_number][k+1];
      :
		if(check_y >= 20 || tetrix_blockbox[check_y][check_x]!=0)
		{

이 경우에도 똑같이 위로 다시 한칸 올리고 블럭을 고정해주는 동작으로 진행하니 별 탈(?)은 없습니다 :)

여기까지가 블럭을 쌓는 부분이고, 전체 소스는 아래와 같습니다.

<!DOCTYPE html>
<html lang="ko">
<head>
	<meta charset="UTF-8">
	<title>캔바스. 테트리스</title>
</head>
<body>
https://blog.naver.com/ephraimdrlee 
/ 크레이의 세컨드라이프 탐구생활 네이버 블로그<br/>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script>
// 기본 초기화
var init=false;
var myCanvas;
var Context;

var tetrix_blockbox_boxsize=25;
var tetrix_blockbox_top=50;
var tetrix_blockbox_left=280;

// tetrix_blockbox[row][col]; 20행 10열
var tetrix_blockbox;

// 테트리스 블럭박스 초기화
function tetrix_blockbox_init()
{
	// 20행 10열의 박스 생성
	tetrix_blockbox=new Array();
	for(i=0;i<20;++i)
	{
		tetrix_blockbox.push(new Array(10));
		// 모두 0으로 채운다
		for(j=0;j<10;++j)tetrix_blockbox[i][j]=0;
	}
}

// 5가지 타입 블록
var tetrix_block;

// 5가지 블럭 초기화
function tetrix_block_init()
{
	tetrix_block=new Array();

	// 첫번째 블럭
	// □□□□
	tmp=new Array();
	tmp.push(0,0); tmp.push(0,1); tmp.push(0,2); tmp.push(0,3);
	tetrix_block.push(tmp);

	// 두번째 블럭
	// □□□
	//  □
	tmp=new Array();
	tmp.push(0,0); tmp.push(0,1); tmp.push(0,2); tmp.push(1,1);
	tetrix_block.push(tmp);

	// 세번째 블럭
	// □□
	//  □□
	tmp=new Array();
	tmp.push(0,0); tmp.push(0,1); tmp.push(1,1); tmp.push(1,2);
	tetrix_block.push(tmp);

	// 네번째 블럭
	//  □□
	// □□
	tmp=new Array();
	tmp.push(0,1); tmp.push(0,2); tmp.push(1,0); tmp.push(1,1);
	tetrix_block.push(tmp);

	// 다섯번째 블럭
	// □□
	// □□
	tmp=new Array();
	tmp.push(0,0); tmp.push(0,1); tmp.push(1,0); tmp.push(1,1);
	tetrix_block.push(tmp);
}

// 현재 떨어지는 블록번호와 좌표
var tetrix_block_number=1;
var tetrix_block_x=3;
var tetrix_block_y=0;

// 초기화
function Init()
{
	if(init==false)
	{
		myCanvas=document.getElementById("MyCanvas");
		Context=myCanvas.getContext("2d");		
		init=true;
		tetrix_block_init();	// 5가지 블럭 모양 초기화
		tetrix_blockbox_init();	// 블럭상자 초기화
	}
}

function Run()
{
	// 블럭을 한칸 떨어뜨리고
	tetrix_block_y++;

	// 겹침검사	
	var size=(tetrix_block[tetrix_block_number]).length;
	for(k=0;k<size;k+=2)
	{
		check_y = tetrix_block_y + tetrix_block[tetrix_block_number][k];
		check_x = tetrix_block_x + tetrix_block[tetrix_block_number][k+1];
		// 겹치는 경우
		if(check_y >= 20 || tetrix_blockbox[check_y][check_x]!=0)
		{
			// 다시 위로 이동시킨 다음
			tetrix_block_y--;
			// 블럭을 블럭판에 박는다
			for(k=0;k<size;k+=2)
			{
				check_y = tetrix_block_y + tetrix_block[tetrix_block_number][k];
				check_x = tetrix_block_x + tetrix_block[tetrix_block_number][k+1];
				tetrix_blockbox[check_y][check_x]=1;
			}
	
			// 블럭을 다시 제일 위로 생성시키고
			tetrix_block_y=0;
			// 블럭번호도 바꿔 주자
			tetrix_block_number++;
			if(tetrix_block_number>=5)tetrix_block_number=0;			
			break;
		}
	}

	
	// 그리기 이벤트
	onDraw();
}

// draw 이벤트
function onDraw()
{
	if(init==false)return;
	// 전체 테두리
	Context.strokeStyle="#000";
	Context.lineWidth=1;
	Context.strokeRect(0, 0, myCanvas.width-1, myCanvas.height-1);
	// 블럭 표시
	for(i=0;i<20;++i)
		for(j=0;j<10;++j)
		{
			if(tetrix_blockbox[i][j]==0)
				Context.fillStyle="#ccc";
			else
				Context.fillStyle="green";
			
			// 떨어지는 블럭표시
			var size=(tetrix_block[tetrix_block_number]).length;
			for(k=0;k<size;k+=2)
			{
				if(tetrix_block_y+tetrix_block[tetrix_block_number][k]==i
				   && tetrix_block_x+tetrix_block[tetrix_block_number][k+1]==j)
					Context.fillStyle="blue"; 
			}

			x=tetrix_blockbox_left + j*tetrix_blockbox_boxsize;
			y=tetrix_blockbox_top + i*tetrix_blockbox_boxsize;
			Context.fillRect(x, y, tetrix_blockbox_boxsize-2, tetrix_blockbox_boxsize-2);
		}
}

$(document).ready(function(){
	Init();
	setInterval(Run, 500);

});

</script>

<canvas id="MyCanvas" width=800 height=600>
Canvas is not supported.
</canvas>
블럭이 계속 떨어지면서 쌓이는 부분 추가
<span id=debug></span>
</body>
</html>

블럭이 쌓이는걸 보니 이 블럭을 움직이고 싶다는 생각이 드시는 분도 계실겁니다 :)

다음 시간에는 화살표키로 블럭을 움직이는 부분을 다뤄보도록 하겠습니다.

본 게시물의 결과물은 아래 페이지에서 제공됩니다. 미리 보기를 원하시는 분은 방문해 보세요 :)

http://dreamplan7.cafe24.com/canvas/cray07.php

 

캔바스. 테트리스

 

dreamplan7.cafe24.com

코드라는건 한번에 이해되기 어렵습니다.
반복해서 여러번 들여다 보고 이렇게 저렇게 코드를 바꿔가면서 직접 실습해봐야
비로서 코딩 감각이 생기는데요.
부디 도전하시는 분들은 모두 성공하시길 바랍니다 :)

오늘도 여기까지 읽어주시느라 수고하셨습니다.
감사합니다.