새소식

알고리즘 테스트 ⏲/JavaScript

[JavaScript] 미니 전투 게임 제작

  • -
미니 전투 게임 제작

간단한 텍스트 게임이다. 다이어그램대로 작성했는데 자질구레한 기능들을 구현해 넣다보니 코드가 좀 지저분해진 것 같다. (플래그 변수 넣고 빼는 부분은 나중에 스스로 헷갈려서 버그 수정에 힘이 좀 들었다.) 오류 나올만한 부분은 모두 제거했고 문제는 게임이 재미가 .. 어차피 구현 훈련을 위한 목적이니까. 좀 더 게임스럽게 만들려면 그래픽도 추가하고 아이템이나 다양한 몬스터들도 추가를 하면 될 것 같다. 객체 지향으로 재설계하는게 이런 게임 만들기 프로그램에선 더 깔끔할 것 같긴 하다.

개인 풀이

다이어그램

알고리즘

const $startGame = document.querySelector(".startGame");
const $myInfo = document.querySelector(".myInfo");
const $enemyInfo = document.querySelector(".enemyInfo");
const $form = document.querySelector(".form");
const $inputName = document.querySelector(".inputName");
const $normalMode = document.querySelector(".normalMode");
const $fightMode = document.querySelector(".fightMode");
const $name = document.querySelector(".name");

const $nm_adventure = document.querySelector(".nm_adventure");
const $nm_rest = document.querySelector(".nm_rest");
const $nm_exit = document.querySelector(".nm_exit");

const $fm_attack = document.querySelector(".fm_attack");
const $fm_heal = document.querySelector(".fm_heal");
const $fm_exit = document.querySelector(".fm_exit");

const $hp = document.querySelector(".hp");
const $defense = document.querySelector(".defense");
const $power = document.querySelector(".power");
const $exp = document.querySelector(".exp");
const $level = document.querySelector(".level");

const $enemyHp = document.querySelector(".enemyHp");
const $enemyPower = document.querySelector(".enemyPower");

const colorPack = {
  lowHp: "rgb(255, 245, 160)",
  death: "rgb(102, 12, 12)",
  alive: "white",
  attacked: "red",
  black: "black",
  white: "white",
};
const my = {
  hp: 100,
  defense: 2,
  power: 25,
  exp: 0,
  level: 1,
};
const enemy = {
  hp: 0,
  power: 0,
};

$myInfo.style.display = "none";
$enemyInfo.style.display = "none";
$form.style.display = "none";

const handleStart = () => {
  $form.style.display = "block";
  $startGame.style.display = "none";
  $inputName.focus();
};

$hp.textContent = my.hp;
$power.textContent = my.power;
$exp.textContent = my.exp;
$level.textContent = my.level;
$defense.textContent = my.defense;

let adventureFlag = true;
const handleNmAdventure = () => {
  if (my.hp === 0 || !adventureFlag) return;
  handleFightMode();
};

let restFlag = true;
const handleNmRest = () => {
  if (!restFlag) return;
  adventureFlag = false;
  const restInterval = setInterval(() => {
    if (my.hp >= 30) {
      $myInfo.style.backgroundColor = colorPack.lowHp;
    }
    if (my.hp >= 60) {
      $myInfo.style.backgroundColor = colorPack.alive;
    }
    if (my.hp >= 100) {
      restFlag = false;
      adventureFlag = true;
      my.hp = 100;
      $hp.textContent = my.hp;
      clearInterval(restInterval);
      return;
    }
    my.hp += 1;
    $hp.textContent = my.hp;
  }, 20);
};

const handleNmExit = () => {
  location.reload(true);
};
const handleNormalMode = () => {
  if (my.hp < 100) restFlag = true;
  adventureFlag = true;
  healFlag = true;
  $normalMode.style.display = "block";
  $fightMode.style.display = "none";
  $enemyInfo.style.display = "none";
  $nm_adventure.addEventListener("click", handleNmAdventure);
  $nm_rest.addEventListener("click", handleNmRest);
  $nm_exit.addEventListener("click", handleNmExit);
};

let attackFlag = true;
const handleEnemyAttack = () => {
  attackFlag = false;
  healFlag = false;

  setTimeout(() => {
    $hp.style.color = colorPack.attacked;
    console.log(my.defense);
    my.hp -= enemy.power - my.defense;
    setTimeout(() => ($hp.style.color = colorPack.black), 350);

    // 내 체력이 0인 경우
    if (my.hp <= 60) {
      $myInfo.style.backgroundColor = colorPack.lowHp;
    }
    if (my.hp <= 20) {
      $myInfo.style.backgroundColor = colorPack.death;
    }
    if (my.hp <= 0) {
      my.hp = 0;
      $hp.textContent = my.hp;
      setTimeout(() => handleNormalMode(), 2000);
      return;
    } else {
      $hp.textContent = my.hp;
    }
    attackFlag = true;
    healFlag = true;
  }, 1000);
};
let enemyAttackRange = 0;
const increaseExp = () => {
  let expCount = 0;
  let maxExp = parseInt(100 / my.level); // 현재 레벨에서 적 한명 처치당 증가할 수 있는 최대 exp
  console.log(maxExp);
  const expInterval = setInterval(() => {
    expCount += 1;
    my.exp += 1;
    $exp.textContent = my.exp;
    if (my.exp === 100) {
      expCount = 0;
      clearInterval(expInterval);
      my.exp = 0;
      $exp.textContent = 0;
      my.power += 15;
      $power.textContent = my.power;
      my.level += 1;
      $level.textContent = my.level;
      my.defense += 4;
      $defense.textContent = my.defense;
      enemyAttackRange += 5;
      return;
    }
    if (expCount === maxExp) {
      expCount = 0;
      $exp.textContent = my.exp;
      clearInterval(expInterval);
      console.log(my.exp);
      return;
    }
  }, 20);
};
const handleFmAttack = () => {
  if (attackFlag === false) return;
  // 내 턴 공격

  $enemyHp.style.color = colorPack.attacked;
  enemy.hp -= my.power;
  $enemyHp.textContent = enemy.hp;
  setTimeout(() => ($enemyHp.style.color = colorPack.white), 350);

  // 적 체력이 0인 경우
  if (enemy.hp <= 0) {
    attackFlag = false;
    healFlag = false;
    $enemyHp.textContent = 0;
    setTimeout(() => {
      $enemyInfo.style.display = "none";
    }, 1000);
    setTimeout(() => handleNormalMode(), 2000);

    // 경험치 상승
    increaseExp();
    return;
  }
  // 상대 턴 공격
  handleEnemyAttack();
};
let healFlag = true;
const handleFmHeal = () => {
  if (!healFlag) return;
  healFlag = false;
  attackFlag = false;
  let maxHealAmount = 0;
  const healInterval = setInterval(() => {
    if (my.hp >= 20) {
      $myInfo.style.backgroundColor = colorPack.lowHp;
    }
    if (my.hp >= 60) {
      $myInfo.style.backgroundColor = colorPack.white;
    }
    if (my.hp === 100) {
      clearInterval(healInterval);
      my.hp = 100;
      $hp.textContent = 100;
      return;
    }
    if (maxHealAmount === 30) {
      clearInterval(healInterval);
      return;
    }
    my.hp += 1;
    $hp.textContent = my.hp;
    maxHealAmount += 1;
  }, 20);
  setTimeout(handleEnemyAttack, 2000);
};
const handleFmExit = () => {
  handleNormalMode();
};

const handleFightMode = () => {
  $fightMode.style.display = "block";
  $normalMode.style.display = "none";
  $enemyInfo.style.display = "block";

  enemy.hp = Math.floor(Math.random() * 8 + 2) * 10 * my.level; // level * 20 ~ 100
  enemy.power = Math.floor(Math.random() * 5 + 3) * my.level + enemyAttackRange;

  $enemyHp.textContent = enemy.hp;
  $enemyPower.textContent = enemy.power;
  attackFlag = true;

  $fm_attack.addEventListener("click", handleFmAttack);
  $fm_heal.addEventListener("click", handleFmHeal);
  $fm_exit.addEventListener("click", handleFmExit);
};

const handleStartGame = (e) => {
  e.preventDefault();
  const name = $inputName.value;
  $name.textContent = name;
  console.log(name);
  $form.style.display = "none";
  $myInfo.style.display = "block";

  handleNormalMode();
};

$startGame.addEventListener("click", handleStart);
$form.addEventListener("submit", handleStartGame);
<!DOCTYPE html>
<html lang="en">
  <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>Document</title>
    <style>
      body {
        font-weight: 600;
      }
      .mainScreen {
        background-color: rgb(34, 34, 34);
        width: 540px;
        height: 280px;
        display: flex;
        flex-direction: column;
        align-items: center;
        position: relative;
      }
      .startGame {
        width: 140px;
        height: 20px;
        margin-top: 20px;
      }
      .myInfo {
        margin-top: 15px;
        width: 92%;
        height: 40px;
        padding: 10px;
        background-color: white;
      }
      .enemyInfo {
        color: white;
        margin-top: 15px;
        width: 92%;
        height: 40px;
        padding: 10px;
        background-color: rgb(122, 50, 255);
      }
      .stats,
      .enemyStats {
        display: flex;
      }
      .stats div,
      .enemyStats div {
        width: 50px;
        height: 100%;
      }

      .normalMode {
        display: none;
        position: absolute;
        background-color: rgb(110, 255, 154);
        width: 25%;
        padding: 10px;
        height: 25px;
        bottom: 0;
      }
      .fightMode {
        display: none;
        position: absolute;
        background-color: tomato;
        width: 25%;
        padding: 10px;
        height: 25px;
        bottom: 0;
      }
    </style>
  </head>
  <body>
    <main class="mainScreen">
      <button class="startGame">게임시작</button>
      <div class="nameInfo">
        <form class="form">
          <span style="color: white">닉네임을 입력하세요</span>
          <input class="inputName" type="text" />
          <button>확인</button>
        </form>
      </div>
      <div class="myInfo">
        <div class="name"></div>
        <div class="stats">
          체력:
          <div class="hp"></div>
          공격력:
          <div class="power"></div>
          방어력:
          <div class="defense"></div>
          경험치:
          <div class="exp"></div>
          레벨:
          <div class="level"></div>
        </div>
      </div>

      <div class="enemyInfo">
        <div class="enemyName">무작위 적</div>
        <div class="enemyStats">
          체력:
          <div class="enemyHp"></div>
          공격력:
          <div class="enemyPower"></div>
        </div>
      </div>

      <div class="normalMode">
        <button class="nm_adventure">모험</button>
        <button class="nm_rest">휴식</button>
        <button class="nm_exit">종료</button>
      </div>
      <div class="fightMode">
        <button class="fm_attack">공격</button>
        <button class="fm_heal">회복</button>
        <button class="fm_exit">도망</button>
      </div>
    </main>

    <script src="index.js"></script>
  </body>
</html>

 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.