DungeonLife History - 02

윤수빈·2024년 8월 23일
0
post-custom-banner

1. 서론

오늘 진행 현황에 대해 기록할 예정이다.

할건 많은데 진행속도가 느려서 큰일이다...


2. 본론

2-1. 추가 및 수정 내용

1. 출현 몬스터 다양화

  • 스테이지가 진입하기 전 몬스터 인스턴스를 생성하게 되는데 이 시점에서 랜덤으로 여러 몬스터 중 하나가 생성 되도록 하였다.
  • 몬스터의 종류는 Monster Class의 monsterTypes에 저장해 두었다.
  • 각 몬스터 종류의 속성값으로 emersionChance가 있는데 이 수치가 출현확률이다.
  • 출현 확률은 몬스터 종류를 순회하며 랜덤 값을 산출하고 만약 랜덤값이 emersionChance 안에 속하면 생성이 되도록 설정했다.
    let isNotCreate = true;
       const setMonster = {};
       while (isNotCreate) {
         for (let idx in monsterTypes) {
           const monsterEmersionChance = monsterTypes[idx].emersionChance;
           const emersionRandomCount = Math.random() * 100;
           if (emersionRandomCount <= monsterEmersionChance) {
             Object.assign(setMonster, monsterTypes[idx]);
             isNotCreate = false;
           }
         }
       }

2. 플레이어와 몬스터의 일반공격과 특수 공격 추가

  • 몬스터와 플레이어에 actionType 속성 값을 넣어주고 그 안에 해당 객체가 할 수 있는 행동들을 모아놨다.
  • 각 Player, Monster 클래스의 action() 메서드를 통해 해당 객체의 턴일 때 행동권이 주어진다.
  • 몬스터는 랜덤으로 공격할 수 있도록 특수공격이 쿨타임이 아닐 때, 50% 확률로 특수 공격을 사용하도록 하고, 플레이어는 쿨타임이 아닐 때 특수 공격을 선택 및 사용할 수 있다.
## Monster Class ##
  async action(player, monster, logs) {
    if (this.hp > 0) {
      // 쿨타임인 행동을 제외하고 할 수 있는 행동을 정리한다.
      const actions = await Battle.checkPossibleAction(monster);

      // 몬스터의 특수 공격이 쿨타임인지 확인하고,
      // 쿨타임이 아닌 경우 반반확률로 특수 공격을 사용하도록 설정
      // 특수 공격이 아닌 경우는 일반 공격을 하도록 설정
      let attackIs = {};
      if (actions[1] !== undefined) {
        const isSpecialAttack = Math.floor(Math.random() * 100);
        if (isSpecialAttack > 40) {
          attackIs = await Object.assign(attackIs, actions[1]);
          this.actionTypes[1].currentCooltime = this.actionTypes[1].cooltime;
        }
      }

      // 일반 공격
      else if (actions[1] === undefined) {
        attackIs = await Object.assign(attackIs, actions[1]);
        await Object.assign(attackIs, actions[0]);
        this.actionTypes[1].currentCooltime--;
      }

      // 공격 시작
      const damage = await this.attack(attackIs, player);
      attackMessage(monster, player, logs, damage, attackIs.name);
    }
  }
## Player Class ##
  async action(player, monster, logs) {
    // 쿨타임인 행동을 제외하고 할 수 있는 행동을 정리한다.
    const actions = await Battle.checkPossibleAction(this);
    // 행동들을 출력한다.
    possibleActionMessage(actions);
    // 행동들을 선택한다.
    const choice = chooseAction(logs);

    // 플레이어의 선택에 따라 다음 행동 처리
    // 입력에 대한 행동을 키값으로 관리하는게 좋겠다고 판단
    if (actions[choice - 1].type === 'attack') {
      // 스킬을 사용한 경우
      if (actions[choice - 1] === this.actionTypes[1]) {
        // 스킬 쿨타임 적용
        this.actionTypes[1].currentCooltime = this.actionTypes[1].cooltime;
      }

      const damage = await this.attack(actions[choice - 1], monster);
      attackMessage(this, monster, logs, damage, actions[choice - 1].name);
    } else if (actions[choice - 1].type === 'run') {
      this.isRun = this.tryRun();
      runMessage(this.isRun, this.name, logs);
    }
  }

Unit Class에 action() 메서드를 통합해서 관리하면 안되나?
=> 이게 더 깔끔할 것 같아서 시도해봤는데 무한루프현상이 발생해서 일단 멈추었다..

3. 플레이어 선택지 동적화

  • 일반공격과 특수공격이 나누어지고, 쿨타임이 생기면서 고정된 선택지가 아닌 행동이 가능한것만 선택지로 출력되도록 설정했다.
// 선택 가능한 액션을 출력해주는 함수
export function possibleActionMessage(actions) {
  let actionMessage = '';
  for (let i = 0; i < actions.length; i++) {
    actionMessage += `${i + 1}.${actions[i].name} `;
  }
  console.log(`\n ${actionMessage}`);
}

행동 가능한 actions 객체를 받아 이름을 추가하고, 출력해준다.

4. 클래스 모듈화

  • 코드가 추가되면서 관리가 힘들어지고, 보기가 힘들어서 클래스를 나누어 주었다.
  • battle.js : Battle 클래스와 배틀관련 메서드가 모여있다.
  • game.js : 게임을 실행하고 진행하는 메서드가 있다.
  • stage.js : Stage 클래스와 스테이지를 관련 메서드가 모여있다.
  • logs.js : 출력되는 로그들을 관리하는 메서드가 모여있다.
  • unit.js : Unit 클래스 및 자식 클래스들과 관련 메서드가 모여있다.
  • utils.js : 연산이나 값을 반환해주는 함수가 들어있다.

2-2. Current Issue

턴순서에 따라 각 객체가 행동권을 가지는데 몬스터가 행동 메서드인 action()을 호출하고 진행되면서 행동이 undefined로 할당되는 이슈가 있다..

 async action(player, monster, logs) {
    if (this.hp > 0) {
      // 쿨타임인 행동을 제외하고 할 수 있는 행동을 정리한다.
      const actions = await Battle.checkPossibleAction(monster);

      // 몬스터의 특수 공격이 쿨타임인지 확인하고,
      // 쿨타임이 아닌 경우 반반확률로 특수 공격을 사용하도록 설정
      // 특수 공격이 아닌 경우는 일반 공격을 하도록 설정
      let attackIs = {};
      if (actions[1] !== undefined) {
        const isSpecialAttack = Math.floor(Math.random() * 100);
        if (isSpecialAttack > 40) {
          attackIs = await Object.assign(attackIs, actions[1]);
          this.actionTypes[1].currentCooltime = this.actionTypes[1].cooltime;
        }
      }

      // 일반 공격
      else if (actions[1] === undefined) {
        attackIs = await Object.assign(attackIs, actions[1]);
        await Object.assign(attackIs, actions[0]);
        this.actionTypes[1].currentCooltime--;
      }

      // 공격 시작
      const damage = await this.attack(attackIs, player);
      attackMessage(monster, player, logs, damage, attackIs.name);
    }
  }
}

위 코드에서 attackIs 가 간헐적으로 undefined로 할당이 되고 있다.

attackIs 는 행동이 확정된 this.attackType의 객체가 담겨있고, 그 객체를 attack() 메서드에 매개변수로 보내어서 attackIs 안에 든 Damage를 사용하게 된다.

Object.assign()을 할때 await 을 주었는데도 작동하지 않는 것 같아서 Promise를 사용하거나 다른 방식으로 코딩을 해야하는지 고민이다..


결론

  1. 출현 몬스터 다양화, 행동 선택지 동기화, 공격 추가, 코드 리팩토링
  2. 간헐적으로 attackIs undefined 할당되는 현상 발생
  3. 아직 해결법은 못찾은 상태
profile
정의로운 사회운동가
post-custom-banner

0개의 댓글