오늘부터 15일간 2D 기반의 게임 개발을 주제로 개인 프로젝트를 진행합니다.
제가 기획하는 프로젝트는 로그라이크 덱빌딩 장르인 Balatro를 모작하는 것을 주제로 선정하였습니다.
Balatro(발라트로) 모작을 하게된 이유로 부트캠프에 참여하면서 들었던 얘기중 카드 게임이 기본기를 다지는데 좋은 소재라는 얘기를 들었습니다.
지금의 시점에서는 기획을 통한 게임 개발을 진행하는 것보다 배운 내용들을 복습 및 응용해보는 게임개발이 필요하다고 생각하였습니다.
따라서 발라트로의 핵심 동작 흐름을 파악하고 이를 직접 구현해보는 것을 목표로 설정하였습니다.
오늘은 발라트로 모작 개발에 있어 필요한 게임 이해하기 및 개발에 필요한 설계, 기획에 대한 내용을 정리해보겠습니다.
발라트로의 핵심 흐름은 다음과 같습니다.
1. 플레이어가 게임을 시작하면 전체 카드팩에서 8장의 카드가 손패로 드로우된다. 2. 사용자가 손패에서 최대 5장까지 점수계산을 위해 카드를 고른다. 3. 고른 카드를 기반으로 실시간으로 카드 족보가 계산된다. 4. 플레이어가 카드 계산하기를 누르면 해당 족보에 기여된 카드의 숫자에 따른 점수가 계산된다. 5. 카드별 점수가 계산되면 조커카드가 하나씩 발동하면서 보너스 점수가 계산된다. 6. 마지막으로 선택되지 않은(핸드에 있는)카드중 점수 계산에 영향을 주는 카드를 판별한다. 8. 판별된 카드의 추가 점수 계산을 통해 최종 점수계산이 이루어진다. 9. 최종 점수 계산이 누적되며, 총점수가 해당 라운드 목표점수를 넘어서면 게임에 승리한다. 10. 만약 카드 점수 계산 가능 횟수를 모두 소진하였음에도 넘지 못한다면 GameOver된다.
카드 Class
부모 클래스로 지정.
카드 이름, 카드 설명, 카드 이미지를 공통으로 갖도록 선언.
카드 삭제(판매 or 사용), 카드 추가 등을 virtual을 이용한 메소드로 생성 후, override를 통해 자식클래스에서 개별 로직을 구현하여 상황에 맞게 사용하도록 구성
string cardId;
string cardName;
string description;
virtual void Add()
virtual void Remove()
PlayCard(손패 / 문양, 숫자, 계산할 Mult, Chips 필요)
string suit;
int rank;
int baseChip; // 카드별 고유 Chips
JokerCard(조커 카드 / 희귀도, 효과 , 계산할 Mult, Chips 필요)
string rarity;
float addmult; // +, x Mult Float - 일부 배수가 1.2, 1.3이렇게 나옴
int addChip;
int sellPrice;
TaroCard(소모성 - 카드 변경(변경, 강화, 제거…))
int sellPrice;
Type effectType; // 강화, 변경, 파
PlanetCard(소모성 - 포커 족보별 효과(Chips, Mult) 변경)
```jsx
int sellPrice;
float addMult; // 사용시 올라갈 Mult수치
int addChip; // 사용시 올라갈 Chip수치
CardType targetHand; // 강화할 족보 대상
```
⇒ 3,4 카드의 경우 사용시 사라지는데 중간 부모 클래스로 한번 더 묶어서 관리?
바우처카드(소모성, 플레이동안의 상태강화)
계산 로직 Class
선택한 카드 (최대 5장)을 기반으로 족보 계산
특수 효과로 일부 족보가 완화된 경우 고려 필요(ex. 스트레이트, 플러쉬, 스티플의 조건이 5장 → 4장이 되었을 경우 족보 계산시 조건 판별 후 따로 처리)
bool hasFourJoker = false; // 스트레이트, 플러쉬, 스티플 판정완화 조커 보유 여부
struct HandResult{
CardType handType; // 족보
List<PlayingCard> scroeCards; // 족보판정에 사용된 카드 리스트 (추후 점수 판정)
}
족보 확인 후 각 카드의 숫자 점수 계산
카드별 강화효과(+ Chips, *Mult) 확인 후 추가
List or Queue로 저장해둔 Joker효과에 따른 강화효과 확인 후 추가
최종 계산된 정보를 currentScore에 저장 및 targetScore와 비교
int chip;
float munt;
int targetScore;
상태 변경(StateMachine) Class
State : Title / Playing / Shop / SelectCard / Result / GameOver
Command:
메인 화면 → 플레이 : Play, Draw, SubmitCard, Reward, GameOver
플레이 → Reward : 게임 결과에 따른 보상 coin 획득
플레이 → GameOver: 진행하면서 기록한 게임 결과를 출력
GameOver → 메인 화면 : 메인화면으로 돌아가기를 통한 Title 복귀
Reward → 상점 : ReRoll, Buy Card / Back(상점 → 플레이화면)
상점 → 카드효과 선택 : SelectCardEffect, Back(선택 넘기기)
GameState currentState; // 현재 게임 상태 (State)
GameCommand currentCommand; // 현재 게임 명령 (Command)
int earnedCoinInRound // Playing -> Reward 로 넘길 코인
List<string> roundHistory; // Gameover시 출력할 이번 판 기록
int enti; // 현재 단계
게임 화면 Class
Deck & Hand
Deck
최초 셔플(Fisher & Swap)
전체 덱 리스트 관리 (전체덱 → 셔플 → 손패로 전달)
Hand
1. 셔플된 카드 획득
2. 카드 배치 설정( Rank or Suit에 따른 정렬)
3. 카드 선택에 따른 처리 (버리기 or 점수계산 처리. 버리기시 Deck에서 선택한 수만큼 가져오고 버린카드에 저장)
List<PlayingCard> fullDeck;
List<int> discardDeck; // 버린패 (UI상에서 전체패중 소모된 패를 확인하는 용도)
List<int> hands; // 현재 손패 - List로 한 이유는 손패가 고정되지않기 때문
int[] selectHands; // Play하는 카드 (5로 고정하되 5미만의 숫자로 플레이할 경우 나머지 패를 -1로 고정)
Queue<int> selectIndex; // hands에서 선택한 카드 index.
Order sortCards; // Rank or Suit 정렬
JokerSlot
조커 배치(구매 or 카드효과를 통해 생성된 순서대로 배열)
판매
JokerCard[] currentJokers;
int maxJokerSlot = 5;
Inventory
소지중인 타로/행성 카드, 선택 및 사용
타로의 경우 특정 조건(카드 선택 시) 충족에 따라 카드 사용 가능
판매
List<TaroCard> currentTaroCard;
List<PlanetCard> currtnePlanetCard;
// Taro, Planet 사용 기록 저장 - Taro카드중 마지막 사용한 카드 한번 더 사용 카드를 위함
Stack<TaroCard> usedTaroHistory;
Stack<PlanetCard> usedPlanetHistory;
상점 화면 Class
Shop
3가지 영역 분리 ( 바우처, 소모품 카드, 종합)
구매, 리롤, 상점 이용 종료 기능 구현
특정 소모품 구매시 화면 전환
int rerollCost;
// Taro, Planet를 합친 하나의 리스트를 만들어서 표시할 예정
List<JokerCard> jokerList;
List<TaroCard> taroList;
List<PlanetCard> planetList;
Scene 분할
Title Scene
메인 화면으로서 게임 시작 버튼이 있는 곳
GameOver시 돌아오는 화면
Game Start시 Playing Scene으로 이동한다
Playing Scene
In-Game 화면. 실제 플레이가 이루어지는 곳
게임의 결과에 따른 Result Scene의 Win or Lose로 연결된다.
Result Scene
Win
Playing Scene에서 목표 점수를 도달하였을 때 이동되는 화면
게임의 결과와 함께 클리어 보상을 안내한다.
안내가 완료되면 Shop Scene으로 이동한다
Lose
Playing Scene에서 목표 점수를 도달하지 못하였을 때 혹은 주어진 라운드를 모두 클리어하였을 때 이동되는 화면
최종 진행되었던 결과(도달했던 점수, Game Over의 경우 - 몇라운드까지 갔는지 )를 보여준다.
Shop Scene
오늘은 현재까지 준비한 발라트로 개발에 대한 핵심 게임 기획서를 정리하는 시간을 가졌습니다.
처음으로 제대로된 게임 개발을 하는 만큼 배웠던 내용을 바로 응용해보지는 못할 것을 알기에 일일단위로 구현한 내용과 트러블슈팅에 대해서 정리하며 복습을 통해 기본기를 다져가보겠습니다