업그레이드 버튼
게임에서 특정 기능을 업그레이드할 때, 버튼을 클릭하여 업그레이드를 구매하는 시스템이 필요하다.
using DG.Tweening;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
public class UpgradeButton : MonoBehaviour
{
[Header("References")]
public Button button;
[SerializeField] private GameObject limitPanel;
[SerializeField] private GameObject purchasedPanel;
[SerializeField] private LevelManager _levelManager;
[SerializeField] private UpgradeManager _upgradeManager;
[Header("Text")]
[SerializeField] private TextMeshProUGUI warningText;
[Header("Settings")]
public int cost; // 업그레이드 비용
public int limitLevel; // 업그레이드를 구매할 수 있는 최소 레벨
[HideInInspector]
public bool purchased = false; // 업그레이드 구매 여부
private void Start()
{
warningText.gameObject.SetActive(false);
}
// 업그레이드 버튼 클릭 시 호출되는 함수
public void TryPurchaseUpgrade()
{
SaveManager _saveManager = SaveManager.Instance;
_upgradeManager?.ButtonSound();
if (_levelManager.CurrentLevel < limitLevel)
{
ShowWarningText("레벨이");
return;
}
if (_saveManager.CurrentGold < cost)
{
ShowWarningText("골드가");
return;
}
// 업그레이드 성공
CompleteUpgrade();
}
// 업그레이드를 완료하는 함수
private void CompleteUpgrade()
{
purchased = true;
button.interactable = false; // 버튼 비활성화
transform.SetAsLastSibling(); // 버튼을 content의 맨 아래로 이동
purchasedPanel?.SetActive(true); // 구매 완료 패널 활성화
}
// 경고 메시지를 화면에 표시하는 함수
private void ShowWarningText(string text)
{
if (warningText == null) return;
warningText.text = $"{text} 부족합니다.";
warningText.gameObject.SetActive(true);
warningText.alpha = 1f;
warningText.transform.localPosition = Vector3.zero;
// 기존 애니메이션 중단
warningText.DOKill();
// 텍스트를 위로 이동시키면서 서서히 사라지게 함
warningText.transform.DOLocalMoveY(30, 2f);
warningText.DOFade(0, 2f).OnComplete(() => warningText.gameObject.SetActive(false));
}
// DOTween 애니메이션을 정리하는 함수
private void OnDestroy()
{
DOTween.KillAll();
}
}
업그레이드 버튼 클릭 이벤트 (TryPurchaseUpgrade 함수)
이 함수는 업그레이드 버튼을 클릭했을 때 호출된다.
- SaveManager의 인스턴스를 가져와서 캐싱 (코드의 일관성과 미비한 성능 최적화)
- UpgradeManager의 ButtonSound() 함수를 호출하여 버튼 클릭 소리 재생
- 플레이어 레벨이 limitLevel보다 낮으면 ShowWarningText("레벨이")를 호출하여 경고 메세지 표시하고 종료
- 플레이어 골드가 cost보다 적으면 ShowWarningText("골드가")를 호출하여 경고 메세지 표시하고 종료
- 위의 조건을 통과하면 CompleteUpgrade()를 호출하여 업그레이드 완료
업그레이드 완료 처리 (CompleteUpgrade 함수)
이 함수는 업그레이드가 성공적으로 이루어졌을 때 실행된다.

- purchased 변수를 true로 변경하여 구매 완료 상태 저장 (추후 업그레이드 정보 세이브)
- 버튼을 비활성화(button.interactable = false)하여 더 이상 클릭할 수 없도록 변경
- transform.SetAsLastSibling()을 호출하여 버튼을 UI의 맨 아래로 이동
- purchasePanel을 활성화하여 "구매 완료" 상태 표시
경고 메세지 표시 (ShowWarningText 함수)
이 함수는 플레이어가 골드나 레벨이 부족할 때 경고 메세지를 띄우는 역할을 한다.

- warningText의 텍스트를 "[무엇]이 부족합니다." 형태로 설정
- warningText를 활성화하고, 위치 초기화
- DoKill()을 호출하여 기존 애니메이션이 있으면 중단
- DoLocalMoveY(30, 2f)를 호출하여 텍스트를 2초 동안 30px 위로 이동
- DoFade(0, 2f)를 호출하여 2초 동안 텍스트를 서서히 사라지는 효과
- OnComplete를 통해 애니메이션 종료 후 warningText 비활성화
일부 게임에서 버튼을 여러 번 클릭했을 때처럼 텍스트가 계속 다단식으로 쌓이지는 않는다.
그 기능은 아마 오브젝트 풀링을 통해 UI 메세지를 미리 생성해둔게 아닌가 싶다.
DoTween 정리 (OnDestory 함수)
이 함수는 게임 오브젝트가 삭제될 때 DoTween의 모든 애니메이션을 정리한다.

DoTween 애니메이션이 정리되지 않으면 버튼이 사라졌는데도 애니메이션이 계속 실행되거나,
새로운 씬으로 이동했는데 이전 씬에서 실행되던 애니메이션이 남아있는 등 버그가 발생한다.
Tools → Demigiant → DoTween Utility Panel → Preferences에 Safe Mode가 체크 되어있다면
객체가 파괴됐을 때도 경고 메세지만 나올 뿐 별 문제가 발생하지는 않지만,
DoTween 함수를 썼을 경우 꼭 DoTween.KillAll() 함수를 호출해주고 있다.
업그레이드 구현
업그레이드를 숫자가 아닌 타입으로 관리하기 위해 enum을 사용했다.
public enum UpgradeType
{
LUCKY_GOLD,
SHAKE_BOX,
EASY_REQUEST,
FRUIT_PREVIEW,
GUIDE_LINE,
BLUEBERRY_REMOVE
}
public class UpgradeButton : MonoBehaviour
{
public UpgradeType upgradeType; // 업그레이드 유형
public int cost; // 업그레이드 비용
public void TryPurchaseUpgrade()
{
SaveManager _saveManager = SaveManager.Instance;
...
// 업그레이드 정보 저장
_saveManager.SaveUpgradePurchased(upgradeType, true);
}
}
Enum형
Enum을 사용하면 UpgradeType.LUCKY_GOLD 처럼 직관적인 코드 작성이 가능하다.
클래스 밖에 enum을 선언하면, 해당 enum을 전역적으로 접근할 수 있다.
enum이 여러 클래스에서 공통으로 사용될 때 좋은 방법이다.
클래스 안에 enum을 선언하면, 클래스 내부에서만 접근할 수 있다.
외부에서 사용하려면 UpgradeButton.UpgradeType.LUCKY_GOLD 처럼 사용해야 한다.
업그레이드 버튼
업그레이드 버튼마다 타입(upgradeType)을 인스펙터에서 설정했다.
TryPurchaseUpgrade() 가 호출되면 업그레이드를 구매하고, SaveManager에 저장한다.
public class SaveManager : SingleTon<SaveManager>
{
private bool[] upgradePurchased = new bool[Enum.GetValues(typeof(UpgradeType)).Length];
public bool[] UpgradePurchased
{
get => upgradePurchased;
private set
{
upgradePurchased = value;
}
}
// 업그레이드 구매 여부 저장
public void SaveUpgradePurchased(UpgradeType type, bool purchased)
{
int index = (int)type; // enum을 int로 변환하여 배열 인덱스로 사용
upgradePurchased[index] = purchased;
Debug.Log($"[SaveManager] {type} 업그레이드 구매 완료");
SaveData(); // 데이터 저장
}
}
SaveManager
- upgradePurchased[]: 업그레이드 구매 여부를 저장하는 배열
- UpgradePurchased 프로퍼티: 업그레이드 상태를 읽을 수 있지만, 외부에서 직접 수정하지 못하도록 보호
- SaveUpgradePurchased(): 구매한 업그레이드 저장
Enum.GetValues()
enum은 숫자 배열이 아니기 때문에 UpgradeType.Length를 직접 가져올 수 없다.
Enum.GetValues(typeof(UpgradeType)).Length를 사용하면 자동으로 전체 업그레이드 개수를 가져 올 수 있다.
추후 업그레이드를 추가할 때, 숫자를 직접 변경하지 않아도 자동으로 크기가 조절된다.
public class NPCRequest : MonoBehaviour
{
[Header("Settings")]
public int requestAmount; // 요청 개수
private bool isEasyRequestUnlocked = false; // 업그레이드 여부
private void Start()
{
if (SaveManager.Instance.UpgradePurchased[(int)UpgradeType.EASY_REQUEST])
{
isEasyRequestUnlocked = true;
}
}
public void SetupRequest()
{
// 업그레이드 했으면 1, 아니면 1 ~ 2
requestAmount = isEasyRequestUnlocked ? 1 : Random.Range(1, 3);
}
}
업그레이드 적용 방식
- Start() 에서 SaveManager를 통해 업그레이드 구매 여부 확인
- 업그레이드가 적용되었다면 isEasyRequestUnlocked = true 설정
- SetupRequest() 에서 삼항 연산자를 사용하여 주문 개수를 조정
삼항 연산자를 사용하면 if-else 문을 쓰지 않고 간단하게 조건에 따라 값을 설정할 수 있다.
기존 코드에 추가가 간편하다.
'유니티' 카테고리의 다른 글
| [유니티6] Cinemachine Camera(시네머신 카메라) (0) | 2025.03.22 |
|---|---|
| [유니티] #6 수박 게임 만들기 (코루틴, 랜덤 확률, Line Renderer) (0) | 2025.03.17 |
| [유니티] #4 수박 게임 만들기 (난이도, 씬매니저) (0) | 2025.03.09 |
| [유니티] #3 수박 게임 만들기 (사운드, 애니메이션, 이펙트) (0) | 2025.03.04 |
| [유니티] #2 수박 게임 만들기 (UI) (0) | 2025.02.26 |