안녕하세요. 이번 시간에는 턴제 게임을 만들겠습니다! 지금까지 배운 것을 활용해서요. 이전 실습 때의 텍스트 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에 영웅 이름을 입력하고 시작 버튼을 눌러봅시다! 다음처럼 게임이 실행되나요? 이 게임은 단순히 코딩 예시를 보여주는 거기 때문에 스타일은 넣지 않겠습니다.
아직은 메뉴가 실행이 안 되죠? 안 만들었으니까요, 하하... 다음 강좌에서 메뉴를 선택하는 것과 몬스터 데이터를 처리하는 부분을 만들어보겠습니다!
강좌의 최종 실행화면 이미지 변경이 안된거죠?
아무개 1lev HP: 100/100 XP: 0/15 ATT: 10
요렇게 현재HP/맥스HP | 경험치 | 공격력
요렇게 표현하신거죠?
감사합니다.