JRPG와 비주얼노벨을 통합한 웹 게임 개발 회고
JRPG와 비주얼노벨을 통합한 웹 게임 개발 회고
프로젝트 개요
순수 JavaScript로 JRPG의 전투 시스템과 비주얼노벨의 스토리텔링을 결합한 웹 게임을 개발했다. 무거운 라이브러리 없이 가볍게 브라우저에서 실행 가능한 게임을 목표로 했다.
왜 이 조합인가?
JRPG의 매력
- 턴제 전투의 전략성
- 캐릭터 성장 시스템
- 명확한 게임 루프
비주얼노벨의 강점
- 깊이 있는 스토리텔링
- 선택지를 통한 몰입감
- 낮은 진입장벽
이 두 장르를 결합하면 전투와 스토리가 유기적으로 연결된 게임을 만들 수 있다고 판단했다.
핵심 설계 결정
1. 순수 JavaScript 선택
// 라이브러리 없이 상태 관리
const gameState = {
currentScene: 0,
playerStats: { hp: 100, mp: 50, atk: 15, def: 5 },
enemyStats: null,
battleActive: false
};
이유:
- 빠른 로딩 시간
- 의존성 없음
- 학습 목적으로 순수 JS 실력 향상
2. 시나리오 기반 시스템
const scenarios = [
{
type: 'dialogue',
character: '리온',
text: '더 강해져야 해...',
choices: [
{ text: '계속 훈련하기', next: 1 },
{ text: '휴식 취하기', next: 2 }
]
},
// ...
];
장점:
- 스토리 추가/수정 용이
- 비개발자도 콘텐츠 작성 가능
- JSON으로 분리 가능
3. 단일 HTML 파일 구조
모든 것을 하나의 HTML 파일에 담았다. CSS와 JavaScript를 인라인으로 포함시켜 배포와 공유가 간편하도록 했다.
구현 과정에서의 도전
도전 1: 전투와 스토리의 자연스러운 전환
문제: 전투 화면과 대화 화면을 어떻게 부드럽게 전환할까?
해결:
function startBattle(battleKey) {
document.getElementById('visualNovelScreen').classList.remove('active');
document.getElementById('battleScreen').classList.add('active');
// 전투 초기화
}
CSS 클래스 토글과 fadeIn 애니메이션으로 자연스러운 전환 구현.
도전 2: 전투 밸런싱
문제: 너무 쉬우면 지루하고, 너무 어려우면 답답하다.
해결책:
- 플레이어 기본 공격력: 15, 방어력: 5
- 첫 번째 적(고블린): HP 60, 공격력 8
- 방어 시스템: 데미지 50% 감소
- MP 자원 관리로 전략성 추가
여러 번 테스트하며 적절한 수치를 찾았다.
도전 3: 상태 관리
문제: 전투 중 HP/MP 변화, 레벨업 등 상태를 어떻게 관리할까?
해결:
function updateBattleUI() {
const player = gameState.playerStats;
document.getElementById('playerHp').textContent = player.hp;
const hpPercent = (player.hp / player.maxHp) * 100;
document.getElementById('playerHpBar').style.width = hpPercent + '%';
}
단일 gameState 객체로 중앙 집중식 상태 관리. UI는 이 상태를 반영하기만 하면 됨.
배운 점
1. 게임 루프의 중요성
비주얼노벨 파트 → 선택 → 전투 → 성장 → 다음 스토리
이 명확한 루프가 있어야 플레이어가 다음에 무엇을 해야 할지 알 수 있다.
2. 피드백의 중요성
addBattleLog(`${player.name}의 공격! ${enemy.name}에게 ${damage} 데미지!`);
전투 로그, HP 바 애니메이션 등 즉각적인 피드백이 게임의 만족감을 크게 높인다.
3. 스코프 관리
처음엔 모든 기능을 넣고 싶었지만, 핵심 메카닉에 집중하는 게 중요했다.
포기한 기능:
- 인벤토리 시스템
- 복잡한 스킬 트리
- 사이드 퀘스트
결과: 30분 안에 완주 가능한 응집도 높은 게임
기술 스택 정리
- HTML5: 구조
- CSS3: 그라데이션, 애니메이션, 플렉스박스
- JavaScript (ES6+): 게임 로직
- Local Storage: 세이브 기능(미구현)
성능 최적화
1. CSS 애니메이션 활용
JavaScript 애니메이션 대신 CSS transition 사용:
.bar-fill {
transition: width 0.5s;
}
2. 이벤트 위임
버튼마다 리스너를 다는 대신 onclick 인라인 핸들러로 간소화.
3. 최소한의 DOM 조작
상태 변경 시 필요한 부분만 업데이트.
개선 가능한 점
1. 코드 분리
현재는 모든 게 한 파일에 있어 유지보수가 어렵다. 모듈화하면 좋을 것 같다.
// scenarios.js
export const scenarios = [...];
// battle.js
export class BattleSystem { ... }
// main.js
import { scenarios } from './scenarios.js';
import { BattleSystem } from './battle.js';
2. 세이브/로드 시스템
Local Storage를 활용하면 진행 상황 저장 가능.
function saveGame() {
localStorage.setItem('gameSave', JSON.stringify(gameState));
}
function loadGame() {
const saved = localStorage.getItem('gameSave');
if (saved) {
Object.assign(gameState, JSON.parse(saved));
}
}
3. 사운드 추가
Web Audio API로 BGM과 효과음을 넣으면 몰입감이 크게 향상될 것.
4. 반응형 디자인 개선
현재는 데스크톱 중심. 모바일에서도 쾌적하게 플레이할 수 있도록 개선 필요.
통계 및 결과
- 개발 기간: 약 6시간
- 코드 라인 수: ~600줄 (HTML/CSS/JS 포함)
- 파일 크기: ~20KB (압축 전)
- 플레이 타임: 약 20-30분
- 시나리오 분기: 13개 씬
- 전투 시스템: 2개의 전투
다음 프로젝트 아이디어
이번 경험을 바탕으로 다음 프로젝트는:
- Canvas API 활용: 실제 캐릭터 일러스트 렌더링
- TypeScript 도입: 타입 안정성 확보
- SvelteKit 활용: 더 복잡한 상태 관리
- 멀티플레이어: WebSocket으로 협동 플레이
결론
JRPG와 비주얼노벨의 통합은 예상보다 훨씬 잘 맞았다. 스토리가 있는 전투, 전투로 이어지는 스토리라는 구조가 게임에 깊이를 더했다.
무엇보다 순수 JavaScript로 게임을 만들면서 상태 관리, UI 업데이트, 게임 루프 설계 등 게임 개발의 기초를 탄탄히 다질 수 있었다.
다음엔 더 큰 스케일의 게임에 도전해보고 싶다!
참고 자료
이 프로젝트의 전체 소스코드는 GitHub에서 확인할 수 있습니다.