ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [JavaScript] 자바스크립트 10강.셀프 체크 - 기타 기능 구현하기
    Javascript 2023. 6. 15. 19:49
    반응형

    배운 것 정리

    🔆 window

    window 객체는 브라우저를 가리키는 객체로, 브라우저가 제공하는 기본 객체와 함수들은 대부분 window 객체 안에 들어 있습니다. document 객체나 console 객체로 실제로는 window.document, window.console 인데, window를 생략하고

    document 와 console 만 적습니다.

     

    🔆 this

    this 는 상황에 따라 다른 값을 가집니다.

    기본적으로 this 는 window 객체를 가리키므로 어떤 다른 값을 가지는만 외우면 됩니다.

    1. 객체를 통해 this 를 사용할 때는 this 가 해당 객체를 가리키게 됩니다
    2. 특정 메서드는 콜백 함수의 this 를 바꿉니다. addEventListener 가 대표적입니다
    3. 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>

     

    실행 화면

    반응형

    댓글

Designed by Tistory.