
업그레이드 아이템을 샀는지 판단하고 만약 샀다면 해당 버튼의 Interactable = false, '구매 완료' 라는 UI를 활성화 시키는 코드가 있는데 그 코드를...
public enum UpgradeType { Attack, Shield, Jump }
public UpgradeType upgradeType;
private void UpdateBuyUI()
{
switch (type)
{
case UpgradeType.Attack:
if (GameManager.Instance.isAttackUpgrade) { isBought.SetActive(true); myBtn.interactable = false; }
else { isBought.SetActive(false); myBtn.interactable = true; }
break;
case UpgradeType.Shield:
if (GameManager.Instance.isShieldUpgrade) { isBought.SetActive(true); myBtn.interactable = false; }
else { isBought.SetActive(false); myBtn.interactable = true; }
break;
case UpgradeType.Jump:
if (GameManager.Instance.isJumpUpgrade) { isBought.SetActive(true); myBtn.interactable = false; }
else { isBought.SetActive(false); myBtn.interactable = true; }
break;
}
이런 식으로 짜버려서 짜는 중에도 너무 지저분한데 이게 맞나 하던 와중 머리속을 스친 생각은
'아.. Enum 타입은 정수로도 변환해서 쓸 수 있지' 였다.
public enum UpgradeType { Attack, Shield, Jump }
public UpgradeType upgradeType;
private int upgradeIdx => (int)upgradeType; // Enum 타입 정수로 변환
private void UpdateBuyUI()
{
bool isUpgrade = GameManager.Instance.isUpgrade[upgradeIdx];
isBought.SetActive(isUpgrade);
myBtn.interactable = !isUpgrade;
}
짜잔✨ 이제야 좀 볼만한 코드로 바뀐 거 같다. 편하자고 Enum 타입 변수 만들어 놓고 멍청하게 다 쓰고 있었던 내가 참 싫어지는 하루였다.
체력과 쉴드를 UI 오브젝트로 Horizontal Layout Group 을 가진 부모 오브젝트 하위로 생성해서 각각 하나의 배열에 모아서 관리를 하겠다는 생각을 가지고
public void StartGame()
{
SFXManager.Instance.PlayClickSound();
// 비동기로 씬 로딩
SceneLoadManager.Instance.LoadSceneAync("StoryMode", () =>
{
// 씬 로딩이 완료되면 수행할 동작들
GameScore = 0;
// 우선 편의를 위해 player 찾기
player = GameObject.FindWithTag("Player").GetComponent<PlayerController>();
// 구입한 업그레이드 적용
if (isUpgrade[0]) { player.Attack += 50; isUpgrade[0] = false; }
if (isUpgrade[1]) { player.Shield += 3; isUpgrade[1] = false; }
if (isUpgrade[2]) { player._jumpForce += 5f; isUpgrade[2] = false; }
UIManager.Instance.InitHpShieldUI(player.MaxHp);
});
}
[SerializeField] Transform hpContainer; // 부모 오브젝트
private Transform[] hearts; // 하트UI 생성 및 관리할 배열
[SerializeField] GameObject heart_Prefab; // 하트 프리팹
[SerializeField] Transform[] shields; // 쉴드UI 생성 및 관리할 배열
public void InitHpShieldUI(int maxHp)
{
// 플레이어의 최대 Hp만큼 하트 생성
hearts = new Transform[maxHp];
for (int i = 0; i < maxHp; i++)
{
hearts[i] = Instantiate(heart_Prefab, hpContainer).transform;
}
// 플레이어가 가진 쉴드의 수만큼 쉴드 활성화
for(int i = 0; i < GameManager.Instance.player.Shield; i++)
{
shields[i].GetChild(0).gameObject.SetActive(true);
}
}
뭐 여기까진 좋았고 괜찮았다. 아무 문제없이 잘 돌아갔으니까 하지만 문제는 피해를 입거나 회복 아이템을 먹었을 때의 처리가 문제였다.
// 체력 UI 업데이트
public void UpdateHpUI(int maxHp, int hp)
{
GameObject obj = hearts[Math.Max(0, maxHp - hp - 1)].GetChild(0).gameObject;
obj.SetActive(!obj.activeSelf);
}
public void Hit()
{
Hp--;
uIManager.UpdateHpUI(MaxHp, Hp);
if (Hp == 0)
UIManager.Instance.ActiveEndPanel();
}
처음엔 이제 머리로 생각을 해본게 체력이 변경이 될 때 배열의 인덱스를 왼쪽부터 줄여나가야 하니까 '[최대체력 - 체력 - 1] 로 하면 index가 나오지 않나?' 라는 생각을 하고 Hp를 줄이고 인자값을 넘겨서 해봤지만 데미지를 받아 줄어드는 건 상관이 없었지만 체력을 회복할 때 문제가 되는 것이었다.
(최대 체력이 4이고 현재 체력이 2라면 회복을 했을 때 현재 체력값이 3으로 넘어가서
[최대체력(4) - 현재체력(3) - 1] = 0 index는 0으로 2번째 하트가 아닌 1번째 하트가 활성화 됨
그렇게 생각을 하다가 결국 생각해낸 방법은
public void Hit()
{
if (Shield > 0)
uIManager.UpdateShieldUI(Shield--);
else
uIManager.UpdateHpUI(MaxHp, Hp--);
if (Hp == 0)
IManager.Instance.ActiveEndPanel();
}
public void Heal()
{
if(Hp != MaxHp)
uIManager.UpdateHpUI(MaxHp, ++Hp);
}
먼저 값을 넘기고 나중에 ++ 처리를 하는 것이었다. 회복할 때는 먼저 보내줘야 정상 작동한다. 가만히 앉아 모니터를 뚫어져라 쳐다보며 생각해낸 것이다.
줄어들기 전의 하트를 SetActive(false)
늘어난 후의 하트를 SetActive(true)
이게 맞나 싶긴 하지만 그래도 해냈으니 기분은 좋다...

다음주 부터는 이제 C# 언어의 기초 강의를 시작하게 되는데 다시 기초부터 다져갈 수 있는 좋은 기회이니 잘 공부해야겠다.