보관됨

My Monster Maker 제작기

몬스터 아트워크 커스텀 조립 및 스탯 리포트 생성기

나만의 몬스터 생성기 메인 화면
1 / 1

몬스터 가등록 리스트 및 주사위 배틀 선택 화면

나만의 몬스터 생성기 (My Monster Maker) 제작기

GCP 클라우드 네이티브 환경 기반 AI 몬스터 수집 및 주사위 배틀 모바일 PWA 서비스


1. 문제 정의 및 기획 배경

최근 AI 생성 기술이 급속히 발전하면서 고유한 일러스트와 서사를 손쉽게 제작할 수 있게 되었습니다. 저는 사용자가 단순히 고정된 몬스터 캐릭터를 뽑는 것에서 벗어나, 본인만의 애정과 유대감을 가질 수 있도록 자신이 직접 지은 이름과 원하는 성향 설정을 반영해 창조된 고유한 AI 몬스터를 가지면 어떨까 하는 발상에서 출발했습니다. 하지만 몬스터를 생성할 때마다 고비용의 이미지 생성 API를 무제한 호출하면 서버 유지 비용에 극심한 타격이 올 것이 자명했습니다. 이를 극복하기 위해 비용을 철저하게 분산시키는 '하이브리드 생성 파이프라인'을 기획하고, 이와 함께 주사위의 눈에 따라 연쇄적인 시너지가 터지는 턴제 배틀 시스템을 탑재해 가볍고 친근하게 플레이할 수 있는 풀스택 모바일 PWA 서비스를 개발하게 되었습니다.


2. 핵심 사양 및 구현 목표

  • 2단계 하이브리드 생성 설계: 텍스트 형태의 몬스터 등록은 무료로 지원하고, 게임을 플레이해 얻은 승점(VP)을 소모하여 최종 AI 일러스트와 풍부한 고유 스토리를 영구 생성하는 수익형 흐름 구축.
  • 주사위(d6) 기반 콤보 배틀 엔진: 다수의 주사위를 굴려 콤보 룰(트리플, 스트레이트, 올제로)을 체크하고 대미지를 연쇄 합산하는 직관적이면서 전략적인 전투 알고리즘 제작.
  • 서버리스 CI/CD 완성: 백엔드를 Docker 가상화 컨테이너로 감싸고, GCP Artifact Registry와 Cloud Run을 연계해 업데이트 시 중단 없는 롤링 배포 실현.
  • 핵심 기술 스택:
    • Frontend: Vite, React, TypeScript, Tailwind CSS (PWA 빌드 구성)
    • Backend: Node.js, Express (Docker 컨테이너화)
    • Database: Cloud Firestore
    • AI Core: Google Gemini 2.5 Flash Image API, @google/generative-ai
    • Infra & DevOps: GCP Cloud Build, GCP Artifact Registry, GCP Cloud Run, Google Cloud Storage (GCS)

3. 기술 검증 및 트러블슈팅

[1단계] 무료/유료 결합 몬스터 가등록 모듈 개발

유저가 이름과 성격을 입력하면 1차 데이터베이스 메타데이터(스탯 및 스킬 자동 조합)만 무료로 생성해 보존하는 가등록 흐름을 제작했습니다.

[2단계] 난이도 게이지 계약 미니게임 연동

몬스터의 특성 스탯 값에 따라 타이밍 바의 속도와 판정 너비가 비례 제어되는 인게임 실시간 계약 미니게임을 설계했습니다.

[3단계] d6 주사위 배틀 판단 공식 설계

전투 시 캐릭터의 민첩/주사위 개수만큼 6면체 주사위를 굴리고, 콤보 매칭을 정밀 판독하는 콤보 엔진 모듈(battleEngine.ts)을 구현했습니다.

R&D 및 트러블슈팅

1. GCP Artifact Registry 비공개 인증 및 Docker 빌드 실패

  • 문제: Cloud Build를 사용하여 빌드 파이프라인을 기동할 때, multi-stage Docker 빌드 도중 Firebase 관리용 비공개 서비스 계정 JSON 키 파일 경로가 유실되거나 접근 권한이 누출되어 빌드가 빈번하게 크래시되었습니다.
  • 해결: 빌드 디렉터리에 기밀 키 파일을 직수입하지 않고, GCP Secret Manager를 빌드 스크립트(cloudbuild.yaml)에 주입해 Firebase 접속에 필요한 인증 토큰과 키들을 환경변수로 안전하게 온디맨드 로딩하여 도커 빌드를 통과시켰습니다.

2. PWA 모바일 노치(Notch) 및 하단 홈 바 영역 safe-area-inset 깨짐 현상

  • 문제: 사용자가 모바일 기기 홈 화면에 PWA 바로가기 아이콘을 추가한 뒤 실행하면, 기기 상단 상태바 영역과 하단 홈 이동 바에 웹 UI 버튼과 리포트 카드가 겹쳐 눌리지 않거나 글자가 잘리는 UI 결함이 발생했습니다.
  • 해결: HTML index.html meta 태그에 viewport-fit=cover 속성을 설정하고, Tailwind 레이아웃 최상단 래퍼에 padding-top: env(safe-area-inset-top)padding-bottom: env(safe-area-inset-bottom) 스타일 변수를 강제 주입해 기기 디바이스 영역 침범을 완벽 방어했습니다.

4. 핵심 기능 및 구현 코드

  • 하이브리드 생성 파이프라인: 1단계 무료 생성 후, 주사위 배틀을 통해 획득한 승점(VP)을 가치 있게 소모하여 몬스터의 상세 일러스트(Gemini AI)를 획득하는 구조 설계.
  • 주사위(d6) 기반 콤보 배틀 엔진 (battleEngine.ts):
    • 올제로(All Zero): 0이 3개 이상 등장 시 적용.
    • 트리플(Triple): 동일 주사위 눈 3개 이상 등장 시 배율 적용.
    • 스트레이트(Straight): 연속된 3개의 숫자(예: [1,2,3]) 매칭 시 특수 대미지 판정.
  • GCP Cloud Run 무중단 배포: Docker 빌드로 로컬 편차를 제거하고 원스톱 배포 환경 구축.

핵심 코드 (Combat Combo & Dice Rolling Engine)

// battleEngine.ts - 콤보 판정 및 주사위 롤러 import type { Character } from '../types'; export type ComboType = 'triple' | 'straight' | 'allzero' | null; export interface ComboCheckResult { comboType: ComboType; comboName: string; matchedValues?: number[]; } export function checkCombo(diceResults: number[]): ComboCheckResult { const normalDice = diceResults.filter((r) => r !== -1); if (normalDice.length < 3) return { comboType: null, comboName: '' }; // 1. 올제로 검출 (0이 3개 이상) const zeroCount = normalDice.filter((r) => r === 0).length; if (zeroCount >= 3) { return { comboType: 'allzero', comboName: '올제로', matchedValues: [0, 0, 0] }; } // 2. 트리플 검출 (같은 눈이 3개 이상) const valueCounts = new Map<number, number>(); normalDice.forEach((val) => { if (val > 0) valueCounts.set(val, (valueCounts.get(val) || 0) + 1); }); for (const [value, count] of valueCounts.entries()) { if (count >= 3) { return { comboType: 'triple', comboName: '트리플', matchedValues: [value, value, value] }; } } // 3. 스트레이트 검출 (연속된 3개 숫자) const positiveValues = normalDice.filter((v) => v > 0); if (positiveValues.length >= 3) { const sorted = [...positiveValues].sort((a, b) => a - b); const unique = [...new Set(sorted)]; for (let i = 0; i <= unique.length - 3; i++) { if (unique[i + 1] === unique[i] + 1 && unique[i + 2] === unique[i + 1] + 1) { return { comboType: 'straight', comboName: '스트레이트', matchedValues: [unique[i], unique[i + 1], unique[i + 2]], }; } } } return { comboType: null, comboName: '' }; }

5. 미래 확장성 및 고도화 계획

  • 실시간 소켓 배틀 매칭 레이어 이식 (Socket.io 클러스터링)
  • 두 몬스터의 특성 가중치를 합성하여 신종 등급으로 진화시키는 AI 합성 파이프라인

메타데이터

상태실험 보관 (Archived)
최종 갱신2026.05.31

기술 스택

ReactHTML5 CanvasjszipTailwind