스테이지 별 기본 점수 획득 변화를 구현하기 전에 아이템 획득 시 점수에 반영되고, 서버로 보내 관리하는 핸들러를 간단하게 구성하였다.
클라이언트 측 Score.js getItem 메서드
getItem(itemId) {
console.log(itemId);
switch (String(itemId)) {
case '1':
this.score += 10;
break;
case '2':
this.score += 20;
break;
case '3':
this.score += 30;
break;
case '4':
this.score += 40;
break;
default:
console.log('알 수 없는 아이템입니다.');
}
sendEvent(4, { itemId });
}
현재 클라이언트 측에 표시되는 점수 상 변화는 구현하였다. 이 과정에서 문제가 있었으나 itemId를 문자열로 수정하여 해결하였다.
핸들러 ID 4는 서버 측에 새로 작성한 item.handler.js의 getItem 함수인데, 임시 작성 상태이다.
// handlerMapping.js
import { moveStageHandler } from './stage.handler.js';
import { gameEnd, gameStart } from './game.handler.js';
import { getItem } from './item.handler.js';
const handlerMappings = {
2: gameStart,
3: gameEnd,
4: getItem,
11: moveStageHandler,
};
export default handlerMappings;
import { getGameAssets } from '../init/assets.js';
export const getItem = (uuid, payload) => {
const { items } = getGameAssets();
console.log(payload.itemId);
const itemId = payload.itemId;
console.log(`Received itemId: ${itemId}`);
return { status: 'success', message: `get Item! ()` };
};
아직은 미완성이기 때문에 검증 과정이 필요하다.
이후에 게임 첫번째에는 클라이언트에서 서버로 보내는 스테이지 정보와 서버의 정보가 일치하여 정상적으로 스테이지 변경이 확인되지만, 이후 두번째 게임부터는 Current stage mismatch 메시지가 발생하는 것을 확인하였다.
확인을 위해 console.log()를 찍어보았다..
export const moveStageHandler = (userId, payload) => {
// 유저의 현재 스테이지 배열을 가져오고, 최대 스테이지 ID를 찾는다.
let currentStages = getStage(userId);
if (!currentStages.length) {
return { status: 'fail', message: 'No stages found for user' };
}
// 오름차순 정렬 후 가장 큰 스테이지 ID 확인 = 가장 상위의 스테이지 = 현재 스테이지
currentStages.sort((a, b) => a.id - b.id);
const currentStage = currentStages[currentStages.length - 1];
// payload 의 currentStage 와 비교
if (currentStage.id !== payload.currentStage) {
console.log(currentStage.id); // 확인용
console.log(payload.currentStage); // 확인용
return { status: 'fail', message: 'Current stage mismatch' };
}
.....
첫번째 게임에는 if문의 조건인 currentStage.id !== payload.currentStage, 즉 클라이언트에서 받은 payload.currentStage와 서버에서 가져온 currentStage.id가 일치하는지 확인하는 과정에서 문제가 없었지만, 두번째 게임부터 터미널의 확인용 콘솔로그가 찍히기 시작하는 것을 확인하였다.
1000
1003
1000
1004
payload.currrentStage, 즉 클라이언트 측에서 이전 판 플레이 이후 초기화되지 않은 currentstage 값이 전달되는 것을 확인하였다.
강의 중 sendEvent를 통해 적용해야하는 함수의 핸들러 id를 보내는 예시를 클라이언트 측 index.js 의 reset() 함수에 적용했던 것으로 기억해서, 리셋마다 클라이언트 측의 기존 currentstage 값을 초기화하도록 코드를 추가하였다.
function reset() {
hasAddedEventListenersForRestart = false;
gameover = false;
waitingToStart = false;
score.reset(); //
score.currentStage = 1000; // 초기 스테이지 ID로 설정
ground.reset();
cactiController.reset();
gameSpeed = GAME_SPEED_START;
sendEvent(2, { timestamp: Date.now() });
}
이후 두번째 게임, 세번째 게임에서도 스테이지 검증이 정상적으로 진행되었다.
근데 찾아보니 Score.js 에도 점수 초기화 부분이 있길래 index.js 수정은 원복하고 더 간단하게 Score.js를 수정하였다.
reset() {
this.score = 0;
this.currentStage = 1000;
}
똑같이 정상적으로 실행된다. 더 깔끔하게 개선된 것 같다.
이후 스테이지별 아이템 언락 로직을 구성해보았다.
essets 폴더의 파일들을 직접 임포트하는 것, 서버에서 로드한 에셋파일을 전달받는 것도 어려움이 있어서 일단 클라이언트 측 파일에 하드코딩한 후 테스트를 진행하였다.
class ItemController {
unlockItem = {
name: 'item_unlock',
version: '1.0.0',
data: [
{ id: 101, stage_id: 1000, item_id: [1, 2] },
{ id: 201, stage_id: 1001, item_id: [1, 2] },
{ id: 301, stage_id: 1002, item_id: [1, 2] },
{ id: 401, stage_id: 1003, item_id: [1, 2, 3] },
{ id: 501, stage_id: 1004, item_id: [2, 3] },
{ id: 601, stage_id: 1005, item_id: [2, 3] },
{ id: 701, stage_id: 1006, item_id: [2, 3, 4] },
{ id: 801, stage_id: 1007, item_id: [2, 3, 4] },
{ id: 901, stage_id: 1008, item_id: [3, 4] },
],
};
...
// currentStage를 매개변수로 받도록 수정
createItem(currentStage) {
// unlockItem.data 에서 currentStage의 대한 아이템 언락 정보 찾기
const unlockInfo = this.unlockItem.data.find(
(unlockInfo) => unlockInfo.stage_id === currentStage,
);
if (!unlockInfo) {
console.log('정보를 불러올 수 없습닏다.', currentStage); // 확인용
return;
}
// 불러온 unlockInfo의 item_id베열을 itemIds로 선언
const itemIds = unlockInfo.item_id;
// 배열에서 랜덤으로 선택
const index = this.getRandomNumber(0, itemIds.length - 1);
const selectedItemId = itemIds[index];
console.log('Selected Item ID:', selectedItemId); // 확인용
// 선택된 아이템 정보 가져오기
const itemInfo = this.itemImages[selectedItemId - 1]; // 아이템 ID가 1부터 시작한다고 가정
const x = this.canvas.width * 1.5;
const y = this.getRandomNumber(10, this.canvas.height - itemInfo.height);
const item = new Item(
this.ctx,
itemInfo.id,
x,
y,
itemInfo.width,
itemInfo.height,
itemInfo.image,
);
// 생성된 아이템 배열에 추가
this.items.push(item);
}
...
위 과정을 거쳐 unlock 아이템만 생성한다.
이후 index.js의 gameLoop에서 ItemController의 update 메서드를 호출하는데, currentStage를 전달받을 수 있도록 수정하였다.
...
update(gameSpeed, deltaTime, currentStage) {
if (this.nextInterval <= 0) {
this.createItem(currentStage); // currentStage를 인자로 전달
this.setNextItemTime();
}
...
해당 Score 메서드에서 스테이지 가 변경될때 currentStage가 증가하고, 이로 인해 itemController에서 해당 스테이지에 맞는 아이템이 생성된다. (추가적으로 하드코딩된 scorePerSecond를통해 스테이지별로 점수 기본 획득량의 변화를 구현하였다.)
update(deltaTime) {
//
const currentStageData = this.stageAsset.data.find((stage) => stage.id === this.currentStage);
const scorePerSecond = currentStageData ? currentStageData.scorePerSecond : 0;
const goalScore = currentStageData ? currentStageData.score : 0;
// 점수 증가
this.score += scorePerSecond * (deltaTime / 2000); // deltaTime을 초 단위로 변환하여 점수 증가
// 스테이지 변경 시 이벤트 전송
if (Math.floor(this.score) >= goalScore && this.stageChange) {
this.stageChange = false; // 중복 전송 방지
console.log('Current Stage before sending:', this.currentStage);
sendEvent(11, { currentStage: this.currentStage, targetStage: this.currentStage + 1 });
this.currentStage += 1;
}
// 스테이지 변경 스코어 도달 전에는 stageChange를 true로 설정
if (Math.floor(this.score) < goalScore) {
this.stageChange = true; // 다음 스테이지 이벤트를 가능하게 함
}
}
오늘은 클라이언트 측에서 필수기능대로 게임이 진행되도록 구현에 힘썻고, 해당 메서드 들에서 이벤트를 전송하여 서버에서 처리하는 부분을 중점적으로 개발하여 마무리할 예정이다.