2024. 8. 21. 21:34ㆍ[Node.js_6기 본캠프 TIL]
▶ CH 2. Rogue like JAVASCRIPT! 개인 과제
'로그라이크 텍스트게임'을 제작하는 개인 과제가 주어졌다. 어떤 설정을 넣으면 재미있을까 기대에 부풀어 세계관을 짜면서 개발환경을 세팅했다. 해맑은 생각도 잠시, 스켈레톤 코드를 열어보는 순간 머릿 속에 경고등이 요란하게 울리기 시작했다. 내가 이 뼈대를 써서 게임을 만들 수 있다고? JavaScript 문법 종합반 강의를 완주만 했지, 완전히 내 것으로 만들지 못했다는 것을 절절히 깨닫는 순간이었다.
스켈레톤 코드를 이해하려고 한참을 읽었다. 라이브러리를 처음 써보는 만큼, 내가 수정 및 활용할 수 있는 부분이 어디까지인지 파악하는 데에 꽤 많은 시간을 써야 했다.
1) 로비부터 꾸며보자
스켈레톤 코드를 실행했을 때 처음 보이는 화면부터 건드려보기로 했다. 주어진 소스로 그럴듯하게 꾸미는 건 부트스트랩으로 이미 해봤으니, 라이브러리도 비슷하게 활용할 수 있을 것 같았다.
언더바로 만들어진 'RL- Javascript'라는 타이포 부분을 먼저 수정해보기 위해 해당하는 코드를 찾았다.
console.log(
chalk.cyan(
figlet.textSync('RL- Javascript', {
font: 'Standard',
horizontalLayout: 'default',
verticalLayout: 'default'
})
)
);
figlet이라는 라이브러리 기능을 활용해서 타이틀이 구성되고 있다는 것을 확인함과 동시에, cyan이 붙은 것을 보니 chalk은 폰트 컬러를 건드리는 라이브러리구나 싶어 이것저것 테스트 해보기 시작했다.
임시로 잡은 컨셉을 넣어 로비 화면을 수정하다 보니, 이미 구현된 기능들이 눈에 보이기 시작했다. 선택지에 따라 터미널의 console.log가 clear 되는 기능, switch를 활용하여 유저가 입력한 값에 따라 게임을 시작하고 종료하는 로직 등을 활용하면 게임의 완성도를 높일 수 있을 것 같았다.
2) 게임 오버? 게임 클리어?
기본적으로 player가 10개의 스테이지에 존재하는 모든 monster를 처치해야 게임이 클리어되는 구조이다. 그러나 스켈레톤 코드에는 player의 hp가 0이 되어, 게임 오버될 경우에 해당하는 로직과 모든 monster를 처치하고 게임이 클리어될 경우에 대한 로직이 보이지 않았다. 로비 화면을 구성하던 로직들을 가져와서 'Game Over'나 'Game Clear' 문구를 크게 보이게 함과 동시에, 재시작 및 종료 선택지를 주면 될 것 같아서 코드를 재활용하기 시작했다.
// 게임 오버 함수
function gameover() {
console.clear();
// 타이틀 텍스트
console.log(
chalk.cyan(
figlet.textSync('Connect failed', {
font: 'Standard',
horizontalLayout: 'default',
verticalLayout: 'default',
}),
),
);
// 상단 경계선
const line = chalk.magentaBright('='.repeat(50));
console.log(line);
// 메인 텍스트
console.log(chalk.red.bold('Eve와의 연결이 끊어졌습니다.'));
// 설명 텍스트
console.log(chalk.gray('새로운 전투 로봇에 연결하시겠습니까?'));
console.log();
// 옵션들
console.log(chalk.blue('1.') + chalk.white(' 새로운 전투 로봇 연결하기'));
console.log(chalk.blue('2.') + chalk.white(' WN-2s 광산을 포기하기'));
// 유저 입력을 받아 처리하는 함수
function handleUserInput() {
const choice = readlineSync.question('입력: ');
switch (choice) {
case '1':
console.log(chalk.green('정화 작업을 시작합니다.'));
// 여기에서 새로운 게임 시작 로직을 구현
startGame();
break;
case '2':
console.log(chalk.red('WN-2s 광산을 포기합니다.'));
// 게임 종료 로직을 구현
process.exit(0); // 게임 종료
break;
default:
console.log(chalk.red('올바른 선택을 하세요.'));
handleUserInput(); // 유효하지 않은 입력일 경우 다시 입력 받음
}
}
}
// 게임 클리어 함수
function gameclear() {
console.clear();
// 타이틀 텍스트
console.log(
chalk.cyan(
figlet.textSync('Complete', {
font: 'Standard',
horizontalLayout: 'default',
verticalLayout: 'default',
}),
),
);
// 상단 경계선
const line = chalk.magentaBright('='.repeat(50));
console.log(line);
// 메인 텍스트
console.log(chalk.red.bold('정화 작업이 완료되었습니다.'));
// 설명 텍스트
console.log(chalk.gray('행성 관리 프로그램을 종료하시겠습니까?'));
console.log();
// 옵션들
console.log(chalk.blue('1.') + chalk.white(' 종료하기'));
// 유저 입력을 받아 처리하는 함수
function handleUserInput() {
const choice = readlineSync.question('입력: ');
switch (choice) {
case '1':
console.log(chalk.red('행성 관리 프로그램을 종료합니다.'));
// 게임 종료 로직을 구현
process.exit(0); // 게임 종료
break;
default:
console.log(chalk.red('올바른 선택을 하세요.'));
handleUserInput(); // 유효하지 않은 입력일 경우 다시 입력 받음
}
}
}
그리고 얼마 지나지 않아, 슬픈 사실을 깨달았다. 이 기능을 테스트 할 방법이 없었다. 게임 오버 상태가 되려면 player의 hp가 0이 되어야 하는데, 해당 부분은 내가 구현해야 했다. 클리어를 하려면 10 stage의 monster들을 모두 처치해야 하는데 딜을 넣는 부분도 내가 구현해야 했다.
class Player {
constructor() {
this.hp = 100;
}
attack() {
// 플레이어의 공격
}
}
class Monster {
constructor() {
this.hp = 100;
}
attack() {
// 몬스터의 공격
}
class로 player와 monster의 세팅이 각각 분리되어 있었는데, 이 데이터들이 서로 영향을 주게 하는 방법을 찾지 못했다. 게임이 진행될 때마다 Math.random() 메서드로 hp와 attack에 변수를 줘야 하는데, 확률 기능 예시를 봐도 계속 막혀서 더 많은 자료를 찾아봐야 할 것 같다.
function displayStatus(stage, player, monster) {
console.log(chalk.magentaBright(`\n==================== Current Status =====================`));
console.log(
chalk.cyanBright(`[ 제 ${stage} 구역 ] `) +
chalk.blueBright(`| Eve 내구도: ${player.hp} | `) +
chalk.redBright(`| 오염체 생명력: ${monster.hp} |`),
);
console.log(chalk.magentaBright(`=========================================================\n`));
}
const battle = async (stage, player, monster) => {
let logs = [];
while (player.hp > 0) {
console.clear();
displayStatus(stage, player, monster);
logs.forEach((log) => console.log(log));
console.log(
chalk.green(
`\n1. 물리 공격(70%) 2. 반격 준비(30%) 3. 제 ${stage} 구역 방어 시스템 복구(10%)`,
),
);
const choice = readlineSync.question('당신의 선택은? ');
// 플레이어의 선택에 따라 다음 행동 처리
logs.push(chalk.blueBright(`[ Eve의 ${choice}! ]`));
logs.push(chalk.blueBright(`▶ 성공: 오염체에게 ${player.power}의 데미지를 입혔다.`));
}
};
잠시 게임 진행 화면을 건드려보며, 패링 시스템을 넣고 싶은데 어떻게 구현할 수 있을까 고민했다. 일단 일반 공격 로직부터 성공해봐야 알 것 같다. 오늘은 일단 ${ }로 게임 진행에 따라 달라지는 변수를 console.log()에 찍힐 수 있게 한 것만으로 만족하고 마무리하기로 했다. Class에 대한 강의를 정주행하고 다시 작업해봐야겠다.
'[Node.js_6기 본캠프 TIL]' 카테고리의 다른 글
[Node.js_6기 본캠프] CH 2. 개인과제 트러블 슈팅_0823 (5) | 2024.08.23 |
---|---|
[Node.js_6기 본캠프] CH 2. 개인과제 트러블 슈팅_0822 (0) | 2024.08.22 |
[Node.js_6기 본캠프] Today I Learned_0820 (0) | 2024.08.20 |
[Node.js_6기 본캠프] Today I Learned_0819 (0) | 2024.08.19 |
[Node.js_6기 본캠프] Today I Learned_0816 (0) | 2024.08.16 |