본문 바로가기

Web Development/Front-end

[Zerocho-08] 가위바위보 (이미지스프라이트 & Object & setInterval & querySelectorAll)

안녕하세요 어느새 게임을 8개나 만들어봤네요 ㅎ_ㅎ!

가위바위보를 게임을 마지막으로 Javascirpt - 초급(응용)편은 종료됩니다.

구성이 어떤지 간략히 목차를 나열해보겠습니다.

[초급]

- 끝말잇기게임 (JS 기초 총정리)

- 별찍기 (반복문 연습)

- 화면구현 (window & DOM)

- 구구단게임 (Math & 형변환)

- 숫자야구게임 (배열)

- 틱택토게임 (이차원배열)

- 로또게임(querySelector & 배열주요메소드)

- 가위바위보(이미지스프라이트/setTimeout&Interval&ClearTimeout&Object & querySelectorAll)

[중급]

- 지뢰찾기 (스코프&클로저&렉시컬스코프&재귀)

- 반응속도테스트게임 (호출스택, 재귀&비동기와 호출스택)

- 틱택토 개량버전 (리펙토링 & 무승부)

- 카드 짝맞추기 (참조와 복사&깊은복사 & 팩토리패턴 & 프로토타입)

- 자스스톤 (call by ~ & creator , new )

- 2048 (mousedown, up, move & 드래그)

- 테트리스 (keyup , down, press, 호출스택 & 이벤트루프 & ES6 const, let, Arrow Function)

이런 식으로 포스팅이 진행될 예정입니다.

 

이번시간 까지 따라오시면서, 어려우셨던 분들은 한번 다시 처음부터 복습하시면서 익숙해지신 뒤에 다음 과정으로 넘어가시면 좋습니다.

 

아무튼, 이번시간에 배워볼 게임은 가위바위보입니다.

이 게임에서 등장하는 새로운 개념은 '이미지 스프라이트', 'setTimeout', 'setInterval', 'clearTimeout', 'Object(딕셔너리, 객체)' 등 이 주로 등장합니다. 그리고 이전에 사용했던 querySelector을 한번에 여러개를 선택하는 선택자 querySelectorAll 도 등장합니다!

 

우선 가위바위보 게임이 어떤 게임인지 누구나 아시겠지만,

우리가 구현할 가위바위보 게임이 어떻게 생겼는지 한번 간략히 영상으로 살펴보고 시작하겠습니다!

 

가위바위보 게임

우리가 기존에 알고있는 게임과 비슷하죠?

컴퓨터가 가위-바위-보 를 반복해서 .001초마다 바꿔주고, 우리는 가위-바위-보 중 하나를 선택해서 내면,

컴퓨터와의 결과를 비교해서 승리 - 패배 - 무승부 를 결정하는 게임입니다.

 

1. 순서도

가위바위보 게임 순서도

컴퓨터가 가위 -바위- 보를 돌아가면서 출력하고,

사용자는 그 가위-바위-보 중 원하는 버튼을 클릭한 뒤,

승리,패배, 무승부 결과에 대해 출력하고,

다시 게임이 반복되는 방식으로 만들어집니다.

 

2. 코드분석

rps(rockpaperscissor).html파일을 생성한 뒤, 다음과 같이 코드를 작성합니다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>가위바위보!</title>
    <style>
        #computer{
            width: 150px;
            height: 243px;
            background:url('https://en.pimg.jp/023/182/267/1/23182267.jpg') 0px 0px;
        }
    </style>
</head>
<body>
    <div id="computer"></div>
    <div>
        <button id='scissor' class='btn'>가위</button>
        <button id='rock' class='btn'>바위</button>
        <button id='paper' class='btn'>보</button>
    </div>
    <script src='test.js'></script>
</body>
</html>
</html>

1. 컴퓨터가 이미지를 출력할, <div id=computer> 부분을 하나 만들어주고,

2. 사용자가 누를 버튼 3개(가위바위보)를 만들어줍니다. 그리고 각각의 아이디값을 부여하고, class값은 모두 동일하게 btn으로 지정해줬습니다. querySelectorAll을 이용해 세가지 버튼을 모두 선택하기 위함에서 class를 통일시켰습니다.

3. 그리고 text.js를 임포트해왔습니다. (저는 이미 rps.js)파일을 만들어봐서, 포스팅할때는 따로 파일을 만들어서 실행하기에 파일명이 다릅니다.

4. 위쪽에 style 부분을 보시면, css로 div<id=computer>태그를 선택해주고, 컴퓨터가 출력할 창의 크기를 조절해준뒤, 이미지를 url로 가져 왔습니다. 맨 마지막 0px 0px 은 이미지 위치입니다. 첫번째 0px은 좌우값이며, 두번째 0px은 상하값입니다.

 

*여기서잠깐 ! 이미지 스프라이트를 할건데요. 이게 무엇인지 잠깐 살펴보죠.

개념은 큰 이미지 속에 여러 이미지가 있다고 가정하면 중, 원하는 사진이 있는 부분만을 사용하는 것입니다. 좌우, 상하 px값을 이용해서 말이죠. (동영상 참조)

 

이미지 스프라이트

그럼, 바위의 위치는 0 0 이며, 가위는 -142 0이고, 보는 -284 0입니다.

그럼 이제 js 작성을 시작해보겠습니다.

var left = 0;

setInterval(function(){
    document.querySelector('#computer').style.background =
'url(https://en.pimg.jp/023/182/267/1/23182267.jpg)'+left+ ' 0';
}, 100);

위에서 정적으로 되어있는 0px 0px 이미지 위치값을 동적으로 하기위해서는 자바스크립트를 이용해야겠죠?

1. 그래서, 위처럼, querySelector를 통해, #computer 태그를 지정해주고, style background를 자바스크립트 값으로 선언해줬습니다.

*여기서 주의점 0 과 0 사이를 띄어줘야하므로, left 뒤에 ' 0' (앞에 한칸을 준 0) 이렇게 작성해줬습니다.

2. 그리고, 0px 0px 부분에서 좌우를 담당하는 앞에 0px부분을 동적으로하기위해 left라는 변수로 할당해줬습니다.

3. setInterval이라는 함수가 등장합니다.

setInterval은 설정한 시간간격마다, 계속 실행해주는 함수를 의미하며, 일정 시간 후 한번 실행하는 setTimeout과 차이가 있습니다.

setInterval(실행함수, 시간간격) << 이런형태로 구성되어있습니다. 그래서, 위처럼 코드를 짜면, 0.1초마다 한번씩 이미지를 출력하는 코드가 실행됩니다. 이제, 이미지 좌우값을 계속 바꿔주게 함으로써, 0.1초마다 이미지를 바꿔줄 수 있도록 해봅시다.

 

var left = 0;
setInterval(function(){
    if(left === 0){
        left = '-142px';
    } else if (left === '-142px'){
        left = '-284px';
    } else {
        left = 0;
    }
    document.querySelector('#computer').style.background =
    'url(https://en.pimg.jp/023/182/267/1/23182267.jpg)'+ left + ' 0';
}, 100);

이런식으로 작성했습니다.

만약, left가 0 이면 -142px 로 변경시켜주고 실행하도록하고, 다음번 실행에서는 -142로 대입될 것이므로 이를 -284로 대입하도록, 그리고 -284가되면 다시 0으로 대입하도록 만들어줬습니다. (토글)

그럼 이미지가 0.1초마다 계속 0 -> -142 -> -284 이런 순으로 left부분이 변화하면서 이미지가 가위, 바위, 보를 출력하는것으로 계속 변화하는 것을 확인 할 수 있습니다.

 

그럼 이제 가위바위보 버튼을 각각 클릭할 수 있도록 해봅시다.

var left = 0;
setInterval(function(){
    if(left === 0){
        left = '-142px';
    } else if (left === '-142px'){
        left = '-284px';
    } else {
        left = 0;
    }
    document.querySelector('#computer').style.background =
    'url(https://en.pimg.jp/023/182/267/1/23182267.jpg)'+ left + ' 0';
}, 100);


//가위바위보 버튼선택
document.querySelectorAll('.btn').forEach(function(rpsbtn){
    rpsbtn.addEventListener('click', function(){
        console.log(this.textContent, left);
    })
})

1. querySelectorAll을 이용해서, 아까 HTML 에서 작성한 세가지 버튼의 동일한 class 세개를 동시에 선택했습니다. 하지만, 이렇게 하면 컴퓨터입장에서는 세개의 버튼인데 어떤걸 선택하라는지 모르겠죠? 그래서 querySelectorAll에서 지원하는 forEach를 이용해서 각각의 버튼을 동시에 선택해줍니다. 그리고 그 값은 rpsbtn(rock_paper_secissor_button의 약자)를 이용해서 잡아줬습니다.

2. 그렇게 잡아준 rpsbtn에다가 이벤트리스너를 추가해 클릭이벤트를 줍니다. 일단은 잘 클릭되는지 확인을 위해, 텍스트만 출력해보도록 하겠습니다. console.log 후에 this.textContent를 줬습니다. this는 말 그대로, 현재 선택한 버튼을 의미하며 그것의 textContent <<를 출력하는 것을 의미합니다.

3. 또 현재 우리가 버튼을 눌렀을 때 동시에, 컴퓨터가 0.1초마다 바뀌는 가위바위보 중에서 어떤 것을 냈는지 확인하기위해서 left값도 줘봤습니다.

 

이제 콘솔창을 켠 뒤, 각각의 버튼을 클릭해보세요. 그럼 각 버튼의 textContent인, 가위, 바위, 보 가 출력되는 것과, 컴퓨터가 left값을 어떤것을 가지고 있는지(즉, 어떤것을 냈는지) 확인할 수 있습니다.

 

그런데 협업을 위한 코드는 최대한 알아보기 쉬운 변수명과, 적시적소에 맞는 자료구조를 활용한 코드로 알아보기 쉽게 짜주는 코드가 좋은코드입니다. 따라서 Object 자료구조를 활용하고, 변수명을 조금 바꿔줘서 이에 맞게 코드를 조금 바꿔 주도록하겠습니다. 여기서 Object가 등장합니다.

 

var img_location = '0';

//Object 사전식 자료구조. 1:1 매칭시 사용.
var rps_dictionary = {
    rock : '0',
    scissor : '-142px',
    paper : '-284px'
}

//위 자료구조를 활용해 코드를 수정합니다.
setInterval(function(){
    if(img_location === rps_dictionary.rock){
        img_location = rps_dictionary.scissor;
    } else if (img_location === rps_dictionary.scissor){
        img_location = rps_dictionary.paper;
    } else {
        img_location = rps_dictionary.rock;
    }
    document.querySelector('#computer').style.background =
    'url(https://en.pimg.jp/023/182/267/1/23182267.jpg)'+ img_location + ' 0';
}, 100);


document.querySelectorAll('.btn').forEach(function(rpsbtn){
    rpsbtn.addEventListener('click', function(){
        var my_choice = this.textContent;
        console.log(my_choice, img_location);
    })
})

변수명은 자신이 혹은 남이봤을 때 가독성 좋게 짜주시면됩니다. 저는 이런식으로 짯어요.

1. left 는 딱 저걸 봤을 때 뭐가 왼쪽인건지 이해가 안되요. 우리만 알 수 있죠 따라서, 이미지 위치라는 의미의 img_location으로 변경해줬습니다.

2. 그리고 rps_dictionary가 등장하는데요. object 객체를 활용해서 자료구조를 만들어줬습니다.

묵은 0 가위는 -142 그리고 보는 -284로요. 그것을 이제 아래 setInterval 부분에 값에 맞게 적용시켜줬습니다. dictionary(Object)값을 읽어올 때는 위와 같이 Object명.key값 을 입력해주면, key에 맞는 value값이 return됩니다.

3. 그리고 아래로 내려가서, this.textContent를 내가 선택한 버튼이니깐, my_choice라는 이름으로 변수를 설정해주고, 이를 console에 입력하는것으로 변경했습니다. 그리고 left 부분도 변수명을 변경함으로써 img_location으로 바꿔줬습니다.

 

이제 컴퓨터가 입력한 img_location 부분도, 숫자가 아닌 문자로 출력되어 코드 뿐만아니라 콘솔에서도 조금 더 가독성 좋게 만들어봅시다.

var img_location = '0';

//Object 사전식 자료구조. 1:1 매칭시 사용.
var rps_dictionary = {
    rock : '0',
    scissor : '-142px',
    paper : '-284px'
}
//컴퓨터가 선택을 보기위한 거꾸로 만든 dictionary
var op_rps_dictionary = {
    '0': '바위',
    '-142px' : '가위',
    '-284px' : '보',
}

setInterval(function(){
    if(img_location === rps_dictionary.rock){
        img_location = rps_dictionary.scissor;
    } else if (img_location === rps_dictionary.scissor){
        img_location = rps_dictionary.paper;
    } else {
        img_location = rps_dictionary.rock;
    }
    document.querySelector('#computer').style.background =
    'url(https://en.pimg.jp/023/182/267/1/23182267.jpg)'+ img_location + ' 0';
}, 100);


document.querySelectorAll('.btn').forEach(function(rpsbtn){
    rpsbtn.addEventListener('click', function(){
        var my_choice = this.textContent;
        console.log(`내 선택 => ${my_choice} // 컴퓨터 선택 => ${op_rps_dictionary[img_location]}`);
    })
})

op_rps_dictionary라는 Object를 선언하고, 위 rps_dictionary를 거꾸로 만든 뒤, 출력값(value)부분을 한글로 적어줬습니다.

그리고, 이를 출력하는 맨 아래 부분 콘솔에서 예쁘게 출력되도록 위와 같이 문구를 바꿔줬습니다.

이렇게하면 이제 콘솔창에 예쁘게 출력되는것을 확인하실 수 있겠죠?

근데 같은 객체를 거꾸로 쓰느라 두번쓰니깐 상당히 번거로워졌어요.

그럼 위 배열 하나(rps_dictionary)로 해결할 방법은 없을까요? 그러기위해서 이차원배열이 다시 필요해집니다.

 

한번 객체를 이차원 배열로 만드는 방법이 있습니다. Object.entries에 대해 알아보겠습니다.

//Object.entries(객체명) <<= 객체를 2차원 배열로 변경해줌.
var rps_dictionary = {
    rock : '0',
    scissor : '-142px',
    paper : '-284px'
}

var a = Object.entries(rps_dictionary);

console.log(a);

//[ [ 'rock', '0' ], [ 'scissor', '-142px' ], [ 'paper', '-284px' ] ]

 

그럼 저렇게 바뀐 값에서, 우리가 원하는 값을 찾으려면 어떻게하면될까요? 이전에 사용했던 IndexOf 면될까요? 아마 -1을 리턴해줄것입니다. 일차원배열에서는 IndexOf를 사용할 수 있지만, 2차원배열에서는 사용할 수 없기 때문입니다. 그럼 이제 2차원 배열을 다루는 두가지 메소드를 알아보겠습니다. find 와, findIndex 입니다.

//findIndex ==>> 이차원배열에서 지정한 값이 있는 배열의 인덱스 번호(위치)를 반환한다.

var rps_dictionary = {
    rock : '0',
    scissor : '-142px',
    paper : '-284px'
}

var a = Object.entries(rps_dictionary);

console.log(a.findIndex(function(x){
    return x[1] === '-284px';
}))

// reuturn => 2




//find =>> 이차원 배열에서 지정한 값이 있는 배열을 반환한다.

var rps_dictionary = {
    rock : '0',
    scissor : '-142px',
    paper : '-284px'
}

var a = Object.entries(rps_dictionary);

console.log(a.find(function(x){
    return x[1] === '-284px';
}));

// return => [ 'paper', '-284px' ]

 

그럼 이제 객체를 2차원 배열로 전환하는 (Object.entries) 도 알게 됐고,

2차원 배열에서 원하는 값 혹은 인덱스를 추출하는 방법 (find & findIndex) 도 알게 되었으니,

이것을 활용해서 op_rps_dictionary를 삭제하고, 이 부분을 2차원 배열로 조금 더 효율적으로 다뤄봅시다.

var img_location = '0';

var rps_dictionary = {
    rock : '0',
    scissor : '-142px',
    paper : '-284px'
}

//위 rps_dictionary를 이차원배열로 만들고, 함수로 감싸줬습니다.
function computer(img_location){
    return Object.entries(rps_dictionary).find(function(rps){
        return rps[1] === img_location;
    })[0]
}

setInterval(function(){
    if(img_location === rps_dictionary.rock){
        img_location = rps_dictionary.scissor;
    } else if (img_location === rps_dictionary.scissor){
        img_location = rps_dictionary.paper;
    } else {
        img_location = rps_dictionary.rock;
    }
    document.querySelector('#computer').style.background =
    'url(https://en.pimg.jp/023/182/267/1/23182267.jpg)'+ img_location + ' 0';
}, 100);


document.querySelectorAll('.btn').forEach(function(rpsbtn){
    rpsbtn.addEventListener('click', function(){
        var my_choice = this.textContent;
        console.log(`내 선택 => ${my_choice} // 컴퓨터 선택 => ${computer(img_location)}`);
    })
})

 

1. computer라는 함수를 만들어줬습니다. 그리고 매개변수로 img_location을 받아왔습니다. 왜냐면, 컴퓨터가 선택하는 것은 매 0.1초마다 계속 변하기 때문에 고정값으로 두면 안되기 때문입니다.

2. 그리고 함수의 return 값으로, Object.entries(rps_dictionary)를 해줘서 위 객체를 2차원 배열로 변환했습니다.

3. 그리고나서 find를 이용해, rps_dictionary의 이차원 배열을 rps로 받아오고, 이것의 첫번째 값이 0, -142, -284 인 것을 찾기 위해 [1]값 = img_location이라고 해줬습니다.

4. 이렇게 받아오면 배열 덩어리가 생깁니다. ['paper', '-142px'] 예를들면 이렇게 말이죠. 그럼 그 중 우리가 보고싶은 것은 0번째값이므로, 뒤에 [0]을 붙여줘서 마무리했습니다.

5. 그리고 아래 콘솔에 찍는 컴퓨터의 선택 부분에 이 함수를 실행시켜줬습니다.

이제 콘솔창을 살펴보면 이전과 달리, 컴퓨터가 가위바위보 중 낸 것이 무엇인지 직관적으로 알 수 있게 됐습니다.

 

이제 내가 낸 가위바위보 중 하나와, 컴퓨터가 그 시점에 낸 가위바위보를 비교해서, 누가 이겼는지 확인할 수 있는 로직을 구현해봅시다.

document.querySelectorAll('.btn').forEach(function(rpsbtn){
    rpsbtn.addEventListener('click', function(){
        var my_choice = this.textContent;
        console.log(`내 선택 => ${my_choice} // 컴퓨터 선택 => ${computer(img_location)}`);
        if(my_choice === '가위'){
            if(computer(img_location) === 'rock'){
                console.log(`컴퓨터가 승리했습니다.`);
            } else if(computer(img_location) === 'paper'){
                console.log(`사용자님이 승리했습니다.`);
            } else {
                console.log(`비겼습니다.`);
            }
        } else if(my_choice === '바위'){
            if(computer(img_location) === 'rock'){
                console.log(`비겼습니다.`);
            } else if(computer(img_location) === 'paper'){
                console.log(`컴퓨터가 승리했습니다.`);
            } else {
                console.log(`사용자님이 승리했습니다.`);
            }
        } else {
            if(computer(img_location) === 'rock'){
                console.log(`사용자님이 승리했습니다.`);
            } else if(computer(img_location) === 'paper'){
                console.log(`비겼습니다.`);
            } else {
                console.log(`컴퓨터가 승리했습니다.`);
            }
        }
    })
})

코드에서 아랫부분, 버튼에 이벤트리스너를 달아준 부분에, 적용해주면 되겠죠?

로직은 보시는것과같이, 사용자가 가위를 냈을때, 바위를 냈을 때, 보를 냈을 때 로 구분하고, 그리고 그 안에 다시 조건문을 사용해서, 컴퓨터가 가위, 바위, 보를 냈을 때의 각각의 콘솔을 지정해줬습니다.

 

그리고나서 실행하면 아마 게임이 정상적으로 동작할 것 입니다 !

 

게임을 하다가 버튼을 눌렀을 때 승패결정을 하면서 콘솔에 출력되잖아요?

그런데, setInterver로인해서 이미지가 계속 매 0.1초마다 변합니다.

게임결과가 나온 뒤 잠시 setInterval 이 멈추면 더 좋지 않을까요?

그러기위해서 setInterval 을 멈추는 clearInterval을 이용해보겠습니다.

 

var img_location = '0';
var rps_dictionary = {
    rock : '0',
    scissor : '-142px',
    paper : '-284px'
}

function computer(img_location){
    return Object.entries(rps_dictionary).find(function(rps){
        return rps[1] === img_location;
    })[0]
}
//setInterval을 변수로 묶어줌;
var shuffling = setInterval(function(){
    if(img_location === rps_dictionary.rock){
        img_location = rps_dictionary.scissor;
    } else if (img_location === rps_dictionary.scissor){
        img_location = rps_dictionary.paper;
    } else {
        img_location = rps_dictionary.rock;
    }
    document.querySelector('#computer').style.background =
    'url(https://en.pimg.jp/023/182/267/1/23182267.jpg)'+ img_location + ' 0';
}, 100);


document.querySelectorAll('.btn').forEach(function(rpsbtn){
    rpsbtn.addEventListener('click', function(){
        var my_choice = this.textContent;
        console.log(`내 선택 => ${my_choice} // 컴퓨터 선택 => ${computer(img_location)}`);
        clearInterval(shuffling); //setInterval을 중지시킴;
        if(my_choice === '가위'){
            if(computer(img_location) === 'rock'){
                console.log(`컴퓨터가 승리했습니다.`);
            } else if(computer(img_location) === 'paper'){
                console.log(`사용자님이 승리했습니다.`);
            } else {
                console.log(`비겼습니다.`);
            }
        } else if(my_choice === '바위'){
            if(computer(img_location) === 'rock'){
                console.log(`비겼습니다.`);
            } else if(computer(img_location) === 'paper'){
                console.log(`컴퓨터가 승리했습니다.`);
            } else {
                console.log(`사용자님이 승리했습니다.`);
            }
        } else {
            if(computer(img_location) === 'rock'){
                console.log(`사용자님이 승리했습니다.`);
            } else if(computer(img_location) === 'paper'){
                console.log(`비겼습니다.`);
            } else {
                console.log(`컴퓨터가 승리했습니다.`);
            }
        }
    })
})

1. setInterval을 shuffling이라는 변수에 담아줬습니다.

2. 버튼을 클릭했을 때 멈춰야겠죠? 그러므로 이벤트리스너 안에 버튼을 클릭하는 동시에 멈출수있도록 clearInterval을 작성해줬습니다.

 

근데 이걸로 조금 아쉬워요. 게임이 딱 한판하면 끝난단말이죠? 그래서 다시 시작하는 기능을 추가해주겠습니다.

setTimeout을 추가하겠습니다. 몇초 뒤 실행해라 << 입니다.

document.querySelectorAll('.btn').forEach(function(rpsbtn){
    rpsbtn.addEventListener('click', function(){
        var my_choice = this.textContent;
        console.log(`내 선택 => ${my_choice} // 컴퓨터 선택 => ${computer(img_location)}`);
        clearInterval(shuffling); //setInterval을 중지시킴;
        //3초 뒤에 실행하기위해 작성한 setTimeout !
        setTimeout(function(){
            shuffling = setInterval(function(){
                if(img_location === rps_dictionary.rock){
                    img_location = rps_dictionary.scissor;
                } else if (img_location === rps_dictionary.scissor){
                    img_location = rps_dictionary.paper;
                } else {
                    img_location = rps_dictionary.rock;
                }
                document.querySelector('#computer').style.background =
                'url(https://en.pimg.jp/023/182/267/1/23182267.jpg)'+ img_location + ' 0';
            }, 100);
        }, 3000);

        if(my_choice === '가위'){
            if(computer(img_location) === 'rock'){
                console.log(`컴퓨터가 승리했습니다.`);
            } else if(computer(img_location) === 'paper'){
                console.log(`사용자님이 승리했습니다.`);
            } else {
                console.log(`비겼습니다.`);
            }
        } else if(my_choice === '바위'){
            if(computer(img_location) === 'rock'){
                console.log(`비겼습니다.`);
            } else if(computer(img_location) === 'paper'){
                console.log(`컴퓨터가 승리했습니다.`);
            } else {
                console.log(`사용자님이 승리했습니다.`);
            }
        } else {
            if(computer(img_location) === 'rock'){
                console.log(`사용자님이 승리했습니다.`);
            } else if(computer(img_location) === 'paper'){
                console.log(`비겼습니다.`);
            } else {
                console.log(`컴퓨터가 승리했습니다.`);
            }
        }
    })
})

 

0. 위에서 clearInterval을 해줌으로써 잠시 가위바위보 게임이 중단되며, 

1. setTimeout의 시간을 3000으로 설정함으로써 3초 뒤에 실행됩니다.

2. 그리고 안에, 위에서 만든 setInterval을 삽입함으로써 , 3초뒤에 매 0.1초마다 사진이 바뀌는 즉, 게임이 재실행됩니다.

*shuffling 으로 묶어준 이유는, 위에서 clearInterval을 이용해 게임을 멈추는데, shuffling이라고 변수명으로 지정해주지않으면 clearInterval이 작동할수가 없습니다. 따라서, var로 위에서 선언했으므로, 변수명만 다시써서 shuffling = ~~~ 이런식으로 작성해줍니다.

 

 

마지막으로, shuffling변수에 할당된 setInterval 부분이 두번 중복되요. 따라서, 이 부분을 함수로 바꿔 살짝 리팩토링 해주겠습니다.

var img_location = '0';
var rps_dictionary = {
    rock : '0',
    scissor : '-142px',
    paper : '-284px'
}

function computer(img_location){
    return Object.entries(rps_dictionary).find(function(rps){
        return rps[1] === img_location;
    })[0]
}

//함수로 선언하고
var shuffling;
function gameStarter(){
    shuffling = setInterval(function(){
        if(img_location === rps_dictionary.rock){
            img_location = rps_dictionary.scissor;
        } else if (img_location === rps_dictionary.scissor){
            img_location = rps_dictionary.paper;
        } else {
            img_location = rps_dictionary.rock;
        }
        document.querySelector('#computer').style.background =
        'url(https://en.pimg.jp/023/182/267/1/23182267.jpg)'+ img_location + ' 0';
    }, 100);
}

gameStarter(); //사용


document.querySelectorAll('.btn').forEach(function(rpsbtn){
    rpsbtn.addEventListener('click', function(){
        var my_choice = this.textContent;
        console.log(`내 선택 => ${my_choice} // 컴퓨터 선택 => ${computer(img_location)}`);
        clearInterval(shuffling);
        setTimeout(function(){
            gameStarter();//사용
        }, 3000);

        if(my_choice === '가위'){
            if(computer(img_location) === 'rock'){
                console.log(`컴퓨터가 승리했습니다.`);
            } else if(computer(img_location) === 'paper'){
                console.log(`사용자님이 승리했습니다.`);
            } else {
                console.log(`비겼습니다.`);
            }
        } else if(my_choice === '바위'){
            if(computer(img_location) === 'rock'){
                console.log(`비겼습니다.`);
            } else if(computer(img_location) === 'paper'){
                console.log(`컴퓨터가 승리했습니다.`);
            } else {
                console.log(`사용자님이 승리했습니다.`);
            }
        } else {
            if(computer(img_location) === 'rock'){
                console.log(`사용자님이 승리했습니다.`);
            } else if(computer(img_location) === 'paper'){
                console.log(`비겼습니다.`);
            } else {
                console.log(`컴퓨터가 승리했습니다.`);
            }
        }
    })
})

우선, shuffling 이라는 아무것도 없는 변수를 선언한 뒤에,

gameStarter라는 함수를 만들고, 그 안에 아까있던 setInterval 코드를 그대로 삽입해줬습니다.

그리고 아까 setInterval을 요구하던 부분 두 부분에 삽입해줬습니다.

훨씬 코드가 짧아진 것을 확인할 수 있습니다. 가독성도 좋아졌쬬? ㅎ_ㅎ

 

 

 

이것으로 가위바위보 게임을 마치고, 주요 문법을 정리하는 시간을 가지도록 하겠습니다.

3. 문법정리

우선 Object와, indexOf, find, findIndex등을 다뤘습니다.

//일차원 배열에서 찾는 값의 위치값(인덱스)를 반환하는 indexOf
var ary = [1,2,3,4];
console.log(ary.indexOf(3));


// Obejct 객체란? key : value 값을 가진 자료구조형태.
// 배열과 유사하나, key& value 값을 가진다는 점에서 상이함.
var rps_dictionary = {
    rock : '0',
    scissor : '-142px',
    paper : '-284px'
}
//객체를 이차원 배열로 바꿔주는 Object.entries(객체)
var a = Object.entries(rps_dictionary);

//이차원배열에서 원하는 위치값(인덱스)를 반환하는 findIndex
console.log(a.findIndex(function(x){
    return x[1] === '-284px';
}))

//이차원배열에서 원하는 부분의 배열값을 반환하는 find
console.log(a.find(function(x){
    return x[1] === '-284px';
}));

 

또, 이미지를 원하는대로 짤라서 사용하는 이미지 스프라이트가 있었죠?

개념은 큰 이미지 속에 여러 이미지가 있다고 가정하면 중, 원하는 사진이 있는 부분만을 사용하는 것입니다. 좌우, 상하 px값을 이용해서 말이죠. (동영상 참조)

이미지 스프라이트

 

 

그리고 한번에 여러 HTML태그를 선택할 수 있는 querySelectorAll과 그것의 값을 추출해내는 forEach가 있었습니다.

//querySelectorAll은 기본적으로 querySelector와 사용법이 같고,
//다만, forEach를 적용하지 않으면, 모든 태그가 선택되지 않으므로,
//forEach 를 이용해 모든 btn클래스에 해당하는 태그를 선택할 수 있도록 해줍니다.

document.querySelectorAll('.btn').forEach(function(btn){
	document.querySelectorAll('.btn').forEach(function(btn){
    btn.style.color = 'red';
})
}

//이런식으로 사용하면 모든 btn클래스가 선택되어, 빨간색으로 변합니다.

 

마지막으로 시간차를 두는 setTimeout, setInterval & clearInterval 등이 있었습니다.

//setTimeout

setTimeout(function(){
    console.log(`3초뒤 1회 실행시키는 setTimeout`);
}, 3000);

//setInterval

var interval = setInterval(function(){
    console.log('2초마다 실행을 지속하는 setInterval');
}, 2000);

//clearInterval
//setInterval을 정지시킴.
clearInterval(interval);

*clearInterval을 이용하기위해서는 setInterval을 변수에 넣어줘야합니다.

 

 

 

 

 

 

끝.

 

 

 

 

오늘은 가위바위보 게임을 만들어봤습니다 !

여기까지가 [초급]강좌 입니다.

만약, 어려운점이 많았다면, 여기서 멈추고 다시 처음부터 복습하고 넘어가시는 것을 추천합니다.

 

다음 시간부터는 [중급]강좌가 계속됩니다.

 

[중급]

- 지뢰찾기 (스코프&클로저&렉시컬스코프&재귀)

- 반응속도테스트게임 (호출스택, 재귀&비동기와 호출스택)

- 틱택토 개량버전 (리펙토링 & 무승부)

- 카드 짝맞추기 (참조와 복사&깊은복사 & 팩토리패턴 & 프로토타입)

- 자스스톤 (call by ~ & creator , new )

- 2048 (mousedown, up, move & 드래그)

- 테트리스 (keyup , down, press, 호출스택 & 이벤트루프 & ES6 const, let, Arrow Function)