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개의 전투

다음 프로젝트 아이디어

이번 경험을 바탕으로 다음 프로젝트는:

  1. Canvas API 활용: 실제 캐릭터 일러스트 렌더링
  2. TypeScript 도입: 타입 안정성 확보
  3. SvelteKit 활용: 더 복잡한 상태 관리
  4. 멀티플레이어: WebSocket으로 협동 플레이

결론

JRPG와 비주얼노벨의 통합은 예상보다 훨씬 잘 맞았다. 스토리가 있는 전투, 전투로 이어지는 스토리라는 구조가 게임에 깊이를 더했다.

무엇보다 순수 JavaScript로 게임을 만들면서 상태 관리, UI 업데이트, 게임 루프 설계 등 게임 개발의 기초를 탄탄히 다질 수 있었다.

다음엔 더 큰 스케일의 게임에 도전해보고 싶다!

참고 자료


이 프로젝트의 전체 소스코드는 GitHub에서 확인할 수 있습니다.