모바일 게임에서의 캐릭터 뽑기 시스템은 유저의 기대를 높이고, 나아가 게임의 주요 매출원으로 작용합니다. 이 시스템은 단순한 확률 기반을 넘어 천장 시스템(정해진 횟수 안에 고급 캐릭터가 보장되는 시스템), 다중 보상 옵션, 캐릭터 등급에 따른 비율 조정 등의 세부 기능을 갖추어야 합니다. 이번 글에서는 유니티로 데이터 기반의 복합적인 캐릭터 뽑기 시스템을 구축하는 방법을 다루며, 모든 기능을 고려한 고급 코드를 제공하겠습니다.
목차
1. 모바일 캐릭터 뽑기 시스템의 주요 요소
캐릭터 뽑기 시스템은 다음과 같은 주요 기능을 포함합니다:
- 확률 기반 뽑기: 캐릭터 별로 지정된 확률에 따라 뽑기 결과가 결정됩니다.
- 천장 시스템: 일정 횟수 이상 뽑기 실패 시, 특정 등급 이상의 캐릭터가 보장됩니다.
- 보상 조정 시스템: 동일 캐릭터가 중복으로 뽑힐 때의 보상 조정.
- 다중 뽑기: 1회 뽑기와 10회 뽑기 등 여러 회차를 지원하여 유저의 편의성을 높임.
2. 데이터 구조 설계
먼저, JSON 파일로 캐릭터 정보와 확률 등을 외부에서 관리하여 쉽게 데이터를 업데이트할 수 있도록 설계합니다.
캐릭터 데이터(JSON 예시)
{
"characters": [
{
"id": "character_001",
"name": "Fire Warrior",
"rarity": "SSR",
"probability": 0.5,
"isGuaranteed": true
},
{
"id": "character_002",
"name": "Water Mage",
"rarity": "SR",
"probability": 1.0,
"isGuaranteed": false
}
],
"pityCounterMax": {
"SSR": 100,
"SR": 50
}
}
isGuaranteed
필드는 천장 시스템에서 보장할 캐릭터 여부를 나타냅니다. pityCounterMax
는 천장 횟수를 등급별로 정의한 것입니다.
3. 유니티에서 데이터 기반 캐릭터 뽑기 시스템 구현하기
다음으로, 유니티 C# 코드에서 이 JSON 파일을 불러와 뽑기 로직을 적용해봅니다.
캐릭터 데이터 파싱
먼저 JSON 데이터를 읽어와 캐릭터와 천장 정보까지 포함된 객체로 변환합니다.
using System.Collections.Generic;
using System.IO;
using UnityEngine;
[System.Serializable]
public class CharacterData
{
public string id;
public string name;
public string rarity;
public float probability;
public bool isGuaranteed;
}
[System.Serializable]
public class GachaConfig
{
public List<CharacterData> characters;
public Dictionary<string, int> pityCounterMax;
}
public class GachaSystem : MonoBehaviour
{
private GachaConfig gachaConfig;
private Dictionary<string, int> pityCounters = new Dictionary<string, int>();
void Start()
{
LoadGachaConfig();
}
private void LoadGachaConfig()
{
string path = Application.streamingAssetsPath + "/GachaConfig.json";
string jsonString = File.ReadAllText(path);
gachaConfig = JsonUtility.FromJson<GachaConfig>(jsonString);
foreach (var character in gachaConfig.characters)
{
if (!pityCounters.ContainsKey(character.rarity))
pityCounters[character.rarity] = 0;
}
}
}
4. 뽑기 로직 구현: 1회 및 10회 뽑기 + 천장 시스템
뽑기 기능을 구현합니다. 여기에는 뽑기 횟수에 따라 천장 카운터를 체크하고 보장 캐릭터를 반환하는 로직이 포함됩니다.
public CharacterData DrawCharacter()
{
// 천장 시스템 적용
foreach (var rarity in pityCounters.Keys)
{
if (pityCounters[rarity] >= gachaConfig.pityCounterMax[rarity])
{
return GetGuaranteedCharacter(rarity);
}
}
// 랜덤 뽑기
float randomPoint = Random.Range(0f, 100f);
float cumulativeProbability = 0f;
foreach (var character in gachaConfig.characters)
{
cumulativeProbability += character.probability;
if (randomPoint <= cumulativeProbability)
{
UpdatePityCounter(character.rarity);
return character;
}
}
return null;
}
private CharacterData GetGuaranteedCharacter(string rarity)
{
foreach (var character in gachaConfig.characters)
{
if (character.rarity == rarity && character.isGuaranteed)
{
ResetPityCounter(rarity);
return character;
}
}
return null;
}
private void UpdatePityCounter(string rarity)
{
if (pityCounters.ContainsKey(rarity))
{
pityCounters[rarity]++;
}
}
private void ResetPityCounter(string rarity)
{
if (pityCounters.ContainsKey(rarity))
{
pityCounters[rarity] = 0;
}
}
5. 중복 캐릭터 보상 조정
중복 캐릭터를 뽑을 경우, 추가 보상을 제공하거나 중복 캐릭터에 대한 처리를 해주어야 합니다. 예를 들어, 캐릭터의 조각을 보상으로 지급할 수 있습니다.
public void HandleDuplicateCharacter(CharacterData character)
{
if (IsDuplicate(character.id))
{
// 중복 보상 처리 예시
GiveFragmentReward(character);
}
else
{
// 새로운 캐릭터로 등록
AddToInventory(character);
}
}
private bool IsDuplicate(string characterId)
{
// 인벤토리에서 캐릭터 중복 확인 로직
return Inventory.Contains(characterId);
}
private void GiveFragmentReward(CharacterData character)
{
int fragments = CalculateFragmentAmount(character.rarity);
Inventory.AddFragments(character.id, fragments);
}
이 코드는 캐릭터의 중복 여부를 확인하고 중복일 경우 조각을 보상으로 지급하는 방식입니다.
6. 10회 뽑기 구현
10회 뽑기에서는 중복 캐릭터에 대한 처리와 천장 시스템이 적용되어야 합니다.
public List<CharacterData> DrawMultiple(int drawCount)
{
List<CharacterData> drawnCharacters = new List<CharacterData>();
for (int i = 0; i < drawCount; i++)
{
CharacterData character = DrawCharacter();
drawnCharacters.Add(character);
HandleDuplicateCharacter(character);
}
return drawnCharacters;
}
이 함수는 10회 뽑기를 수행하며, 각각의 뽑기에 대해 중복 처리와 천장 시스템을 고려하여 캐릭터를 반환합니다.
7. 장점과 단점
장점
- 유연성: 데이터 구조를 분리하여 캐릭터 추가 및 확률 조정이 유연함.
- 확장성: 천장 시스템과 중복 보상 처리가 포함되어, 유저 경험을 최적화함.
- 유지보수성: JSON 파일을 통해 데이터를 수정할 수 있어, 코드 수정 없이 뽑기 확률이나 캐릭터를 조정 가능.
단점
- 복잡도 증가: 다중 보상 및 천장 시스템이 포함되면서 코드가 복잡해질 수 있음.
- 성능 부담: 대량의 데이터와 연산이 필요한 경우 메모리 최적화가 필요함.
마무리
유니티에서 데이터 기반으로 캐릭터 뽑기 시스템을 구축하면, 게임 운영의 유연성과 유지보수성이 크게 향상됩니다.