반응형

과거 svn을 사용할때, 소스가 꼬였거나 잘 못된 개발로 되돌아가야할 일이 생길 경우 리비전을 통해 되돌아가고 재작업을 진행하고 그랬는데, git에서는 리비전이라는 용어대신 특정 commit으로 되돌아 가는 방식을 사용해야 했습니다.

 

 

이러한 형태로 git작업이 되어있다고 칩시다...

너무 복잡한 예시는 오히려 이해하는데 방해가 될 것 같아서 최대한 간단하게 해보려고 합니다.

index.js추가 ~ cal메소드 추가부분을 봐주시면 됩니다.

 

fork를 사용 중이라면 되돌아가고자 하는 commit부분에 오른쪽 클릭 후 checkout commit 을 해주면 간단하게 되돌아갑니다.

역시 gui가 한 눈에 잘보이고 편합니다...

이 후 브랜치를 새로 생성하고 소스를 수정한다음 merge까지 진행하면 새롭게 변경할 수 있습니다.

fork사용자는 이렇게 편하지만 git bash를 쓰고 있는분들을 위해 명령어와 함께 설명을 추가해보겠습니다.

 

git bash에서 과거 commit으로 회귀하기

git log

git log

commit된 히스토리들을 봐야 되돌아가고 할텐데 이때 사용하는 명령어는 "git log"입니다.

-p옵션을 사용하면 어떤부분이 바뀌면서 올라갔는지 나오고 추가적으로 -2 와 같은 명령어를 입력하면 최근 2개만 출력해서 보여줍니다.

 

git log -p -2

git log

 

명령어를 입력해보면 노란글씨의 commit 부분이 보일텐데 앞 6자리를 기준으로 확인해주면 알아서 식별을 해줍니다.

git에 등록한 각각 commit의 고유번호들로 이 값을 통해 돌아갈 수 있습니다.

되돌아갈땐 브랜치를 바꿀 때 사용하였던 checkout 명령어를 사용합니다.

 

과거 commit으로 돌아가기

git checkout <commit번호>

"git checkout 0cd1df"를 입력해보겠습니다.

과거 commit으로 이동

 

 

되돌아오기

그럼 다시 원래대로 돌아올수도 있어야겠죠?

마지막 commit된 곳으로 해도되지만 마지막 브랜치인 master로 이동하겠습니다.

 

git checkout master

master로 되돌아오기

 

과거로 commit후 새롭게 브랜치 생성하기

cal()메소드가 존재하지 않던 과거로 돌아가고 거기서 브랜치를 만들어서 master를 진행해보겠습니다.

방금 전 과거 commit으로 돌아갔으니 거기서 소스 수정하고 다시 commit하면 되는게 아닐까 생각하시겠지만 그부분에서 commit을하고 push를 해도 브랜치를 만들어서 진행한게 아니기때문에 적용이 되질 않습니다.

 

 

git log

//돌아갈 commit 고유값 앞 6자리를 기억합니다.

git checkout 4385268

git log를 통해 commit 고유값을 알아낸 후 다시 과거로 돌아갑니다.

이제 브랜치를 새로 생성해줍니다.

 

 

git branch new_psw

과거로 돌아간 후 new_psw브랜치 생성

되돌아가서 브랜치까지 생성을 성공하셨다면 checkout을 통해 꼭 브랜치를 변경하시고 수정할 소스를 바꾸신 후 다시 commit을 처리해줍니다.

이제 브랜치가 생겼기때문에 commit을해도 정상적으로 처리가 됩니다.

 

 

new_psw브랜치로 새로운 소스 올리기

git checkout new_psw //새로 생성한 브랜치로 바꾼다.

git add . //변경된 소스를 올린다.

git commit -m "min메소드 추가" //commit처리

git push origin new_psw //서버에 new_psw브랜치로 올리기

새로운 브랜치를 따서 작업을 완료했으니 변경된 브랜치로 checkout을 하시고 변경된 소스를 올린 후

commit을 해줍니다.

new_psw브랜치에서 소스 올리기

 

push를 통해 서버까지 올리면 이제 master브랜치로 병합처리를 해보겠습니다.

 

 

master브랜치 병합하기

git checkout master

master브랜치로 변경합니다.

 

 

git merge new_psw

master브랜치로 바꿔놓은상태에서 new_psw브랜치를 병합합니다.

master브랜치로 병합하기 충돌발생!

merge failed라는 말과 할께 충돌이 났다는 메시지가 나옵니다.

충돌난 소스를 수정하겠습니다.

 

 

git 충돌!

충돌이 났고 필요없는 cal메소드는 삭제하였습니다.

 

충돌난 부분 수정

 

이제 완벽하게 merge를 끝내기 위해 다시 소스를 올립니다.

 

 

git add .

git commit -m "merge 완료"

git push origin master

merge를 위해 commit을 진행합니다.

 

 

 

정상적으로 merge까지 끝났다.

생각보다 복잡하다면 복잡하지만 branch과정을 한번 해보셨다면 그렇게 어렵지 않을겁니다.

이부분이 어려우신분은 branch부터 간단하게 예제를 한번 해보시면 쉽게 이해가 가능할 것 같습니다.

 

 

fork에서 확인하니 더 잘보입니다.

 

여기서 한단계 더 나아가면 더이상 사용하지 않는 new_psw브랜치까지 삭제해주시면 좋을 것 같습니다.

 

반응형
반응형

최근 git을 사용하면서 추가버전을 롤백하게 되어 과거버전으로 돌아가야 할 일이 생겼습니다.

기존에 사용하던 svn은 여러가지 기능 중 히스토리를 확인하여 날짜를 선택하고 손쉽게 과거로 돌아가 그때부터 다시 commit을 치고 update를하면서 사용 할 수 있었지만 지금 사용하는 git은 그런방법으로 처리하는게 쉽지 않았고 처리 방법으론 과거 commit을 찾아서 해당 commit영역을 checkout 한 후 branch를 새롭게 만들어서 사용하는 방법을 채택하여 사용중에 있습니다.

 

이 과정을 겪으면서 branch에 대해 알아볼 필요성이 생겼고, 간단하게 branch의 사용법을 확인 후 처리했던 방법을 포스팅 해보고자 합니다.

 

GIT - branch

branch만들기

git branch <name>

"git branch 브랜치명"를 통해 브랜치 생성할 수 있습니다.

브랜치 생성

 

 

branch 목록 확인하기

git branch

"git branch"를 통해 브랜치 리스트를 확인 할 수 있습니다.

브랜치 목록 확인

 

 

사용하는 branch 변경하기

git checkout <branch>

"git checkout 브랜치명"을 통해 사용할 브랜치를 바꿀 수 있습니다.

브랜치 변경

 

 

새 브랜치에 소스 올리기

브랜치를 새로 만들어서 변경까지 했다는건 이 부분부터 새로운 소스로 개발을 진행하겠다는 뜻이겠죠?

여기서 소스를 약간 수정하고 add 후 commit을 해서 push까지 진행해보겠습니다.

 

저는 index.html만 약간의 수정을 했습니다.

index.html수정

 

아래 명령을 통해 전부 add해주시고 commit 메시지를 남깁니다.

git add .
git commit -m "브랜치 변경"

소스를 수정 후 commit

push도 진행합니다.

git push origin psw

이번엔 변경된 브랜치명인 psw로 올립니다. (master -> psw)

전 저장소를 연결할 때, origin으로 만들었습니다.

git서버에 push

정상적으로 변경된 branch로 올라간 모습을 확인 할 수 있습니다.

 

 

fork툴을 활용한 git 처리 확인

fork라는 툴을 활용해서 git을 사용하고 있는데 아무래도 gui를 제공하다보니 commit 메시지도 보기 좋고 현재의 브랜치상태나 올린사람등을 쉽게 파악할 수 있어 애용하고 있는 프로그램입니다.

 

이렇게 새로운 브랜치를 만들어서 추가된 것을 볼 수 있습니다.

 

 

브랜치 병합하기(merge)

git merge <commit>

병합을 할 땐, "git merge 브랜치명"의 명령어를 통해 merge합니다.

 

 

git checkout master

지금까지 따라오셨다면 commit의 헤드는 psw에 처리되어 있을텐데, 다시 master로 변경해보겠습니다.

 

 

git merge psw

아까 branch를 변경할땐 checkout이라고 했었죠? master로 브랜치를 바꿨으면 합병을 해보겠습니다.

합병 명령어를 입력합니다.

 

 

그러면 아까 psw에서 처리했던 commit이 합병되는 것을 볼 수 있습니다.

비어있던 index.html

위 캡처처럼 master브랜치의 index.html은 비어있었는데, merge를 하자 아래처럼 바뀌어있습니다.

master 브랜치로 합병

 

master 브랜치로 psw 브랜치에서 처리했던 소스가 합병된 모습을 볼 수 있습니다.

 

 

브랜치 삭제하기

psw의 소스는 합병도 되었고 더이상 쓸모가 없어졌을 경우 브랜치를 지워줘야겠죠?

엄청 많은 브랜치들이 존재하면 어떤건 개발이 끝난거고 어떤건 쓰는건지 구분이 안될 수 있을 것 같습니다.

git branch -d <name>

"git branch -d 브랜치명"을 통해서 브랜치를 삭제 할 수 있습니다.

psw를 삭제해보겠습니다.

 

 

git branch -d psw

psw브랜치 삭제

psw브랜치가 삭제되었습니다. 삭제가 되었는지 브랜치 리스트 확인 명령어를 통해 확인해보겠습니다.

 

 

git branch

master만 남아있다.

잘 삭제되어서 master만 남아있는 모습입니다.

 

 

gui툴인 fork에선 아래처럼 변화가 있습니다.

 

브랜치를 삭제하기 전 mster, psw가 같이 붙어있다.

 

합병으로 인해 브랜치가 지저분하게 붙어있습니다. 삭제 후에는 아래처럼 바뀝니다.

master브랜치만 남아있다.

 

 

여러개의 브랜치 사용하기

여러개의 브랜치 생성하기

psw1, 2를 만들어서 작업하는 상황을 만들어보겠습니다.

git branch psw1
git branch psw2


git checkout psw1

psw1, 2를 만들고 psw1의 브랜치를 사용하도록 하였습니다.

현재 브랜치 리스트

 

 

index2.html 추가

html을 추가하였고, 내부에 간단하게 소스를 작성하였습니다.

이제 서버에 올려보겠습니다.

 

git add .

git commit -m "index2.html 추가"

git push origin psw1

psw1브랜치에서 index2,html 생성 후 commit

psw1브랜치에서 파일을 생성하였고 commit까지 정상적으로 처리하였습니다.

 

psw2브랜치 사용하기

이제 psw2브랜치로 변경해보겠습니다.

git checkout psw2

index2.html이 사라졌다.

브랜치가 변경되었고 생성하였던 index2.html은 사라졌을겁니다. 동일하게 생성해서 psw1브랜치에서 생성했던 소스와 다르게 작성해보세요.

 

파일을 생성하고 소스를 다르게 작성하였다면, 서버에 동일하게 commit을 하겠습니다.

git add .

git commit -m "psw2 branch - index2.html 추가"

git push origin psw2

psw2브랜치에서 commit

 

여기까지 상황을 만들었으니 이제 master에 병합처리를 해보겠습니다.

 

 

여러개의 브랜치 병합과 충돌 발생 해결하기

master브랜치로 checkout합니다.

git checkout master

master 브랜치로 checkout

브랜치를 변경하였으니, 앞에서 배운 merge명령어를 통해 병합해보겠습니다.

 

 

git merge psw1

merge명령어를 통해 합병합니다. psw1의 브랜치부터 했습니다.

psw1브랜치 병합

바로 이어서 psw2브랜치도 병합해보겠습니다.

 

 

git merge psw2

psw2브랜치까지 병합

병합을 하고나면 index2.html이 정상적이지 않은 데이터로 병합된 걸 볼 수 있습니다.

 

충돌이 발생하였다!

바로 충돌이 발생하였기 때문입니다. psw1에서 합병할때는 문제없이 merge 되었을텐데, psw2의 브랜치를 병합하면서 먼저 받았던 index2.html의 소스부분이 서로 꼬였기 때문입니다.

<<<<<<<HEAD부분은 기존의 마스터가 가지고 있던 소스부분이고

=======기준부터

>>>>>>>psw2까지는 psw2의 브랜치를 받으면서 충돌이 발생한 부분입니다.

 

 

지금은 소스가 매우 간단하고 충돌난 부분이 해당 부분밖에 없어서 간단하게 해결이 가능하지만

여러부분이 충돌이 났을 경우엔 모든 충돌 위치를 찾아서 병합할 부분을 고쳐주셔야 합니다.

 

원하는 소스로 병합처리를 하고 소스를 다시 올려보도록 하겠습니다.

소스 병합처리 완료

 

 

git add .

git commit -m "merge end"

git push origin master

merge 종료

정상적으로 처리가 끝났습니다.

 

fork에서 작업내역 확인

gui툴인 fork에서 확인해보면 좀 더 한눈에 작업내역이 보입니다.

psw1브랜치에서 index2.html을 생성하여 소스를 작성하고 올렸고

psw2브랜체에서도 동일하게 생성 후 소스를 올렸으며, master가 병합처리를 끝낸 히스토리를 컴밋 메시지를 통해 볼 수 있습니다.

반응형
반응형

예전에 포스팅한 amchart에서 svg로 표현된 svg파일을 가져와서 svg코드를 수정거나 CSS 변경으로 적용했던 부분을 많이 보러 오시는걸 보고 한국지도를 찾는분들이 많이 계시는걸 알게 되었습니다.

 

이번에는 d3 라이브러리와 맵정보가 담긴 geoJson파일을 읽고 파싱하여 지도의 형태의 도형을 그려 넣을 것입니다. 그려 넣은 지도에 클릭 이벤트, 줌 이벤트 등을 추가할 수 있으며 이를 만들어보겠습니다.

추가적으로 이번엔 웹서버가 필요합니다.

was서버로 유명한 tomcat을 쓰셔도 좋고 간단하게 웹서버를 올릴 수 있는 http-server를 쓰셔도 됩니다. 

 

데이터 시각화를 지원하는 수많은 라이브러리 중에 d3라는 강력한 라이브러리가 있습니다.

데이터를 차트화도 시켜주고 이미지화 지도 등등 다양하게 표현이 가능합니다.

 

특히, 우리가 일반적으로 사용하는 차트형태가 아닌 topology차트와 같은 기하학적인 형태(트리형 표현, 노드 구성도 등)의 차트도 표현이 가능합니다.

 

이렇게 좋은 기능을 제공하는 d3이지만 개인적으로 안좋은 점(?), 힘든점으로 첫 번째 버전업에 따른 변경되는 메소드명, 파라미터등입니다.

버전이 올라감에 따라 과거버전에서 사용된 메소드가 사라지거나 이름이 바뀌는데... 버전 별로 어떤 기능을 쓸 때, 사용해야 하는 메소드명이라던지... 파라미터를 매번 다시 찾아봐야하는 점이 힘듭니다.

두번째는 기능이 많다보니 공식 API문서도 따로 공부를 해야할 정도로 양도 방대하고 영문으로 되어있습니다...(영어를 잘하는분들이 부럽습니다ㅜ.ㅜ) 엄청 깊게 사용해야할게 아니면 따로 공부보단 그때마다 사용해야할 메소드를 찾아서 적용하는편이 나을 것 같습니다.

 

개인적으로 느낀 d3에 대한 설명은 이정도로 하고 진행해보겠습니다.

 

 


d3를 활용한 한국 지도 만들기

 

한국 지도 gif...

만들어볼 한국지도의 UI 형태입니다.

카카오맵이나 구글지도, 오픈레이어스와 같은 형태가 아니니 참고바랍니다.

 

아래는 준비물입니다.

- d3(3.1.7 ver)

- was서버(http-server, node, tomcat등)

- 한국 지도의 데이터가 담긴 geoJSON파일

d3는 3.1.7버전으로 개발을 했었네요... 현재 최신 버전의 d3를 다운받아서 사용하시면 아마 메소드가 충돌나거나 에러가 발생하여 정상적으로 동작하지 않을겁니다.

 

geoJSON파일은 구글링을 하시면 많이 찾으실수 있는데 통계청을 통해 사용하셔도 되고, 아래 URL

https://github.com/vuski/admdongkor

 

vuski/admdongkor

대한민국 행정동 경계 파일. Contribute to vuski/admdongkor development by creating an account on GitHub.

github.com

이분의 github에서 받은 데이터를 QGIC3 툴을 활용하여 잘라서 사용하셔도 됩니다.

실제로 이번포스팅에는 없지만 지역별로 나눠야 하는 작업이 있어서 한국지도를 QGIC3툴로 잘라서 사용했습니다.

 

아래 2개 파일은 과거 d3버전이나, json파일 받는게 어려운 분들을 위해 따로 첨부합니다.

d3.js
0.29MB
korea.json
1.31MB

 


korea.html

<!DOCTYPE html>
<html lang="en" dir="ltr">
    <head>
        <meta charset="utf-8" />
        <title>koreaMap</title>
        <link rel="stylesheet" href="css/korea.css" />
    </head>
    <script type="text/javascript" src="js/d3.js"></script>
    <script type="text/javascript" src="js/korea.js"></script>
    <body>
        <div id="container"></div>
    </body>
</html>

html은 간단합니다. container라는곳에 데이터를 파싱하여 한국 지도를 넣을겁니다.

css는 korea.css라는 파일에서 간단하게 정의할겁니다. hover와 같은 이벤트들~

 

이제 동작을 위해 d3라이브러리를 추가해야겠죠? 소스를 동작시킬 korea.js도 연결하였습니다.

 

korea.css, korea.js를 만들어보겠습니다.

 

korea.css

@charset "UTF-8";

#container {
	width: 700px;
	min-height: 700px;
	float: left;
	margin: 15px 35px;
}
#states path {
	fill: #585858;
	stroke: #000000;
	stroke-width: 1.5px;
}

#states path:hover {
	fill: #009300;
}

#states .active {
	fill: #00B700;
}

#states .activeDetail {
	fill: #00B700;
}

#states path {
	cursor: pointer;
}

#states text {
	cursor: pointer;
	font-size: 12px;
	fill: #fff;
}

지역별 색상과 hover 이벤트 글씨 색상등을 처리했습니다. 이번에도 svg로 그려지기때문에 fill, stroke등의 속성이 사용되었습니다.

 

korea.js

window.onload = function() {
    drawMap('#container');
};

//지도 그리기
function drawMap(target) {
    var width = 700; //지도의 넓이
    var height = 700; //지도의 높이
    var initialScale = 5500; //확대시킬 값
    var initialX = -11900; //초기 위치값 X
    var initialY = 4050; //초기 위치값 Y
    var labels;

    var projection = d3.geo
        .mercator()
        .scale(initialScale)
        .translate([initialX, initialY]);
    var path = d3.geo.path().projection(projection);
    var zoom = d3.behavior
        .zoom()
        .translate(projection.translate())
        .scale(projection.scale())
        .scaleExtent([height, 800 * height])
        .on('zoom', zoom);

    var svg = d3
        .select(target)
        .append('svg')
        .attr('width', width + 'px')
        .attr('height', height + 'px')
        .attr('id', 'map')
        .attr('class', 'map');

    var states = svg
        .append('g')
        .attr('id', 'states')
        .call(zoom);

    states
        .append('rect')
        .attr('class', 'background')
        .attr('width', width + 'px')
        .attr('height', height + 'px');

    //geoJson데이터를 파싱하여 지도그리기
    d3.json('json/korea.json', function(json) {
        states
            .selectAll('path') //지역 설정
            .data(json.features)
            .enter()
            .append('path')
            .attr('d', path)
            .attr('id', function(d) {
                return 'path-' + d.properties.name_eng;
            });

        labels = states
            .selectAll('text')
            .data(json.features) //라벨표시
            .enter()
            .append('text')
            .attr('transform', translateTolabel)
            .attr('id', function(d) {
                return 'label-' + d.properties.name_eng;
            })
            .attr('text-anchor', 'middle')
            .attr('dy', '.35em')
            .text(function(d) {
                return d.properties.name;
            });
    });

    //텍스트 위치 조절 - 하드코딩으로 위치 조절을 했습니다.
    function translateTolabel(d) {
        var arr = path.centroid(d);
        if (d.properties.code == 31) {
            //서울 경기도 이름 겹쳐서 경기도 내리기
            arr[1] +=
                d3.event && d3.event.scale
                    ? d3.event.scale / height + 20
                    : initialScale / height + 20;
        } else if (d.properties.code == 34) {
            //충남은 조금 더 내리기
            arr[1] +=
                d3.event && d3.event.scale
                    ? d3.event.scale / height + 10
                    : initialScale / height + 10;
        }
        return 'translate(' + arr + ')';
    }

    function zoom() {
        projection.translate(d3.event.translate).scale(d3.event.scale);
        states.selectAll('path').attr('d', path);
        labels.attr('transform', translateTolabel);
    }
}

d3사용으로 인해 여러 메소드들이 사용되었습니다.

d3의 메소드들을 다 설명하기엔 너무 길어지므로 공식 홈페이지의 API들이나 다른 예제들을 참조하여 추가해보시면 좋을것 같습니다.

 

지역명을 입력하는 label부분에서 서로 중간지점이 겹쳐서 글자를 제대로 알아보지 못하는 현상이 발생해서 

공통으로 사용하는 trnslateTolabel이라는 함수에서 약간의 커스텀이 처리되었습니다.

 

소스 작성이 완료되었으면 이제 실행을 해봐야겠죠?

웹 서버가 필요합니다!

톰캣같은 was로 개발하고 계신분들은 확인시 문제가 없겠지만 서버없이 html을 실행하게 되면 이런 에러가 발생할겁니다. 처음에 시작할 때 서버가 필요하다고 했었죠?

 

저는 http-server를 활용해서 실행하였습니다.

터미널 창을 열고 프로젝트 디렉토리로 이동해서 http-server를 입력합니다.

터미널에 http-server 입력!

 

enter입력! 서버가 실행되었습니다.

웹서버 실행

별다른 옵션없이 실행하여 기본포트인 8080으로 실행되었습니다.

 

이제 localhost:8080/korea.html을 입력해서 실행해보겠습니다. (127.0.0.1:8080/korea.html)

정상적으로 실행된 모습

 

http-server 설치법 및 사용법은 매우 간단하므로 구글링을 통해 보시고 사용하는것도 추천드립니다.

(추후에 포스팅하게 되면 연결해놓겠습니다.)

 

 

아래 URL의 github를 가시면 지금까지 작성한 소스를 받아보실수 있습니다.

https://github.com/myhappyman/d3_koreaMap

 

myhappyman/d3_koreaMap

Contribute to myhappyman/d3_koreaMap development by creating an account on GitHub.

github.com

반응형
반응형

간단한 HTML, CSS, JAVASCRIPT의 작업을 할 때, 주로 아톰을 사용하다가 리액트 공부를 하면서 VS Code를 알게 되었습니다. 뭔가 더 직관적이고 간편한 UI가 마음에 들어서 요즘엔 주로 사용하는 툴입니다. 아톰의 추가 패키지 설치처럼 VS Code에도 추가 확장 프로그램을 설치 할 수 있습니다.

 

설치방법

좌측 메뉴 중 최하단의 Extensions 메뉴를 클릭하고 찾고자 하는 확장 프로그램을 검색해서 설치하면 됩니다.

단축키 Ctrl + Shift + X

 


확장 프로그램 추천

사용하면서 편리한 확장 프로그램을 알게 되면 계속해서 추가하겠습니다.

 

1. ESLint : 자바스크립트 문법 및 코드 스타일을 검사해줍니다.

 

2. open in browser : html 같은 페이지를 바로 브라우저창에서 키고 싶을 때, 브라우저 연결을 도와줍니다.

 

3. Prettier-Code formatter : 코드 스타일을 자동으로 정리해줍니다.

 

4. HTMLHint : 작성한 HTML 문법에 문제가 있는지 체크해줍니다.

태그가 안닫히거나 올바른 문법이 아니면 경고를 띄워줍니다.

 

5. Reactjs Code Snippets: 리액트를 사용하는분들에게 추천합니다.

함수를 작성하거나 단축 단어를 사용하여 간편하게 코드를 작성할 수 있습니다.

 

6. Korean Language Pack for Visual Studio Code: VS Code를 처음에 설치하시면 영문버전인데 툴을 한글버전으로 사용하고 싶은분들에게 추천합니다. 설치 후 별도의 설정이 필요합니다. 저는 영문버전으로 사용중입니다.

 

반응형
반응형

https://myhappyman.tistory.com/94

 

HTML, JAVASCRIPT - 테트리스 만들기 - 3

https://myhappyman.tistory.com/93 HTML, JAVASCRIPT - 테트리스 만들기 - 2 https://myhappyman.tistory.com/92 HTML, JAVASCRIPT - 테트리스 만들기 - 1(table요소, 배열값으로 테트리스 만들기) 웹 개발을 해..

myhappyman.tistory.com

 

3장에서 키보드 입력 이벤트까지 처리해보았습니다.

 

이번 포스팅에서는 어떤 입력을 받거나 일정시간마다 내려가더라도 테트리스 블럭이 게임 맵을 뚫고 넘어가지 않는 함수를 작성하고 사용하도록 해보겠습니다.

 

isMove()라는 함수를 추가해서, 키 이벤트값이나 setInterval함수에 따라 진행이 되었을때, 벽인지 아닌지 체크 후 boolean값을 리턴하는 함수를 만들어보겠습니다.

 

움직임 제한 함수 추가 isMove()

function isMove(TYPE, TURN, GX, GY){
    TURN = TURN > 3 ? TURN % 4 : TURN;
    for(var i=0; i<4; i++){
        for(var j=0; j<4; j++){
            if(TETRIS[TYPE][TURN][i][j] == 1){ //테트리스의 블럭모양이 나왔는데
                if(MAP[GX+2+i][GY+2+j] != 0){ //닿을곳이 맵이 아니면
                    return false;
                }
            }
        }
    }
    return true;
}

이러한 함수를 추가할겁니다. 파라미터값들에 대해 설명을 하면 아래와 같습니다.

첫번째 파라미터(TYPE)에는 테트리스의 현재 타입값을 넣습니다.

두번째 파라미터(TURN)에는 테트리스의 현재 회전값을 넣습니다.

세번째 파라미터(GX)는 현재 테트리스가 위치한 위아래 위치값 넣습니다.

네번째 파라미터(GY)는 현재 테트리스가 위치한 좌우의 위치값을 넣습니다.

리턴값은 boolean값인 true, false값을 처리합니다.

 

그리고 맵 데이터에서 현재 이동이 가능한 값 0으로 된 데이터인지 체크를하고 0이 아니라면 움직이지 못하도록 false값을 리턴할겁니다.

모든 조건을 통과했을때만 true값이 나와서 동작을 시킵니다.

 

 

isMove()함수에 대해서 좀 더 알아보겠습니다.

숫자 1번키를 눌러서 왼쪽으로 이동한다!

숫자1번(또는 왼쪽으로 이동하는 키)을 눌러서 왼쪽으로 이동한다고 가정을 했을때,

MAP배열 데이터와 테트리스 데이터가 위 그림처럼 되어있을텐데, 여기서 계속해서 이동이 가능한 영역은 회색입니다. 현재 그림을 기준으로 왼쪽으로 2번까진 이동이 가능하겠죠. 테트리스 모양인 'ㄱ'자의 막대는 넘어가면 안되니까요.

 

즉, 현재의 테트리스의 타입과 회전모양을 값으로 받고 TETRIS배열의 0번째부터 끝까지 배열모양을 조사해서 1이라는건 테트리스의 모양이므로 입력한 동작이 움직일수 있는지 없는지 체크하는 조건문이 진행됩니다. 

if(TETRIS[TYPE][TURN][i][j] == 1)

 

전역변수 GX값, GY값은 MAP배열을 기준으로 2만큼씩 안으로 들어가 있기 때문에 MAP데이터를 검사할때 2만큼 추가하였고, 각각 닿는 부위를 체크하기 위해 위아래는 검사하는 GX축에 i값만큼 더하고, 좌우를 검사하는 GY부분에 j만큼 더하였습니다.

if(MAP[GX+2+i][GY+2+j] != 0)

와 같은 조건문이 만들어졌습니다. 0이 아니라는건 맵이 아니기 때문에 return false가 처리되면서 이동을 못하도록 하죠.

 

그럼 이제 실질적으로 isMove()를 써봐야겠죠 키이벤트를 정의했던 myFunction()을 수정해보겠습니다.

 

myFunction함수에 키이벤트에 따른 이동제한 처리

function myFunction(input){
    //그리기 전에 지우기
    erase(GX, TYPE, TURN);
    switch(input){
        case 53://회전
            if(isMove(TYPE, TURN+1, GX, GY)){
                TURN++;
                TURN = TURN % 4;
            }
            break;
        case 49://블럭왼쪽이동
            if(isMove(TYPE, TURN, GX, GY-1)){
                GY--;
            }
            break;
        case 51://블럭오른쪽이동
            if(isMove(TYPE, TURN, GX, GY+1)){
                GY++;
            }
            break;
        case 50://블럭아래로이동
            if(isMove(TYPE, TURN, GX+1, GY)){
                GX++;
            }
            break;
        case 32://스페이스
            while(isMove(TYPE, TURN, GX+1, GY)){
                GX++;
            }
            break;
    }
    //테트리스 블럭 그리기
    drawTetris(GX, TYPE, TURN);
}

3장에서 입력된 키보드 값을 처리할 때 위 방향키를 입력받으면 TURN값을 ++처리하여 증가하거나

왼쪽으로 이동하면 전역변수 GY값을 --시켰는데 이번 포스팅에서는 if문인 조건문이 추가되었습니다.

회전을 하게되면 파라미터값에 현재의 전역변수의 회전값에 +1을 처리한 값을 넣고 움직일 수 있는지 없는지 체크합니다. 조건이 만족되면 그때서야 TURN의 전역변수 값을 ++하여 증감해줍니다.

 

왼쪽으로 이동할땐, 좌우를 처리하는 GY값에 -1을 처리하고 왼쪽으로 이동이 가능한지 아닌지 체크합니다.

마찬가지로 조건이 만족되었을때만 GY--처리를 합니다.

 

스페이스값은 아래로 이동하는것을 더이상 진행이 불가할때까지 처리해주면 됩니다.

while문을 통해 처리하였고 이동을 못하면 false값이 나오니 자연스럽게 빠져오겠죠.

 

이제 마지막으로 action()함수의 setInterval부분을 추가하겠습니다.

일정시간마다 자연스럽게 내려가다보니 일정시간이 지나면 제한이 없어서 뚫고 지나가게 됩니다.

 

 

action() 함수의 일정시간마다 동작하는 setInterval() 이동제한 추가

function action(){
    //keyEvent
    document.addEventListener("keypress", function(){
        myFunction(event.keyCode);
    });

    var intervalID = setInterval(function(){
        erase(GX, TYPE, TURN); //생성한 전위치 블럭 삭제
        if(isMove(TYPE, TURN, GX+1, GY)){
            GX++; //한줄씩 내리기
        }
        drawTetris(GX, TYPE, TURN); //테트리스를 그린다.
    }, GAME_SPEED);
}

키 이벤트부분과 유사합니다.

먼저 현재의 블럭을 지워주고 아래로 이동하는 키값이 강제로 입력되었다고 생각하시면 됩니다.

아래 위값을 제어하는 GX값이 증가하였다고 생각하고 isMove()함수를 통해 체크합니다.

 

그러면 더이상 맵을 뚫고 블럭이 사라지는 일은 없을 겁니다.

더이상 벽을 뚫고 들어가지 않는다.

 

여기까지 동작하는 소스를 한번 올리도록 하겠습니다.

 

아래의 ZIP파일을 받아주시면 됩니다.

tetris_v3.zip
0.00MB

반응형
반응형

https://myhappyman.tistory.com/93

 

HTML, JAVASCRIPT - 테트리스 만들기 - 2

https://myhappyman.tistory.com/92 HTML, JAVASCRIPT - 테트리스 만들기 - 1(table요소, 배열값으로 테트리스 만들기) 웹 개발을 해보겠다고 예전에 학원을 다니면서 강사님과 같이 만들어봤던, 테트리스 예제가..

myhappyman.tistory.com

2장 이후 3장까지 왔습니다. 이번에는 키 이벤트를 처리해보겠습니다.

 

3. 키 이벤트에 따라 테트리스 제어하기

이번에는 키 이벤트를 받아서 테트리스를 제어해보겠습니다.

 

2장에서 만들었던 action 메소드에 keypress 이벤트를 추가하겠습니다.

keypress 처리

function action(){
    //keyEvent
    document.addEventListener("keypress", function(){
        myFunction(event.keyCode);
    });
}

특정 키값을 받을때마다 파라미터 값으로 myFunction에 파라미터로 넘겨주고 그에 따라 동작을 정의할 것입니다.

 

myFunction - 입력값에 따른 출력 메시지

function myFunction(input){
    switch(input){
        case 53://회전
            console.log("5번이 입력되었습니다.");
            break;
        case 49://블럭왼쪽이동                        
            console.log("1번이 입력되었습니다.");
            break;
        case 51://블럭오른쪽이동            
            console.log("3번이 입력되었습니다.");
            break;
        case 50://블럭아래로이동            
            console.log("2번이 입력되었습니다.");
            break;
        case 32://스페이스
            console.log("스페이스바가 입력되었습니다!");
            break;
    }
    //테트리스 블럭 그리기
    drawTetris(GX, TYPE, TURN);
}

 

action 함수에서 키이벤트를 추가했기 때문에 키보드 입력값이 들어오면 myFunction이 실행될텐데 이제 파라미터 input값에 따라 switch문에서 동작을 시켜줄겁니다.

저는 우측 키보드로 게임을 즐긴다고 생각하고 키 세팅을 했는데, 이 부분은 원하시는 키값으로 하시면 됩니다.

키 세팅

 

키 입력을 정상적으로 받아진다.

실행 후 키보드를 입력해보면 블럭은 움직이지 않지만 키보드 입력에 따라 콘솔로그값이 찍히는 모습을 볼 수 있습니다.

 

이제 입력값에 따라 실제로 이동이 되거나 블록을 회전시키거나 맨 아래로 이동시켜야겠죠?

바로 동작을 처리해보겠습니다.

회전, 스페이스바, 이동 시키기

function myFunction(ChangeValue){
    switch(ChangeValue){
        case 53://회전
            TURN++;
            TURN = TURN % 4;
            break;
        case 49://블럭왼쪽이동
            GY--;
            break;
        case 51://블럭오른쪽이동
            GY++;
            break;
        case 50://블럭아래로이동            
            GX++;
            break;
        case 32://스페이스
            GX=21;
            break;
    }
    //테트리스 블럭 그리기
    drawTetris(GX, TYPE, TURN);
}

53은 윗 방향을 누르는 키값으로 회전이 되어야 합니다. 즉, TURN의 값을 증가시키고 그리면 됩니다.

하지만 %연산자가 있는것을 볼 수 있는데, 존재하는 이유는 회전은 4가지의 모습이 있기 때문입니다.

 

맨 처음 시작할때 추가하였던 tetris_data.js에서 TETRIS 변수 중 ㄹ모양의 블럭을 예시로 볼 경우

ㄹ 모양 4가지 회전

이렇게 4가지 형태를 볼 수 있습니다.

이러한 이유때문에 모든 블럭을 4가지 형태로 넣었고, ㅁ모양의 블럭도 4가지인 이유입니다.

 

실행해서 해보면 일정시간마다 블럭이 내려가게 했을 때처럼 이전 블럭의 잔상이 남는 것을 볼 수 있는데, 눈치채신분들은 여기서 지우는 함수를 넣으면 된다는것을 알 수 있을겁니다.

키 이벤트에 따라 변경되지만 잔상이 남는다.

 

erase함수를 역시 처음에 추가해보겠습니다.

 

그럴싸한 myFunction - erase함수까지 추가

function myFunction(input){
    //그리기 전에 지우기 추가!!!
    erase(GX, TYPE, TURN);
    switch(input){
        case 53://회전
            TURN++;
            TURN = TURN % 4;
            break;
        case 49://블럭왼쪽이동
            GY--;
            break;
        case 51://블럭오른쪽이동
            GY++;
            break;
        case 50://블럭아래로이동            
            GX++;
            break;
        case 32://스페이스
            GX=21;
            break;
    }
    //테트리스 블럭 그리기
    drawTetris(GX, TYPE, TURN);
}

 

아직 완벽하진 않지만 그럴싸하게 키 이벤트도 받고 동작이 되는 모습을 볼 수 있습니다.

 

 

다음 포스팅에서는 마지막행에 닿으면 현재 블럭의 이벤트가 멈추고 다음블럭으로 넘어갈 수 있게 추가해보겠습니다.

 

반응형
반응형

https://myhappyman.tistory.com/92

 

HTML, JAVASCRIPT - 테트리스 만들기 - 1(table요소, 배열값으로 테트리스 만들기)

웹 개발을 해보겠다고 예전에 학원을 다니면서 강사님과 같이 만들어봤던, 테트리스 예제가 있어서 약간의 소스 정리 후 포스팅을 하면 좋을 것 같아 테트리스 만들기 예제를 시작합니다. 테트리스 만들기 예제들..

myhappyman.tistory.com

 

테트리스 만들기 1장 이후 2장입니다.

 

테트리스 구조를 만들고 맵을 만들었으니 이제 테트리스 다운 동작을 만들어야 할 것같습니다.

 

이번엔 index.js에 action()이라는 함수를 추가해서 일정 시간마다 자연스럽게 내려가는 동작을 추가해보겠습니다.

여기서 일정시간마다 동작한다. 라는 부분에서 떠오르는 함수가 있으신가요? setInterval 또는 setTimeout, animationFrame등이 생각 날 것 같습니다. 저는 setInterval을 활용해서 처음에 정의한 gamespeed의 변수값마다 동작하도록 작성했습니다.

 

2. 일정시간마다 블럭이 떨어지는 효과 만들기

index.js - action()

window.onload = function(){
    drawMap();
    drawNextTetris(Ntype);
    myFunction();
    action(); //action 함수 추가
}

/**
 * 동작 메소드
 * interval 함수로 입력시간마다 동작
 * (gameSpeed에 따라 떨어지는 속도가 변경)
 */
function action(){

    var intervalID = setInterval(function(){
        console.log("action!")
        GX++;
        drawTetris(GX, TYPE, TURN);
    }, GAME_SPEED);
}

window.onload 맨 끝에 action함수를 추가하여 페이지가 로드되면 action함수가 실행되도록 처리하였습니다.

 

action 함수 내부를 보니 Interval함수에 의해 GAME_SPEED값마다 콘솔로그값을 출력 후 GX전역 변수값을 증가시킨 후에 drawTetris 함수를 호출하는 것을 볼 수 있습니다.

 

 

drawTetris함수는 현재 선택된 테트리스의 값을 특정 위치에 그려주는 함수 입니다.

특정 위치를 그려주므로 일정 시간마다 우리는 위에서 아래로 떨어지는 모습을 위해 GX변수값을 증가시켜주면 자연스럽게 밑으로 계속해서 그려줄 것입니다.

 

 

 

하지만 계속 그려주게되면 이전 모습이 남아있어 이러한 형태로 잔상이 있겠죠?

이제 잔상을 지워주는 함수를 만들겠습니다.

 

 

erase 함수

한줄씩 내리면서 특정위치를 지우기전에 현재 위치의 테트리스 블럭값을 확인하고 지우는 erase 함수를 만들어보겠습니다.

//특정 지역을 map으로 초기화 (block값으로 되어있던걸 map으로)
function erase(GX, TYPE, TURN){
    for(var x=0; x<TETRIS[BLOCKTYPE][BLOCKROTATE].length; x++){
        for(var y=0; y<TETRIS[BLOCKTYPE][BLOCKROTATE][x].length; y++){
            if(TETRIS[TYPE][TURN][x][y]==1){
                ChangeColor(x+GX, y+GY, "map");
            }
        }
    }
}

function action(){
    var intervalID = setInterval(function(){
        erase(GX, TYPE, TURN); //생성한 전위치 블럭 삭제
        GX++; //한줄씩 내리기
        drawTetris(GX, TYPE, TURN); //테트리스를 그린다.
    }, GAME_SPEED);
}

 

현재의 테트리스 모양과 회전위치값을 가지고 와서 1이면 블럭모양이므로 1인지 체크 후에 블럭모양이라면 erase함수에서는 map이라는 클래스를 넣어 모두 맵으로 바꿔줍니다.

 

그럼 아래와 같이 지우면서 그리기 때문에 테트리스처럼 보이게 되죠.

 

지우면서 그려진다.

반응형
반응형

웹 개발을 해보겠다고 예전에 학원을 다니면서 강사님과 같이 만들어봤던, 테트리스 예제가 있어서 약간의 소스 정리 후 포스팅을 하면 좋을 것 같아 테트리스 만들기 예제를 시작합니다.

 

테트리스 만들기 예제들을 찾아보면 캔버스값으로 처리하는 예제들이 많던데, 아직 캔버스 사용이 쉽지는 않은터라 게임치고는 UI가 엄청 화려하게 변화는 없는 테트리스정도는 html의 간단한 요소들로 충분히 표현이 가능하고 jquery나 다른 화려한 플러그인 없이 순수 javascript만으로 로직을 구성해서 표현할 수 있는 테트리스를 선택하게 되었습니다.

크게 구분하자면 배열데이터를 조작하고 매번 배열의 데이터를 검사하여 table요소를 통해 UI를 표현하는 형태로 진행할 예정입니다.

 

 

 


1. 작성을 위해 페이지 구성 & 배열 데이터 만들기 맵 그리기

 

페이지별 구성도

이러한 형태로 페이지들을 구성할 예정입니다.

메인이될 index.html 페이지

css를 꾸며줄 index.css

동작처리를 위한 index.js

전체 맵데이터, 테트리스 모양데이터를 담아놓을 tetris_data.js 로 구성하여 소스를 작성하겠습니다.

 

각각 소스들을 보도록 하겠습니다.

 

index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="./css/index.css">
    <title>Tetris</title>
    <script src="./js/tetris_data.js"></script>
    <script src="./js/index.js"></script>
</head>
<body>
    <div id="container"></div>
</body>
</html>

사용할 index.html은 1개입니다.

tetris_data.js라는곳에는 전역으로 처리할 맵 배열과 테트리스 모양배열을 담아두고 실질적으로 돌아가는 코드 동작은 index.js에서 처리할 예정입니다.

 

tetris_data.js

//맵
var MAP=[
    [4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4],       
    [4,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,2,2,2,2,2,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,2,2,2,2,2,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,2,2,2,2,2,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,2,2,2,2,2,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,2,2,2,2,2,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4],
    [4,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4],
    [4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4]];

//테트리스 조각
var TETRIS=[
    [
        [//막대기
            [0,0,0,0],
            [1,1,1,1],
            [0,0,0,0],
            [0,0,0,0]
        ],
        [
            [0,1,0,0],
            [0,1,0,0],
            [0,1,0,0],
            [0,1,0,0]
        ],
        [
            [0,0,0,0],
            [1,1,1,1],
            [0,0,0,0],
            [0,0,0,0]
        ],
        [
            [0,1,0,0],
            [0,1,0,0],
            [0,1,0,0],
            [0,1,0,0]
        ]
    ],
    [
        [//ㄹ1
            [0,1,0,0],
            [0,1,1,0],
            [0,0,1,0],
            [0,0,0,0]
        ],
        [
            [0,0,1,1],
            [0,1,1,0],
            [0,0,0,0],
            [0,0,0,0]
        ],
        [
            [0,1,0,0],
            [0,1,1,0],
            [0,0,1,0],
            [0,0,0,0]
        ],
        [
            [0,0,1,1],
            [0,1,1,0],
            [0,0,0,0],
            [0,0,0,0]
        ]
    ],
    [
        [//ㄹ2
            [0,0,1,0],
            [0,1,1,0],
            [0,1,0,0],
            [0,0,0,0]
        ],
        [
            [0,1,1,0],
            [0,0,1,1],
            [0,0,0,0],
            [0,0,0,0]
        ],
        [
            [0,0,1,0],
            [0,1,1,0],
            [0,1,0,0],
            [0,0,0,0]
        ],
        [
            [0,1,1,0],
            [0,0,1,1],
            [0,0,0,0],
            [0,0,0,0]
        ]
    ],
    [
        [//ㄱ
            [0,1,1,0],
            [0,0,1,0],
            [0,0,1,0],
            [0,0,0,0]
        ],
        [
            [0,0,0,1],
            [0,1,1,1],
            [0,0,0,0],
            [0,0,0,0]
        ],
        [
            [0,1,0,0],
            [0,1,0,0],
            [0,1,1,0],
            [0,0,0,0]
        ],
        [
            [0,1,1,1],
            [0,1,0,0],
            [0,0,0,0],
            [0,0,0,0]
        ]
    ],
    [
        [//ㄴ
            [0,1,1,0],
            [0,1,0,0],
            [0,1,0,0],
            [0,0,0,0]
        ],
        [
            [0,1,0,0],
            [0,1,1,1],
            [0,0,0,0],
            [0,0,0,0]
        ],
        [
            [0,0,1,0],
            [0,0,1,0],
            [0,1,1,0],
            [0,0,0,0]
        ],
        [
            [0,1,1,1],
            [0,0,0,1],
            [0,0,0,0],
            [0,0,0,0]
        ]
    ],
    [
        [//ㅁ
            [0,1,1,0],
            [0,1,1,0],
            [0,0,0,0],
            [0,0,0,0]
        ],
        [
            [0,1,1,0],
            [0,1,1,0],
            [0,0,0,0],
            [0,0,0,0]
        ],
        [
            [0,1,1,0],
            [0,1,1,0],
            [0,0,0,0],
            [0,0,0,0]
        ],
        [
            [0,1,1,0],
            [0,1,1,0],
            [0,0,0,0],
            [0,0,0,0]
        ]
    ],
    [
        [//ㅗ
            [0,0,1,0],
            [0,1,1,1],
            [0,0,0,0],
            [0,0,0,0]
        ],
        [
            [0,0,1,0],
            [0,0,1,1],
            [0,0,1,0],
            [0,0,0,0]
        ],
        [
            [0,0,0,0],
            [0,1,1,1],
            [0,0,1,0],
            [0,0,0,0]
        ],
        [
            [0,0,1,0],
            [0,1,1,0],
            [0,0,1,0],
            [0,0,0,0]
        ]
    ]
];

- 전역변수 MAP 배열에 테트리스 맵 데이터를 담아놓고 그릴 배열입니다.

  > 2차원 배열

  > 4의 값은 게임의 보드를 표현할 값입니다.

  > 3은 테트리스 가이드 라인으로 처리할 값입니다.

  > 2번은 다음 테트리스 블럭을 표현할 테트리스맵으로 검은 배경을 처리할 값입니다.

  > 0번은 테트리스 블럭이 돌아다니는 테트리스맵으로 검은 배경을 처리할 값입니다.

 

- 전역변수 TETRIS는 테트리스 게임의 블럭들을 담아놓는 배열입니다. ㅡ, ㄱ, ㄴ, ㄹ, ㅁ, ㅗ 형태의 블럭을 회전 4회의 모양별로 담아두었습니다.

  > 3차원 배열[첫번째][두번째][세번째]

  > 첫번째 인덱스의 값은 테트리스의 모양을 구분합니다.

  > 두번째 인덱스의 값은 테트리스의 회전을 구분합니다.

  > 세번째 인덱스의 값은 맵의값인지 블럭의값인지 구분합니다.

 

index.js

맵과 테트리스의 블럭들을 그려봐야겠죠?

실질적으로 동작을 정의할 자바스크립트입니다.

var GX = 0; //블럭을 생성할 초기 위치 X
var GY = 3; //블럭을 생서할 초기 위치 Y
var NGY = 17;
var TURN = 0;
var TYPE = Math.round(Math.random()*6);
var NTYPE = Math.round(Math.random()*6);
var BLOCKTYPE=6, BLOCKROTATE=3;
var GAME_SPEED = 2000;
 
window.onload = function(){
    drawMap();
    drawNextTetris(NTYPE);
    myFunction();
}

function drawMap(){
    var rowLen = MAP.length;
    var tag = "<table>";
    var x = 0;
    var y = 0;
    for(var i=0; i<rowLen; i++){
        tag += "<tr>"
        var colLen = MAP[i].length;
        for(var j=0; j<colLen; j++){
            var className = "";
            var idValue = "";
            if(MAP[i][j] == 0){
                className = "map";
                idValue = "x"+(i-2)+"y"+(j-2);
            }else if(MAP[i][j] == 2){
                className = "map";
                idValue = "xn"+(i-1)+"yn"+(j-16);
            }else if(MAP[i][j] == 3){
                className = "guard";
            }else if(MAP[i][j] == 4){
                className = "board";
            }

            if(idValue != ""){
                tag += "<td id="+idValue+" class="+className+"></td>"
            }else{
                tag += "<td class="+className+"></td>"
            }
            
        }
        tag += "</tr>"
    }
    document.getElementById("container").innerHTML = tag + "</table>";
};

function ChangeColor(x, y, cN){
    document.getElementById("x"+x+"y"+y).className = cN;
}

//다음에 그려질 방향의 테트리스 그리기
function drawNextTetris(NTYPE){
    for(var x=0; x<4; x++){
        for(var y=0; y<4; y++){
            if(TETRIS[NTYPE][0][x][y] == 1){
                ChangeColor("n"+(x+1), "n"+y, "block"+NTYPE);                
            }
        }
    }
}

//테트리스 그리기
function drawTetris(GX, TYPE, TURN){
    for(var x=0; x<TETRIS[BLOCKTYPE][BLOCKROTATE].length; x++){
        for(var y=0; y<TETRIS[BLOCKTYPE][BLOCKROTATE][x].length; y++){
            if(TETRIS[TYPE][TURN][x][y] == 1){
                ChangeColor(x+GX, y+GY, "block"+TYPE);
            }
        }
    }
}

//동작을 초기화하고 입력값에 따라 그려줄 함수
function myFunction(input){
    //테트리스 블럭 그리기
    drawTetris(GX, TYPE, TURN);
}

drawMap이라는 함수는 페이지가 로드되면 실행되면서 MAP배열의 값을 불러와서 table을 그리고 각각 td값에 알맞는 클래스값을 지정하여 테트리스 게임의 맵처럼 표출시키는 함수 입니다.

ChangeColor함수는 전달받은 x,y같에 따라 클래스명을 처리해줍니다.

drawNextTetris는 다음으로 그려질 블럭을 그리는 함수입니다.

drawTetris함수는 테트리스 블럭을 특정 위치에 그리는 함수 입니다.

myFunction은 현재 기능적으로 정의된게 없지만 추후에 동작 정의나 초기값 설정등을 처리할 함수입니다.

 

index.css

마지막으로 디자인을 입혀야 게임다운 느낌이 들겠죠? index.css입니다.

table{
    margin: auto;
    border-collapse: collapse;
}

td{
    width: 18px;
    height: 18px;
    text-align:center;
    vertical-align:middle;
    outline: 0.5px solid #EAEAEA;
}

.board{
    background-color: #5f3dc4;
}
.guard{
    background-color: #91a7ff;
}
.map{
    background-color: #495057;
}
.ghost{
    background-color: #495057;
}

.block0{
    background-color: #f5f100;
}
.block1{
    background-color: #e64980;
}
.block2{
    background-color: #ae3ec9;
}
.block3{
    background-color: #7048e8;
}
.block4{
    background-color: #4263eb;
}
.block5{
    background-color: #1098ad;
}
.block6{
    background-color: #37b24d;
}
.block7{
    background-color: #f59f00;
}

 

css까지 작성하시고 페이지를 열어보시면 이러한 기본 준비가 완성되어 있을겁니다.

 

 

다음장부터는 index.js에서 정의 동작을 수정하고 추가하면서 진행하다보면 어느새 완성된 테트리스를 만나볼 수 있을겁니다. 계속해서 진행해보겠습니다.

반응형