게시글

5만명이 선택한 평균 별점 4.9의 제로초 프로그래밍 강좌! 로드맵만 따라오면 됩니다! 클릭
강좌28 - JavaScript - 8년 전 등록 / 7년 전 수정

턴제 게임 만들기(1)

안녕하세요. 이번 시간에는 턴제 게임을 만들겠습니다! 지금까지 배운 것을 활용해서요. 이전 실습 때의 텍스트 RPG를 좀 더 발전시켜보겠습니다!

이전 게임은 자동 진행이 되고, 게임과의 인터렉션이 처음 이름을 입력받는 한 번 밖에 없는게 단점이었습니다. 이번 실습에선 게임에 명확한 턴을 부여하고, 인터렉션을 어떻게 처리하는지 보여드리겠습니다!

전체 게임 객체를 싱글턴 객체로 만들고, 데이터를 처리하는 부분은 메소드 체이닝 패턴을 사용하겠습니다.

일단 게임 객체부터 만들어보죠. 싱글턴이라 객체 하나만 생성됩니다. initiate 함수 안의 instance 객체에 기본적으로 필요한 메소드를 여러 개 만들어두었습니다. 게임에 필요한 정보를 보여주는 역할입니다.

var TurnGame = (function() {
  var instance;
  var initiate = function(heroName) {
    var hero = {
      name: heroName,
      lev: 1,
      maxHp: 100,
      hp: 100,
      xp: 0,
      att: 10
    };
    return {
      showLevel: function() {
        document.getElementById('hero-level').innerHTML = hero.lev + 'lev';
        return this;
      },
      showXp: function() {
        var self = this;
        if (hero.xp > 15 * hero.lev) {
          hero.xp -= 15 * hero.lev;
          hero.maxHp += 10;
          hero.hp = hero.maxHp;
          hero.att += hero.lev;
          hero.lev++;
          window.setTimeout(function() {
            self.setMessage('레벨업!');
          }, 1000);
        }
        document.getElementById('hero-xp').innerHTML = 'XP: ' + hero.xp + '/' + 15 * hero.lev;
        document.getElementById('hero-att').innerHTML = 'ATT: ' + hero.att;
        return this.showLevel().showHp();
      },
      showHp: function() {
        if (hero.hp < 0) {
          return this.gameOver();
        }
        document.getElementById('hero-hp').innerHTML = 'HP: ' + hero.hp + '/' + hero.maxHp;
        return this;
      },
      toggleMenu: function () {
        document.getElementById('hero-name').innerHTML = hero.name;
        document.getElementById('start-screen').style.display = 'none';
        if (document.getElementById('game-menu').style.display === 'block') {
          document.getElementById('game-menu').style.display = 'none';
          document.getElementById('battle-menu').style.display = 'block';
          document.getElementById('battle-input').focus();
        } else {
          document.getElementById('game-menu').style.display = 'block';
          document.getElementById('battle-menu').style.display = 'none';
          document.getElementById('menu-input').focus();
        }
        return this;
      },
      setMessage: function(msg) {
        document.getElementById('message').innerHTML = msg;
        return this;
      },
    };
  };
  return {
    getInstance: function(name) {
      if (!instance) {
        instance = initiate(name);
      }
      return instance;
    }
  };
})();
document.getElementById('start-screen').onsubmit = function(e) {
  var name = document.getElementById('name-input').value;
  e.preventDefault();
  if (name && name.trim() && confirm(name + '으로 하시겠습니까?')) {
    TurnGame.getInstance(name).showXp().toggleMenu(); // 체이닝
  } else {
    alert('이름을 입력해주세요');
  }
};
document.getElementById('game-menu').onsubmit = function(e) {
  var input = document.getElementById('menu-input');
  var option = input.value;
  e.preventDefault();
  input.value = '';
};
document.getElementById('battle-menu').onsubmit = function(e) {
  var input = document.getElementById('battle-input');
  var option = input.value;
  e.preventDefault();
  input.value = '';
};

코드가 엄청 길어서 당황하셨을 수도 있는데 크게 두 부분입니다. 처음에 TurnGame 싱글턴 객체 그리고 이벤트 리스너입니다.

이벤트 리스너를 #start-screen, #game-menu, #battle-menu 폼에 연결해서 submit 시 동작하게 만들었습니다. 그리고 #game-menu와 #battle-menu는 미리 만들어두었지만, display: none; 으로 숨겨 필요한 경우에만 보이게 코딩했습니다.

TurnGame.getInstance(name).showXp().toggleMenu();

이 부분을 잘 보세요. instance 객체의 메소드를 연속으로 쓰고 있습니다. 바로 TurnGame.getInstance, TurnGame.showXp, TurnGame.showToggle 모두 instance 또는 this를 return하기 때문인데요. (showXp는 showHp와 showLevel을 내부적으로 return합니다.) 계속 같은 객체를 return하기 때문에 그 객체의 메소드를 연속으로 쓸 수 있는겁니다. jQuery를 하신 분이라면 익숙할겁니다. 이러한 패턴을 메소드 체이닝이라고 부릅니다. 체인처럼 연속적으로 실행할 수 있다는 뜻입니다.

코드가 길어질 것 같으니까 위의 자바스크립트 코드를 turn.js 파일로 만들어서 html에서는 불러오는 게 좋을 것 같네요. 다음 html 파일이 이 게임을 실행하는 파일입니다. 앞으로 이 html을 실행하면 됩니다!

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <title>턴제 게임</title>
</head>
<body>
<form id="start-screen">
  <input id="name-input" placeholder="영웅 이름을 입력하세요!" />
  <button id="start">시작</button>
</form>
<div id="screen">
  <div id="hero-stat">
    <span id="hero-name"></span>
    <span id="hero-level"></span>
    <span id="hero-hp"></span>
    <span id="hero-xp"></span>
    <span id="hero-att"></span>
  </div>
  <form id="game-menu" style="display: none;">
    <div id="menu-1">1.모험</div>
    <div id="menu-2">2.휴식</div>
    <div id="menu-3">3.종료</div>
    <input id="menu-input" />
    <button id="menu-button">입력</button>
  </form>
  <form id="battle-menu" style="display: none;">
    <div id="battle-1">1.공격</div>
    <div id="battle-2">2.회복</div>
    <div id="battle-3">3.도망</div>
    <input id="battle-input" />
    <button id="battle-button">입력</button>
  </form>
  <div id="message"></div>
  <div id="monster-stat">
    <span id="monster-name"></span>
    <span id="monster-hp"></span>
    <span id="monster-att"></span>  
  </div>
</div>
<script src="./turn.js"></script>
</body>
</html>

html을 실행시켜 input에 영웅 이름을 입력하고 시작 버튼을 눌러봅시다! 다음처럼 게임이 실행되나요? 이 게임은 단순히 코딩 예시를 보여주는 거기 때문에 스타일은 넣지 않겠습니다.

undefined

아직은 메뉴가 실행이 안 되죠? 안 만들었으니까요, 하하... 다음 강좌에서 메뉴를 선택하는 것과 몬스터 데이터를 처리하는 부분을 만들어보겠습니다!

조회수:
0
목록
투표로 게시글에 관해 피드백을 해주시면 게시글 수정 시 반영됩니다. 오류가 있다면 어떤 부분에 오류가 있는지도 알려주세요! 잘못된 정보가 퍼져나가지 않도록 도와주세요.
Copyright 2016- . 무단 전재 및 재배포 금지. 출처 표기 시 인용 가능.
5만명이 선택한 평균 별점 4.9의 제로초 프로그래밍 강좌! 로드맵만 따라오면 됩니다! 클릭

댓글

8개의 댓글이 있습니다.
5년 전
안녕하세요?

강좌의 최종 실행화면 이미지 변경이 안된거죠?


아무개 1lev HP: 100/100 XP: 0/15 ATT: 10

요렇게 현재HP/맥스HP | 경험치 | 공격력

요렇게 표현하신거죠?


감사합니다.
7년 전
menu-1, battle-1 을 data-type으로 해도 되나요?? (data-menu = '1', data-battle = '1' )
7년 전
그래도 됩니다. 대신 클릭 시 data-menu나 data-battle 값을 확인하는 코드가 따로 필요하겠죠?
7년 전
테스팅 도중 '~ is not defined' 오류가 생겨 질문드립니다. turn.js에서 14줄 lev, 29줄 xp와 lev, 37줄 hp와 maxHp 앞에 각각 hero.을 붙여주니 에러는 해결했는데 제대로 디버깅한 건지 잘 모르겠네요. hero를 붙여주는게 맞는건가요?
7년 전
넵 맞습니다. 이걸 6개월간 방치하고 있었네요 ㅠ
7년 전
$('#target').submit((e)=>{
e.preventDefault();
$('#name').html(`hello ${$('#input').val()}`);
});
jquery를 이용해서 조금씩 수정중인데, 이 파일을 html에 script태그 안에 넣으면 작동을 하는데
왜 따로 .js파일로 빼 놓으면 작동하지 않을까요?
7년 전
콘솔 창의 에러메시지를 확인해보세요. 스크립트 파일 로딩 순서 문제인 것 같습니다. html 태그들을 제일 위에 놓고 제이쿼리 스크립트를 넣고, 사용자의 스크립트를 마지막에 넣으면 됩니다.
7년 전
답변감사합니다! 제이쿼리를 밑에 두었네요 ㅠ
한가지 더 여쭙고 싶은데
$('#target').submit((e)=>{
e.preventDefault();
여기있는 e의 역할은 무엇인가요?
7년 전
submit 이벤트에 대한 정보를 담고 있는 이벤트 객체입니다.
8년 전
e.preventDefault(); 가 실행중인 이벤트를 중단시킨다고 나와있던데 중지시키는 이유는 뭔지 알수있을까요??
8년 전
아 혹시 이벤트를 한번만 쓰고 다음번부터 못쓰게 중지하는건가여
8년 전
아뇨. 아예 못쓰게 하는 겁니다. 폼 안의 버튼을 클릭하면 폼 전송 이벤트가 실행되는 데 이 때 페이지가 이동해버려요. 그걸 막는 겁니다.
8년 전
initiate 내부 함수 hero 객체에 있는 maxpHP --> maxHP 오타요~
8년 전
감사합니다~
8년 전
쥔장님~ 게임 언제 나오는 거에요 도대체!!
8년 전
죄송해요.. 제가 다른 게임에 빠져서...
8년 전
혹시 오ㅡ버워친가요?
8년 전
게임 완성했으니 보스 한 번 잡아보시죠!
8년 전
미연시 추천합니다. Cho님 현실에 없으니 '가상'현실에서라도 만나야죠!
8년 전
턴제형 게임이면 미연시 같은 게임인가요? ㅎㅎ
8년 전
...그쪽 취향이신가봐요
8년 전
ㅎㅎ 벌써 기대하고 있어요. 요즘 좀 질렸거든요... 꺆!~ 아름다운 소녀로 해주세요.
8년 전
소원대로 우락부락한 남자들만 나오게 하겠습니다!
8년 전
어머머 그것도 좋아요. 아몰랑~~ 넘나 좋은 것! 빨리 부탁해요 ♡