14 KiB
낚시 미니게임 구현 기획안
이 문서는 Kord의 낚시(Fishing) 미니게임 시스템에 대한 설계 방향과 구현 범위를 정리한 기획서입니다.
개요
낚시 미니게임은 기존 미니게임 경제 시스템에서 사용할 재화를 공급하는, 실시간 이모지 조작형 미니게임입니다.
사용자는 1초마다 갱신되는 상태 메시지를 보며 입력을 미리 선택하고, 물고기가 특정 위치에 일정 시간 머문 뒤 그 입력이 맞았는지 판정받습니다. 핵심 목표는 물고기를 끌어와 거리를 줄이는 동시에, 낚시줄 끊어짐 게이지가 가득 차지 않도록 관리하는 것입니다.
이 게임은 단순 슬래시 명령 기반이 아니라, 버튼 조작과 실시간 게이지 변화, 물고기 이모지 표시를 통해 더 직접적인 조작감을 주는 것을 목표로 합니다.
핵심 게임 루프
1. 스레드 입장과 세션 시작
- 사용자는 먼저
/fishing enter명령으로 낚시 전용 스레드에 입장합니다. - 봇은 명령을 실행한 채널에
UserName's Fishing Spot형식의 전용 스레드를 생성합니다. - 이미 같은 사용자의 낚시 스레드가 있으면 기존 스레드를 재사용합니다.
- 실제 낚시 세션 시작은 전용 스레드 안에서
/fishing cast를 입력했을 때만 가능합니다. - 즉, 스레드 생성과 게임 시작은 별도 단계로 분리합니다.
- 봇은 실시간 게임 메시지를 생성합니다.
- 메시지에는 다음 요소가 포함됩니다.
- 중앙에 표시되는 물고기 이모지
- 거리 게이지
- 낚시줄 끊어짐 게이지
- 네 개의 조작 버튼
- 현재 라운드에 예약된 입력
- 다음 판정까지 남은 시간
1-1. 전용 스레드 규칙
- 스레드 이름은 영문 기준
UserName's Fishing Spot형식을 사용합니다. - 낚시 게임 메시지, 버튼 입력, 결과 메시지는 모두 해당 스레드 안에서만 처리합니다.
- 이렇게 하면 일반 채팅이 밀려도 낚시 UI가 섞이지 않고 유지됩니다.
- 한 사용자는 동시에 하나의 낚시 스레드만 활성화할 수 있습니다.
/fishing cast는 자신의 낚시 스레드 안에서만 사용할 수 있습니다.- 성공이나 실패로 게임이 끝나더라도 스레드는 즉시 삭제하지 않습니다.
- 같은 스레드 안에서 다시
/fishing cast를 입력해 연속 플레이할 수 있어야 합니다. /fishing end를 실행했을 때만 세션을 정리하고 스레드를 삭제합니다.
2. 조작 버튼
사용자는 아래 네 가지 버튼 중 하나를 선택할 수 있습니다.
⬅️왼쪽⏺️중앙➡️오른쪽🛌휴식
3. 물고기 위치
- 물고기는 텍스트가 아니라 이모지로 표시됩니다.
- 물고기 이모지는 메시지의 시각적 중앙 라인에 위치해야 합니다.
- 내부 상태상 물고기 위치는 왼쪽, 중앙, 오른쪽 중 하나를 가집니다.
- 물고기는 한 라운드 동안 같은 위치에 일정 시간 머뭅니다.
- 사용자는 그 라운드 안에서 방향 버튼을 미리 입력합니다.
- 물고기가 해당 위치에 일정 시간 이상 머문 뒤 입력이 일치하면 성공 판정이 납니다.
- 입력이 없거나 다른 방향이면
타이밍 빗나감으로 처리됩니다.
4. 거리 게이지
- 물고기를 얼마나 더 끌어와야 하는지를 나타내는 게이지입니다.
- 시작값은
100같은 양수로 설정합니다. - 방향을 맞춘 입력이 성공 판정되면 거리가 감소합니다.
- 휴식을 선택하면 거리가 다시 증가합니다.
- 거리가
0이 되면 낚시에 성공합니다.
5. 낚시줄 끊어짐 게이지
- 낚시줄이 얼마나 끊어질 위기에 가까운지를 나타내는 게이지입니다.
- 방향을 맞춘 입력이 성공 판정되면 이 게이지가 증가합니다.
- 타이밍을 놓치면 소량 증가합니다.
- 휴식을 선택하면 이 게이지가 회복됩니다.
- 게이지가 최대치에 도달하면 즉시 낚시에 실패합니다.
6. 휴식 행동
🛌휴식은 해당 라운드에서 즉시 적용됩니다.- 낚시줄 끊어짐 게이지를 회복합니다.
- 대신 물고기와의 거리가 다시 증가합니다.
- 즉, 휴식은 실패 위험을 낮추지만 진행도를 되돌리는 안전 선택지입니다.
7. 틱 업데이트
- 낚시 상태는 1초마다 갱신됩니다.
- 메시지도 1초 주기로 갱신됩니다.
- 이 갱신 루프는 아래 요소를 처리합니다.
- 현재 라운드 경과 시간 계산
- 입력 예약 상태 반영
- 성공 / 타이밍 빗나감 판정
- 다음 물고기 위치로 라운드 전환
- 게이지 렌더링 갱신
- 세션 종료 판정
UI / UX 요구사항
실시간 메시지 구성
낚시 메시지는 최소한 아래 요소를 포함해야 합니다.
- 물고기 이모지로 표시되는 현재 위치
- 거리 게이지
- 낚시줄 끊어짐 게이지
- 간단한 상태 텍스트
- 현재 예약 입력
- 다음 판정까지 남은 시간
- 예:
입질 중,타이밍 빗나감,휴식 중,성공,실패
게이지 디자인
항상 아래 두 개의 게이지가 동시에 보여야 합니다.
- 거리 게이지
- 성공을 향해 감소하는 게이지
- 휴식 시 다시 증가할 수 있음
- 채워진 블록 / 빈 블록 형태로 표현 가능
- 낚시줄 끊어짐 게이지
- 실패를 향해 증가하는 게이지
- 거리 게이지와 시각적으로 구분되어야 함
예시:
위치: ⬅️ 🐟 ➡️
입력: ⏺️
남은 시간: 2s
거리: ████████░░ 20 / 100
끊어짐: ████░░░░░░ 40 / 100
최종 렌더링은 더 다듬을 수 있지만, 핵심은 물고기 자체를 반드시 이모지로 유지하는 것입니다.
조작 버튼
버튼은 직관적이고 빠르게 눌릴 수 있어야 하므로, 이모지 중심으로 구성합니다.
⬅️⏺️➡️🛌
성공 / 실패 조건
성공
- 거리 게이지가
0이 됩니다. - 보상을 지급합니다.
- 세션을 종료하고 버튼을 비활성화합니다.
실패
- 낚시줄 끊어짐 게이지가 최대치에 도달합니다.
- 세션을 종료하고 버튼을 비활성화합니다.
선택적 시간 제한
- 일정 시간 동안 행동하지 않으면 실패하도록 설계할 수도 있습니다.
- 다만 이 기능은 MVP에는 필수가 아니며, 템포가 느릴 때만 후속 단계에서 검토합니다.
종료 명령
/fishing end명령을 제공해 사용자가 직접 낚시 스레드를 종료할 수 있어야 합니다.- 종료 명령이 실행되면 진행 중인 낚시 세션이 있다면 즉시 정리됩니다.
- 전용 스레드는
/fishing end에서만 삭제됩니다. - 성공/실패 후에는 버튼만 비활성화하고 스레드는 유지합니다.
- 사용자는 같은 스레드 안에서 다시
/fishing cast를 입력해 새 게임을 시작할 수 있어야 합니다.
경제 시스템 연동
낚시는 기존 미니게임 경제를 보조하는 수단으로 설계합니다.
권장 보상 모델
- 낚시에 성공하면
gold를 지급합니다. - 지급된
gold는 현재refinement게임이 사용하는 경제 프로필에 반영합니다. - 이렇게 하면 낚시는 정련 게임을 보조하는 재화 수급형 미니게임이 됩니다.
확장 가능성
후속 버전에서는 아래 요소를 추가할 수 있습니다.
- 물고기 희귀도
- 물고기 크기(cm) 시스템
- 개별 물고기 인벤토리
- 물고기 도감 / 컬렉션
- 미끼 종류
- 낚싯대 및 업그레이드
- 물고기 판매 시스템
Phase 1에서는 직접 gold를 주는 방식이 가장 단순하고 호환성이 좋습니다.
설정 모델
낚시는 공용 미니게임 레지스트리에 등록되는 구조로 가야 합니다.
MiniGame Registry
추가할 키:
fishing
이를 통해 다음이 가능해집니다.
- 길드별 활성화 / 비활성화
- 전용 채널 제한
/minigame을 통한 상태 조회
낚시의 경우 전용 채널 안에서 다시 개별 스레드를 생성하는 방식으로 운영합니다.
기술 구조
서비스
권장 신규 서비스:
FishingService
주요 책임:
- 낚시 전용 스레드 생성 / 삭제
- 세션 생성 / 종료
- 사용자별 활성 낚시 세션 추적
- 틱 업데이트 루프 관리
- 물고기 위치 생성
- 입력 예약 및 라운드 판정
- 보상 정산
인터랙션 처리
권장 커스텀 ID prefix:
fishing_
기존 구조와 일관성을 유지합니다.
music_refine_
영속 데이터
권장 초기 모델:
FishingProfileuserIdguildIdtotalCatchCountsuccessCountfailCountbestCatchRewardlastCastAtcreatedAtupdatedAt
이 정도면 초반 통계 추적에 충분하고, 너무 이르게 인벤토리를 과설계하지 않을 수 있습니다.
도감/크기 확장 시에는 아래 모델을 추가합니다.
FishingCollectionEntryuserIdguildIdfishIdcatchCountbestRaritybestSizeCmlastCaughtAtcreatedAtupdatedAt
이 모델은 유저가 어떤 물고기를 몇 번 잡았는지, 최고 레어도와 최고 크기가 무엇인지 추적하는 데 사용합니다.
물고기 크기 시스템
- 낚시 성공 시 물고기마다
cm단위의 크기를 부여합니다. - 기본 크기 범위는 물고기별 데이터에서 관리합니다.
- 최종 크기는
물고기 기본 크기 범위 × 레어도 보정치로 계산합니다. - 즉, 같은 물고기라도 레어도가 높을수록 더 큰 개체가 등장할 수 있습니다.
- 성공 결과 메시지에는 잡은 물고기의 크기를 함께 표시합니다.
- 도감에는 해당 물고기의 최고 크기를 기록합니다.
도감 (Dex / Collection)
/fishing dex명령을 통해 개인 도감을 조회할 수 있어야 합니다.- 도감에는 아래 정보를 보여줍니다.
- 잡아본 물고기 목록
- 각 물고기의 포획 횟수
- 최고 레어도
- 최고 크기(cm)
- 마지막 포획 시각
- 아직 잡지 못한 물고기는 후속 버전에서 실루엣/잠금 상태로 표시할 수 있습니다.
세션 모델
낚시 플레이 자체는 즉각적인 반응을 위해 메모리 세션 기반이 적합합니다.
권장 런타임 필드:
guildIduserIdthreadIdmessageIdfishPositionselectedActionphaseStartedAtdistancelineTensiontickIntervalexpiresAt
입력 판정 규칙
권장 MVP 규칙은 아래와 같습니다.
- 각 라운드마다 물고기는 하나의 위치에 일정 시간 머뭅니다.
- 플레이어는 그 라운드에서 방향 입력을 미리 예약합니다.
- 물고기가 해당 위치에
특정 시간 이상머문 시점에 입력이 일치하면 - 거리 감소
- 낚시줄 끊어짐 게이지 증가
- 성공 판정 후 다음 라운드로 이동
- 라운드 시간이 끝날 때까지 올바른 입력이 없으면
타이밍 빗나감- 거리 감소 없음
- 소량의 끊어짐 증가
- 휴식을 선택하면
- 낚시줄 끊어짐 게이지 감소
- 대신 거리 증가
- 휴식 적용 후 즉시 다음 라운드로 이동
이 구조는 다음 긴장감을 만듭니다.
- 방향을 잘 예약해 두면 안정적으로 거리 감소를 만들 수 있음
- 너무 공격적으로 당기면 줄이 끊어질 위험이 커짐
- 휴식은 실패를 막아주지만 물고기가 다시 멀어짐
단계별 계획
Phase 1
fishing을 미니게임 레지스트리에 등록/fishing enter추가/fishing cast추가/fishing end추가/fishing enter실행 시UserName's Fishing Spot스레드 생성/fishing cast는 전용 스레드 안에서만 허용- 메모리 기반 낚시 세션 루프 구현
- 1초 주기 메시지 갱신
- 입력 예약형 라운드 판정 구현
- 두 개의 게이지 표시
- 네 개의 이모지 조작 버튼 추가
- 성공 시
gold지급 - 성공/실패 후 스레드 유지
/fishing end실행 시 스레드 삭제
Phase 2
/fishing status추가/fishing ranking추가- 사용자별 낚시 통계 추가
- 낚시 프로필 영속화
- 물고기 이동 패턴 개선
- 보상 밸런스 조정
/fishing dex추가- 물고기 크기(cm) 시스템 추가
- 도감용 포획 기록 저장
- 길드 내 최고 크기 기준 Top 10 랭킹 표시
Phase 3
- 희귀도 체계 추가
- 인벤토리 / 도감 고도화
- 미끼 / 낚싯대 보정치 추가
- 리더보드 지원
- 미포획 물고기 잠금/실루엣 UI 추가
검증 / 테스트
수동 테스트 시나리오
- 허용된 채널에서
/fishing enter실행 UserName's Fishing Spot스레드가 자동 생성되는지 확인- 자신의 낚시 스레드 밖에서는
/fishing cast가 거부되는지 확인 - 낚시 관련 메시지가 스레드 안에서만 진행되는지 확인
- 실시간 메시지에 물고기 이모지와 두 개의 게이지가 보이는지 확인
- 방향 버튼을 미리 눌러 예약 입력이 반영되는지 확인
- 일정 시간 뒤 방향이 맞았을 때 거리 감소가 적용되는지 확인
- 타이밍을 놓치면
타이밍 빗나감으로 처리되는지 확인 - 휴식을 눌렀을 때 끊어짐 게이지가 회복되고 거리가 증가하는지 확인
- 거리
0도달 시 성공 처리되는지 확인 - 끊어짐 게이지 최대 도달 시 실패 처리되는지 확인
- 세션 종료 후 버튼이 비활성화되고 스레드는 유지되는지 확인
- 같은 스레드 안에서 다시
/fishing cast가 가능한지 확인 /fishing end실행 시 스레드가 자동 삭제되는지 확인- 보상이 정상 지급되는지 확인
/minigame설정 기반 채널 제한이 적용되는지 확인
엣지 케이스
- 같은 사용자가 중복으로 세션 시작
- 스레드 삭제 권한이 없을 때 종료 처리
- 세션 종료 후 오래된 버튼 클릭
- 낚시 세션 중 봇 재시작
- 인터랙션 응답 지연
- 1초 주기 메시지 갱신 시 Discord rate limit 영향
참고 사항
- 1초 갱신 루프는 이 게임의 손맛을 좌우하므로 메시지 갱신 성능을 꼭 확인해야 합니다.
- Discord 메시지는 게임 엔진이 아니므로, 순간 반응보다는 명확한 판정 윈도우가 더 중요합니다.
- 최종 설계는 화려함보다 반응성, 명확성, 실패 상태의 가독성을 우선해야 합니다.