-
[JavaScript] 자바스크립트 10강.셀프 체크 - 기타 기능 구현하기Javascript 2023. 6. 15. 19:49반응형
배운 것 정리
🔆 window
window 객체는 브라우저를 가리키는 객체로, 브라우저가 제공하는 기본 객체와 함수들은 대부분 window 객체 안에 들어 있습니다. document 객체나 console 객체로 실제로는 window.document, window.console 인데, window를 생략하고
document 와 console 만 적습니다.
🔆 this
this 는 상황에 따라 다른 값을 가집니다.
기본적으로 this 는 window 객체를 가리키므로 어떤 다른 값을 가지는만 외우면 됩니다.
- 객체를 통해 this 를 사용할 때는 this 가 해당 객체를 가리키게 됩니다
- 특정 메서드는 콜백 함수의 this 를 바꿉니다. addEventListener 가 대표적입니다
- this 가 바뀌는 것을 원치 않는다면 함수 선언문 대신 화살표 함수를 사용합니다
🔆 참조, 깊은 복사, 얕은 복사
복사는 어떤 값을 다른 변수에 대입할 때 기존 값과 참조 관계가 끊기는 것을 의미합니다.
객체가 아닌 값은 애초부터 참조 관계가 없으므로 그냥 복사합니다.
- 얕은 복사는 중첩된 객체가 있을 때 가장 바깥 객체만 복사되고, 내부 객체는 참조 관계를 유지하는 복사되는 것
- 배열을 얕은 복사 하면 => [...배열]
- 객체 얕은 복사 하면 => {...객체}
- 깊은 복사는 내부 객체까지 참조 관계가 끊겨 복사되는 것
const array = [{ j: 'k' }, { l: 'm' }]; const reference = array; // 참조 const shallowCopy = [...array] // 얕은 복사 const deepCopy = JSON.parse(JSON.stringify(array)); // 깊은 복사 console.log(array === reference); // true console.log(array[0] === reference[0]); // true console.log(array === shallowCopy); // flase console.log(array[0] === shallowCopy[0]); // true console.log(array === deepCopy); // flase
🔆 클래스
객체를 생성하는 템플릿 문법입니다. class 예약어로 클래스를 선언하고, constructor 메서드 안에 기존 코드를 넣습다.new 를 붙여 호출하면 constructor 함수가 실행되고 객체가 반환됩니다. this 는 생성된 객체 자신을 가리키게 됩니다.
🔆 클래스 상속
클래스끼리 extends 예약어로 상속할 수 있습니다. 상속하는 클래스는 부모 클래스가 되고, 상복받는 클래스는 자식 클래스가 됩니다. 공통되는 속성이나 메서드는 부모 클래스로부터 상속 받습니다.
class Hero extends Unit { constructor(game, name) { super(game, name, 100, 10, 0); // 부모 클래스의 생성자 호출 this.lev = 1; // 그 외 속성 } // 공격 함수 attack(target) { super.attack(target); // 부모 클래스의 attack // 부모 클래스의 attack 외의 동작 } }
문제 요구 사항
🟦 휴식 기능 및 종료 기능 추가
🟦 종료 기능은 게임을 종료하고 주인공을 새로 생성하는 화면으로 되돌아갑니다.
🟦 휴식 기능은 전투 중에 체력을 20 회복하는 기능, 회복 후에 몬스터에게 한 번 공격을 당합니다. 최대 체력(maxHp)값을 넘을 수 없습니다.
🟦 도망 기능은 너무 강력한 몬스터를 만났을 때 도망가는 기능으로, 일반 메뉴로 되돌아갑니다
🟦 힌트 회복 기능에는 Math.main 메서드를 사용하고, 종료 기능은 quit 메서드를 재사용하면 됩니다.
코드 구현
<script> ... // 일반메뉴 onGameMenuInput = (event) => { event.preventDefault(); const input = event.target['menu-input'].value; if (input === '1') { // 모험 this.changeScreen('battle'); const randomIndex = Math.floor(Math.random() * this.monsterList.length); const randomMonster = this.monsterList[randomIndex]; this.monster = new Monster( this, randomMonster.name, randomMonster.hp, randomMonster.att, randomMonster.xp, ); this.updateMonsterStat(); this.showMessage(`몬스터와 마주쳤다. ${this.monster.name}인 것 같다!`); } else if (input === '2') { // 휴식 this.hero.hp = this.hero.maxHp; this.updateHeroStat(); this.showMessage('충분한 휴식을 취했습니다.'); } else if (input === '3') { // 종료 this.showMessage(); this.quit(); } } .... </script>
코드 구현
<script> // 배틀 메뉴 함수 onBattleMenuInput = (event) => { event.preventDefault(); const input = event.target['battle-input'].value; if (input === '1') { // 공격 const { hero, monster } = this; hero.attack(monster); monster.attack(hero); // 영웅이 죽었을 경우 if (hero.hp <= 0) { this.showMessage(`${hero.lev} 레벨에서 전사했습니다. 새 주인공을 생성하세요.`); this.quit(); // 몬스터이 죽었을 경우 } else if (monster.hp <= 0) { this.showMessage(`몬스터를 잡아 ${monster.xp} 경험치를 얻었다.`); hero.getXp(monster.xp); this.monster = null; this.changeScreen('game'); } else { this.showMessage(`${hero.att}의 데미지를 주고, ${monster.att}의 데미지를 받았습니다.`); } this.updateHeroStat(); this.updateMonsterStat(); } else if (input === '2') { // 회복 const { hero, monster } = this; hero.hp = Math.min(hero.maxHp, hero.hp + 20); monster.attack(hero); this.showMessage('체력을 조금 회복했다!'); this.updateHeroStat(); } else if (input === '3') { // 도망 this.changeScreen('game'); this.monster = null; this.showMessage('부리나케 도망쳤다!'); this.updateMonsterStat(); } } </script>
최종 코드
<!DOCTYPE html> <html lang="ko"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>텍스트 RPG</title> </head> <body> <form id="start-screen"> <input id="name-input" placeholder="영웅 이름을 입력하세요!" /> <button id="start">시작</button> </form> <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> <script> const array = [{ j: 'k' }, { l: 'm' }]; const reference = array; // 참조 const shallowCopy = [...array] // 얕은 복사 const deepCopy = JSON.parse(JSON.stringify(array)); // 깊은 복사 console.log(array === reference); // true console.log(array[0] === reference[0]); // true console.log(array === shallowCopy); // flase console.log(array[0] === shallowCopy[0]); // true console.log(array === deepCopy); // flase // 변수 선언 const $startScreen = document.querySelector('#start-screen'); const $gameMenu = document.querySelector('#game-menu'); const $battleMenu = document.querySelector('#battle-menu'); const $heroName = document.querySelector('#hero-name'); const $heroLevel = document.querySelector('#hero-level'); const $heroHp = document.querySelector('#hero-hp'); const $heroXp = document.querySelector('#hero-xp'); const $heroAtt = document.querySelector('#hero-att'); const $monsterName = document.querySelector('#monster-name'); const $monsterHp = document.querySelector('#monster-hp'); const $monsterAtt = document.querySelector('#monster-att'); const $message = document.querySelector('#message'); class Game { constructor(name) { this.monster = null; this.hero = null; this.monsterList = [ { name: '슬라임', hp: 25, att: 10, xp: 10 }, { name: '스켈레톤', hp: 50, att: 15, xp: 20 }, { name: '마왕', hp: 150, att: 35, xp: 50 }, ]; this.start(name); } start(name) { console.log(this); // Game을 지칭함 $gameMenu.addEventListener('submit', this.onGameMenuInput); $battleMenu.addEventListener('submit', this.onBattleMenuInput); this.changeScreen('game'); this.hero = new Hero(this, name); this.updateHeroStat(); } // 화면 변하는 함수 changeScreen(screen) { if (screen === 'start') { // 시작메뉴 $startScreen.style.display = 'block'; $gameMenu.style.display = 'none'; $battleMenu.style.display = 'none'; } else if (screen === 'game') { // 일반메뉴 $startScreen.style.display = 'none'; $gameMenu.style.display = 'block'; $battleMenu.style.display = 'none'; } else if (screen === 'battle') { // 전투메뉴 $startScreen.style.display = 'none'; $gameMenu.style.display = 'none'; $battleMenu.style.display = 'block'; } } // 일반메뉴 onGameMenuInput = (event) => { event.preventDefault(); const input = event.target['menu-input'].value; if (input === '1') { // 모험 this.changeScreen('battle'); const randomIndex = Math.floor(Math.random() * this.monsterList.length); const randomMonster = this.monsterList[randomIndex]; this.monster = new Monster( this, randomMonster.name, randomMonster.hp, randomMonster.att, randomMonster.xp, ); this.updateMonsterStat(); this.showMessage(`몬스터와 마주쳤다. ${this.monster.name}인 것 같다!`); } else if (input === '2') { // 휴식 this.hero.hp = this.hero.maxHp; this.updateHeroStat(); this.showMessage('충분한 휴식을 취했습니다.'); } else if (input === '3') { // 종료 this.showMessage(); this.quit(); } } // 배틀 메뉴 함수 onBattleMenuInput = (event) => { event.preventDefault(); const input = event.target['battle-input'].value; if (input === '1') { // 공격 const { hero, monster } = this; hero.attack(monster); monster.attack(hero); // 영웅이 죽었을 경우 if (hero.hp <= 0) { this.showMessage(`${hero.lev} 레벨에서 전사했습니다. 새 주인공을 생성하세요.`); this.quit(); // 몬스터이 죽었을 경우 } else if (monster.hp <= 0) { this.showMessage(`몬스터를 잡아 ${monster.xp} 경험치를 얻었다.`); hero.getXp(monster.xp); this.monster = null; this.changeScreen('game'); } else { this.showMessage(`${hero.att}의 데미지를 주고, ${monster.att}의 데미지를 받았습니다.`); } this.updateHeroStat(); this.updateMonsterStat(); } else if (input === '2') { // 회복 const { hero, monster } = this; hero.hp = Math.min(hero.maxHp, hero.hp + 20); monster.attack(hero); this.showMessage('체력을 조금 회복했다!'); this.updateHeroStat(); } else if (input === '3') { // 도망 this.changeScreen('game'); this.monster = null; this.showMessage('부리나케 도망쳤다!'); this.updateMonsterStat(); } } // 영웅 상태 업데이트 updateHeroStat() { const { hero } = this; if (hero === null) { $heroName.textContent = ''; $heroLevel.textContent = ''; $heroHp.textContent = ''; $heroXp.textContent = ''; $heroAtt.textContent = ''; return; } $heroName.textContent = hero.name; $heroLevel.textContent = `${hero.lev}Lev`; $heroHp.textContent = `HP: ${hero.hp}/${hero.maxHp}`; $heroXp.textContent = `XP: ${hero.xp}/${15 * hero.lev}`; $heroAtt.textContent = `ATT: ${hero.att}`; } // 몬스터 상태 업데이트 updateMonsterStat() { const { monster } = this; if (monster === null) { $monsterName.textContent = ''; $monsterHp.textContent = ''; $monsterAtt.textContent = ''; return; } $monsterName.textContent = monster.name; $monsterHp.textContent = `HP: ${monster.hp}/${monster.maxHp}`; $monsterAtt.textContent = `ATT: ${monster.att}`; } // 메세지 보여주는 함수 showMessage(text) { $message.textContent = text; } // 초기화 quit() { this.hero = null; this.monster = null; this.updateHeroStat(); this.updateMonsterStat(); $gameMenu.removeEventListener('submit', this.onGameMenuInput); $battleMenu.removeEventListener('submit', this.onBattleMenuInput); this.changeScreen('start'); game = null; } } // 공툥 요소 함수(부모 클래스) class Unit { constructor(game, name, hp, att, xp) { this.game = game; this.name = name; this.maxHp = hp; this.hp = hp; this.xp = xp; this.att = att; } attack(target) { target.hp -= this.att; } } // 영웅 객체 생성 class Hero extends Unit { constructor(game, name) { super(game, name, 100, 10, 0); // 부모 클래스의 생성자 호출 this.lev = 1; // 그 외 속성 } // 공격 함수 attack(target) { super.attack(target); // 부모 클래스의 attack // 부모 클래스의 attack 외의 동작 } // 힐 함수 heal(monster) { this.hp += 20; this.hp -= monster.att; } // 경험치 함수 getXp(xp) { this.xp += xp; if (this.xp >= this.lev * 15) { // 경험치를 다 채우면 this.xp -= this.lev * 15; this.lev += 1; this.maxHp += 5; this.att += 5; this.hp = this.maxHp; this.game.showMessage(`레벨업! 레벨 ${this.lev}`); } } } // Monster 객체 생성 class Monster extends Unit { constructor(game, name, hp, att, xp) { super(game, name, hp, att, xp); } } let game = null; // 시작 화면모드 $startScreen.addEventListener('submit', (event) => { event.preventDefault(); const name = event.target['name-input'].value; game = new Game(name); }); // 게임 모드 $gameMenu.addEventListener('submit', (event) => { event.preventDefault(); const input = event.target['menu-input'].value; if (input === '1') { // 모험 } else if (input === '2') { // 휴식 } else if (input === '3') { // 종료 } }); // 배틀 모드 $battleMenu.addEventListener('submit', (event) => { const input = event.target['menu-input'].valueAsNumber; if (input === '1') { // 공격 } else if (input === '2') { // 회복 } else if (input === '3') { // 도발 } }); </script> </body> </html>
실행 화면
반응형'Javascript' 카테고리의 다른 글
[JavaScript] 자바스크립트 11강.셀프 체크 - 몇 초 걸렸는지 체크하기 (0) 2023.06.26 [JavaScript] 자바스크립트 11장. 이벤트 루프 이해하기 - 카드 짝 맞추기 게임 (0) 2023.06.16 [JavaScript] 자바스크립트 10장. 클래스_텍스트 RPG 게임 만들기 (0) 2023.06.09 [JavaScript] 자바스크립트 9강.셀프 체크 - 컴퓨터의 턴 만들기 (0) 2023.06.08 [JavaScript] 자바스크립트 9강 이차원 배열 다루기_틱택토 게임 (0) 2023.06.07