게시글

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

턴제 게임 만들기(3)

안녕하세요! 완성된 js 코드를 올려드리겠습니다! html 파일은 1편에 있는게 전부입니다.

TurnGame 객체가 initiate된 이후부터 상황을 한 번 찬찬히 따라가보세요. 이해가 안 가는 부분은 댓글로 질문해주세요!

turn.js

var TurnGame = (function () {
  var instance;
  var initiate = function (heroName) {
    var hero = {
      name: heroName,
      lev: 1,
      maxHp: 100,
      hp: 100,
      xp: 0,
      att: 10
    };
    var monsters = [{
      name: '슬라임',
      hp: 25 + hero.lev * 3,
      att: 10 + hero.lev,
      xp: 10 + hero.lev,
    }, {
      name: '스켈레톤',
      hp: 50 + hero.lev * 5,
      att: 15 + hero.lev * 2,
      xp: 20 + hero.lev * 2,
    }, {
      name: '찬호[보스]',
      hp: 100 + hero.lev * 10,
      att: 25 + hero.lev * 5,
      xp: 50 + hero.lev * 5,
    }];
    var monster = null;
    var turn = true;
    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;
      },
      generateMonster: function () {
        monster = JSON.parse(JSON.stringify(monsters[Math.floor(Math.random() * monsters.length)]));
        document.getElementById('monster-name').innerHTML = monster.name;
        document.getElementById('monster-hp').innerHTML = 'HP: ' + monster.hp;
        document.getElementById('monster-att').innerHTML = 'ATT: ' + monster.att;
        this.setMessage(monster.name + '이(가) 공격해옵니다');
        return this.toggleMenu();
      },
      menuInput: function (input) {
        if (input === '1') {
          return this.generateMonster();
        } else if (input === '2') {
          hero.hp = hero.maxHp;
          return this.showHp().setMessage('체력을 회복했습니다');
        } else if (input === '3') {
          return this.exit();
        } else {
          alert('잘못된 입력');
        }
      },
      battleInput: function (input) {
        if (input === '1') {
          return this.attackMonster();
        } else if (input === '2') {
          if (hero.hp + hero.lev * 20 < hero.maxHp) {
            hero.hp += hero.lev * 20;
          } else {
            hero.hp = hero.maxHp;
          }
          return this.showHp().setMessage('체력을 회복했습니다').nextTurn();
        } else if (input === '3') {
          return this.clearMonster().setMessage('도망쳤습니다');
        } else {
          alert('잘못된 입력');
        }
      },
      attackMonster: function () {
        monster.hp -= hero.att;
        document.getElementById('monster-hp').innerHTML = 'HP: ' + monster.hp;
        if (monster.hp > 0) {
          return this.setMessage(hero.att + '의 데미지를 입혔습니다.').nextTurn();
        }
        return this.win();
      },
      attackHero: function () {
        hero.hp -= monster.att;
        return this.showHp();
      },
      nextTurn: function () {
        var self = this;
        turn = !turn;
        document.getElementById('battle-button').disabled = true;
        if (!turn) {
          window.setTimeout(function () {
            self.setMessage(monster.name + '의 턴입니다');
            window.setTimeout(function () {
              document.getElementById('battle-button').disabled = false;
              if (self.attackHero()) {
                self.setMessage(monster.att + '의 데미지를 입었습니다');
                window.setTimeout(function () {
                  self.setMessage(hero.name + '의 턴입니다');
                }, 1000);
              }
            }, 1000);
          }, 1000);
          return this.nextTurn();
        }
        return this;
      },
      win: function () {
        this.setMessage(monster.name + ' 사냥에 성공해 경험치 ' + monster.xp + '을 얻었습니다');
        hero.xp += monster.xp;
        return this.clearMonster().showXp();
      },
      clearMonster: function () {
        monster = null;
        document.getElementById('monster-name').innerHTML = '';
        document.getElementById('monster-hp').innerHTML = '';
        document.getElementById('monster-att').innerHTML = '';
        return this.toggleMenu();
      },
      gameOver: function () {
        document.getElementById('screen').innerHTML = hero.name + '은 레벨' + hero.lev + '에서 죽었습니다. 새로 시작하려면 새로고침하세요';
        return false;
      },
      exit: function (input) {
        document.getElementById('screen').innerHTML = '이용해주셔서 감사합니다. 새로 시작하려면 새로고침하세요';
      }
    };
  };
  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 = '';
  TurnGame.getInstance().menuInput(option);
};
document.getElementById('battle-menu').onsubmit = function (e) {
  var input = document.getElementById('battle-input');
  var option = input.value;
  e.preventDefault();
  input.value = '';
  TurnGame.getInstance().battleInput(option);
};

저보다 빨리 보스를 잡아보세요!

다음 시간은 고급 강좌 첫 편으로, jQuery 분석을 해보겠습니다!

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

댓글

5개의 댓글이 있습니다.
5년 전
안녕하세요. nextTurn 에서 return this.nextTurn(), return this 를 생략해도 동일하게 동작하는 것 같은데 해당 구문이 필요한 이유는 무엇일까요?
5년 전
메서드 체이닝을 위해서입니다. this.nextTurn().attackHero().attackMonster() 이런 식으로 연달아 쓸 수 있게 해줍니다.
5년 전
앗 답변 정말 감사드립니다. 그런 이유가 있었군요. 한가지 더 여쭙자면 해당 구문을 생략해도 소스가 이상없이 동작했던 건 nextTurn 함수 안에서는 메서드 체이닝을 사용하지 않아서이겠죠?
5년 전
네네 맞습니다~
6년 전
요거 한글 입력시 input 폼 안에서 자모음 분리현상 일어나는데 무엇이 문제인지 알 수 있을까요??
6년 전
댓쓴인데 엣지 브라우저 고유 버그인거 같네요 ㅠㅠ
7년 전
안녕하세요 턴제게임 어디서 할 수 있어요??
7년 전
직접 코드 복사하셔서 html 파일 만든 후 실행하셔야 합니다.
7년 전
NextTurn에서 this를 self로 사용한 이유는 무엇인가요??
7년 전
window.setTimeout 안의 this는 nextTurn 함수의 this와 다릅니다. nextTurn 안의 this를 setTimeout 안에서 쓰기 위해 변수에 저장했습니다. 관련 강좌로 실행 컨텍스트 강좌가 있습니다.
8년 전
턴제게임만들기(2)랑 턴제게임만들기(3)에서 턴제게임만들기(2)에서는 onclick 이벤트를 주었는데 (3)에서는 onsubmit 을주어서 .. 2개가 빠진건지 아니면 제가 이해를 잘못한건지 잘모르겠어서 질문남겼습니다 ㅎ
8년 전
수정했습니다! 감사합니다~