오늘은 게임의 전반적인 정보를 저장하는 Manager에 대한 구현 내용을 정리해보겠습니다.
플레이에 필요한 정보를 담당하는 Manager에는 다음과 같은 내용으로 기획하였습니다.
RoundManager
1. 필요한 정보
- 남은 핸드 플레이 횟수
- 남은 버리기 횟수
- 플레이어 보유 코인
- Chip, Mult, Ranking
- 라운드별 목표 점수
- 플레이어 누적 점수
2. 데이터 기록
- Chip, Mult, Ranking, Score의 경우 CardCalculator, HandEvaluator 등에서 계산하기 때문에
Pub-Sub 방식을 활용하여 발행된 이벤트를 구독하여 RoundManager에서 정보를 업데이트한다.
- 남은(플레이, 버리기)횟수의 경우 Bool로 함수를 구현하여 실제 카드 계산 및 버리기가 진행되는 시점에
횟수가 남아있는지, 선택된 카드가 존재하는지를 기반으로 동작을 처리한다.
3. 승패판정
- 라운드별 목표점수 달성여부에 따라 Scene 전환처리를 진행한다.
- 승리시 데이터 기록을 기반으로 획득 코인을 계산하여 Clear Scene으로 전달한다.
<style>
public class RoundManager : MonoBehaviour
{
[Header("InGame Data")]
public int remainHand;
public int remainDiscard;
public int playChip;
public float playMult;
public int targetScore;
public int playerTotalScore;
public int gameRound;
public int playerCoin;
public HandRanking playRanking;
private void Awake()
{
if (Instance == null)
{
Instance = this;
DontDestroyOnLoad(gameObject);
SetRoundInfo();
}
else
{
Destroy(gameObject);
return;
}
if (hand == null) hand = FindFirstObjectByType<Hand>();
UpdateGameInfo();
}
private void OnEnable()
{
CardCalculator.scoreChanged += SetScore;
CardCalculator.chipChanged += SetChipAndMult;
HandEvaluator.rankingChanged += SetRanking;
}
private void OnDisable()
{
CardCalculator.scoreChanged -= SetScore;
CardCalculator.chipChanged -= SetChipAndMult;
HandEvaluator.rankingChanged -= SetRanking;
}
public void IsReachedTargetScore()
{
playChip = 0;
playMult = 0;
if (playerTotalScore < targetScore)
{
if(remainHand > 0)
{
return;
}
else
{
GameSceneManager.Instance.LoadSceneByName("GameOver");
}
}
else
{
GameSceneManager.Instance.LoadSceneByName("Clear");
UpdateGameInfo();
}
}
}
</style>
상황: RoundManager의 경우 데이터 일관성을 유지함과 동시에 전역에서 하나의 정보를 기준으로 처리해야하기 때문에 싱글톤으로 구성하였습니다.
그런데 소모된 버리기횟수, 핸드 플레이 횟수가 Scene전환시 유지되지 못하는 오류가 있었습니다.
원인: 원인은 2가지로 추측됩니다.
1. 싱글톤 파괴
- 싱글톤으로 유지하였지만 하이러키상에서 다른 GameObject하위에 배치하였는데 Scene전환에 따라 싱글톤임에도 불구하고 부모 오브젝트가 파괴되어 같이 파괴되었습니다
2. Scene별 싱글톤 배치
- 최초로 사용되는 Scene에서 싱글톤을 배치하고 다른 Scene에서 배치하지 않아도 되었는데 이를 몰라 사용하는 모든 Scene에 배치하여 데이터가 일관되지 못한게 원인으로 예상됩니다.
해결: 최초 사용되는 InGameScene에서만 배치한 후, Scene전환에 따른 오브젝트 파괴전, 부모 오브젝트를 탈출하는 방식으로 구현할 수 있었지만 편의상 하이러키에서 RoundManager를 최상단에 배치하였습니다.