본문 바로가기

부트캠프

Tower_Defense_Project

기지 강화하기 로직 트러블 슈팅

 

  • 기본 구상
처음에는 타워를 지정하여 하나씩 강화할 생각이었으나 남들도 다 그런식으로 할꺼라 생각하니 다른방법으로 하고싶어짐
타워를 강화하는게 아니라 기지를 강화하면 타워를 구입할시 나오는 타워의 종류가 바뀌는 방식을 채용했다.

기지 +1 === 타워 +1 을 해줌으로써 타워와 기지의 인덱스를 동일시하여 함께 올라가도록 하면 금방 끝날거라 예상하고 진행했다.

 

 


강화수치를 따로 기록할 것이 아니기때문에 따로 baseDB를 만들 필요성을 느끼지 못하여 하드코딩으로 진행했다.

 

let baseMaxHp = [0, 1000, 2000, 4000, 8000]; //기지 최대 체력
let upgradeIndex = 0; //기지 강화 수치 초기값
let baseHp = 1000; // 기지 체력

//기지 업그레이드 로직
function baseUpgrade() {
  //업그레이드 가능 여부 체크
  if (upgradeIndex < baseMaxHp.length - 1) {
    upgradeIndex++;
    baseHp += baseMaxHp[upgradeIndex]; // 기지 체력에 추가
    console.log('기지 강화 성공');
    placeBase();
  } else {
    console.log('최대치임');
  }
}

 

강화시 체력을 baseMaxHp 배열로 생성해두고 특정 조건을 만족한다면 강화에 성공하는 간단한 방식으로 구현했다.

 

그리고 upgradeIndex를 사용하여 타워의 인덱스도 함께 변하도록 수정

async function placeNewTower() {
  const upgradeTower = towerData[upgradeIndex].towerId;
  const towerInfo = await towerData.find((a) => a.towerId === upgradeTower);

 기지를 강화하여 upgradeIndex가 된다면  타워의 인덱스도 +1 되어 다음단계의 타워가 나온다.

 

하지만 이런식으로 작성하니 현재 골드검증방식과 충돌이 일어났다.

 

현재 골드 검증 방식은 사용한 획득한 골드 - 사용한 골드 를 서버에서 계산하는 방식이라 현재 로직으로는 클라이언트에서 모든 과정이 끝나므로 검증이 불가능한듯함

 

위 과정을 부분폐기하고 db에서 base의 정보를 가져와 사용하는 방식을 채용하기로함

 

//schema.prisma

model Base {
  baseId         Int       @id                 // 베이스 ID
  baselevel             Int       @default(1)         // 베이스 초기 레벨
  baseHp         Int       @default(200)        // 베이스 HP
  baseUpgradeCost     Int       @default(1000)        // 베이스 강화 비용
  img               String                        // 베이스 이미지 파일 경로
}

스키마 파일에 base모델을 추가하고 

 

      //받은 데이터 emit으로 클라이언트에게 보내주기
      socket.emit('datainfo', {
        towers,
        monsters,
        stages,
        bases,
      });

socket을 사용하여 클라이언트로 base의 정보를 보내주고

 

  let baseMaxHp = baseData[upgradeIndex].baseHp; //기지 최대 체력
if (userGold >= baseData[upgradeIndex].baseUpgradeCost) {
    if (upgradeIndex < baseData.length - 1) {
      upgradeIndex++;
      userGold -= baseData[upgradeIndex].baseUpgradeCost;
      baseHp += baseMaxHp; // 기지 체력에 추가
      console.log('기지 강화 성공');
      placeBase();
    } else {
      console.log('최대치임');
    }
  } else {

    console.log('돈없음');
  }

데이터의 값들을 db의 있는 값들로 할당시켜줘 id에따른 체력으로 변경되도록 수정하고 강화가격을 baseId마다 할당

 

이제 클라이언트 로직이 끝났으므로 서버에서 검증을 해줄차례

 

강화정보를 서버에서 저장할 수 있도록 base.model.js를 추가

//base 모델
const bases = {};
//유저의 기지 기록 배열 생성
export const createBase = (accountId) => {
  bases[accountId] = [];
  console.log(`createbase`);
};
//기지 기록 받아오기
export const getBases = (accountId) => {
  return bases[accountId];
};
//기지 세팅
export const setBases = (accountId, basesdata) => {
  return bases[accountId].push(basesdata);
};
//기지 배열 비우기
export const clearBases = (accountId) => {
  console.log(`clearBases`);
  bases[accountId] = [];
};

 

 

base.handler 에서 검증

 

import { getData } from '../init/data.js';

/**
 * @desc 기지 강화 검증
 * @author 우종
 */
export const baseUpgradeHandler = (accountId, data, socket) => {

  //db에 기지 정보
  const { bases } = getData();
  // 강화를 시도할때 돈이 있었는가
  const { currentUpgradeIndex, currentGold, base } = data;

  if (
    currentUpgradeIndex !== getBase[getBase.length - 1].currentUpgradeIndex ||
    currentGold < bases[currentUpgradeIndex].upgradeCost ||
    base.maxHp !== getBase[getBase.length - 1].base.maxHp
  ) {
    return { status: 'fail', message: '너 강화못해' };
  }

  return { status: 'success', message: '강화성공' };
};

하지만 여기서 검증 로직을 짜다보니 상태 동기화에 대한 의문이 생김

 

상태 동기화는 서버에서 검증 후 클라이언트에 값을 보내주는 걸로 알고 있지만

지금 상황에서는 클라이언트에서 강화후 서버로 데이터를 보내주어 검증을 하는 방식이다.

 

즉 물건을 살때 선불이 아닌 후불로 결제가 이루어 지고있는것과 같음

 

정상적인 선불 결제를 위해 코드를 수정

 

import { getData } from '../init/data.js';
import {
  deleteBase,
  getBases,
  getBaseUpgrade,
  setBases,
  setBaseUpgrade,
} from '../models/base.model.js';

/**
 * @desc 기지 강화 검증
 * @author 우종
 */

export const baseUpgradeHandler = (accountId, data, socket) => {
  const { currentUpgradeIndex, currentGold, base } = data;
  const getBase = getBases(accountId);
  const getUpgrade = getBaseUpgrade(accountId);
  if (getUpgrade.length === 0) {
    setBaseUpgrade(accountId, currentUpgradeIndex);
  }
  if (getBase.length === 0) {
    setBases(accountId, data);
    return { status: 'success', message: 'Base Seting' };
  }
  //db에 기지 정보
  const { bases } = getData();
  // 강화를 시도할때 돈이 있었는가
  
  if (
    currentUpgradeIndex !== getBase[getBase.length - 1].currentUpgradeIndex ||
    currentGold < bases[currentUpgradeIndex].baseUpgradeCost ||
    base.maxHp !== getBase[getBase.length - 1].base.maxHp
  ) {
    return { status: 'fail', message: 'Upgrade Fail' };
  }

  const index = currentUpgradeIndex + 1;
  const gold = currentGold - bases[currentUpgradeIndex].baseUpgradeCost;
  const hp = base.maxHp + bases[currentUpgradeIndex].baseHp;
  setBaseUpgrade(accountId, index);

  console.log(getBaseUpgrade(accountId)); // 이거 가져다 골드 검증하면됨
  deleteBase(accountId, 0);
  socket.emit('base', {
    index,
    gold,
    hp,
  });
  return { status: 'success', message: 'Upgrade Success' };

클라이언트에서 기지가 생성될 경우의 초기값을 받아오고 현재 유저가 가지고있는 돈이 db에 정의된 강화 비용과 같은지 비교하고 현재 인덱스를 비교하여 조건이 만족할 경우 socket.emit으로 클라이언트로 강화된 후의 값을 전달한다..

 

  serverSocket.on('base', (data) => {
    upgradeIndex = data.index;
    userGold = data.gold;
    baseHp = data.hp;
    placeBase();
  });

클라이언트에서는 해당 값을 받아 변수에 할당시키고 할당된 값을 다시 그려준다.

//최종 강화 로직

function baseUpgrade() {

  let baseMaxHp = baseData[upgradeIndex].baseHp; //기지 최대 체력

  //업그레이드 가능 여부 체크

  if (userGold >= baseData[upgradeIndex].baseUpgradeCost) {
    if (upgradeIndex < baseData.length - 1) {
    //서버로 쏴주는 부분
      serverSocket.emit('event', {
        handlerId: 35,
        currentUpgradeIndex: upgradeIndex, //현재 강화 단계
        currentGold: userGold, //현재 골드

        base: base,
      });

      console.log('기지 강화 성공');
      // placeBase();
    } else {
      console.log('최대치임');
    }
  } else {
    console.log('돈없음');
  }
}

 

마지막으로 골드 검증을 위해 모델을 추가하여 남겨둠

//최종 base 모델
const bases = {};
const baseUpgrade = {};
//유저의 기지 기록 배열 생성
export const createBase = (accountId) => {
  bases[accountId] = [];
  baseUpgrade[accountId] = [];
  console.log(`createbase`);
};

//기지 기록 받아오기
export const getBases = (accountId) => {
  return bases[accountId];
};

//기지 업글 단계
export const getBaseUpgrade = (accountId) => {
  return baseUpgrade[accountId];
};

//기지 세팅
export const setBases = (accountId, basesdata) => {
  return bases[accountId].push(basesdata);
};

//기지 업글 단계 저장
export const setBaseUpgrade = (accountId, upgrade) => {
  return baseUpgrade[accountId].push(upgrade);
};

//유저 특정 기지 제거
export const deleteBase = (accountId, selectedBaseIndex) => {
  console.log(`deleteBase`);
  return bases[accountId].splice(selectedBaseIndex, 1);
};

//기지 배열 비우기
export const clearBases = (accountId) => {
  console.log(`clearBases`);
  bases[accountId] = [];
};

 

'부트캠프' 카테고리의 다른 글

일단박조KPT  (2) 2024.10.16
IOCP 의 개념  (0) 2024.10.14
메모리  (3) 2024.10.10
BCNF  (1) 2024.10.09
변수 표기법  (0) 2024.10.08