Back-End/UnityScript(C#)

Unity Script(유니티 스크립트) 캐릭터 능력치 스탯(status), UI script 구현 방법(게임 개발, 게임 UI, 게임 능력치 설정, 싱글톤 패턴, C#)

개발자 DalBy 2024. 7. 22. 16:54
반응형

Unity Script(유니티 스크립트) 캐릭터 능력치 스탯(status), UI script 구현 방법(게임 개발, 게임 UI, 게임 능력치 설정, 싱글톤 패턴)

 

이번에 유니티 스크립트(unity script)에서 캐릭터 능력치 스탯 관련한 script를 작성하는 방법을 포스팅하겠습니다.

 

 

먼저 하이라키뷰에서 Canvas와 player 게임 오브젝트를 생성하고 

하이라키뷰
하이라키뷰

GUI 정보를 처리 할 C# 스크립트 MainCanvasController와 플레이어 능력치 정보를 처리 할 PlayerController 클래스를 생성하였습니다. 

 

구성한 스탯 정보는 다음과 같습니다.

스탯 정보
스탯 정보

유저의 스탯 포인트에 따라 체력, 매력, 지식, 행운에 대한 능력 포인트를 증가시킬 수 있습니다.

 

 

먼저 PlayerController 스크립트 코드는 다음과 같습니다.

    // 기초 스탯
    private int healthValue;
    private int attractionValue;
    private int knowledgeValue;
    private int luckValue;

    // 보조 스탯
    private int thinkingValue;
    private int languageValue;
    private int faithValue;
    private int stressValue;

    private int timeValue;
    private int statusPoint;

    private static PlayerController instance = null;
    private static readonly object padlock = new object();

    public int HealthValue { get => healthValue; set => healthValue = value; }
    public int AttractionValue { get => attractionValue; set => attractionValue = value; }
    public int KnowledgeValue { get => knowledgeValue; set => knowledgeValue = value; }
    public int LuckValue { get => luckValue; set => luckValue = value; }
    public int ThinkingValue { get => thinkingValue; set => thinkingValue = value; }
    public int LanguageValue { get => languageValue; set => languageValue = value; }
    public int FaithValue { get => faithValue; set => faithValue = value; }
    public int StressValue { get => stressValue; set => stressValue = value; }
    public int TimeValue { get => timeValue; set => timeValue = value; }
    public int StatusPoint { get => statusPoint; set => statusPoint = value; }

    private PlayerController() { }

    public static PlayerController Instance 
    { 
        get
        {
            if (instance == null)
            {
                instance = FindObjectOfType<PlayerController>();

                if (instance == null)
                {
                    GameObject singletonObject = new GameObject();
                    instance = singletonObject.AddComponent<PlayerController>();
                    singletonObject.name = typeof(PlayerController).ToString();
                }

                // singleTon instance scene moving, can't not destory
                DontDestroyOnLoad(instance.gameObject);
            }
            return instance;
        }
    }

    // 초기 셋팅
    private static void InitialSettings()
    {
        instance.healthValue = 5;
        instance.attractionValue = 5;
        instance.knowledgeValue = 5;
        instance.luckValue = 5;

        instance.thinkingValue = 10;
        instance.languageValue = 5;
        instance.faithValue = 0;
        instance.stressValue = 0;

        instance.statusPoint = 10;
    }

    void Awake()
    {
        // create instance
        if (instance == null)
        {
            instance = this;

            // InitialSettings start
            InitialSettings();

            DontDestroyOnLoad(this.gameObject);
        }
        else if (instance != this)
        {
            Destroy(gameObject);
        }
    }

초기 셋팅 메소드 InitialSettings()를 딱 한번 실행하여, 초기 데이터를 대입합니다. 그리고 싱글톤 패턴을 활용하여 모든 스크립트상 해당 데이터를 받아 처리할 때, 동일한 데이터가 공유될 수 있게 처리하였습니다. 코드 작성 후 player 오브젝트에 추가합니다.

 

테스트 실행시 하이라키뷰에서 코드가 실행된 모습을 확인 할 수 있습니다.

 

 

MainCanvasController 스크립트 코드는 다음과 같습니다.

    // alert
    public GameObject alertPanel;
    public TMP_Text alertMsg;
    
    // GUI status
    public TMP_Text HealthValue;
    public TMP_Text AttractionValue;
    public TMP_Text KnowledgeValue;
    public TMP_Text LuckValue;
    public TMP_Text ThinkingValue;
    public TMP_Text LanguageValue;
    public TMP_Text FaithValue;
    public TMP_Text StressValue;

    public TMP_Text StatusPointValue;
    public TMP_Text TimeValue;

    // 이전 값
    private int prevHealthValue;
    private int prevAttractionValue;
    private int prevKnowledgeValue;
    private int prevLuckValue;
    private int prevStatusPoint;
    
    // 각각 (+) 버튼 이벤트
    public void StatusPointButton(string param)
    {

        if (prevStatusPoint > 0)
        {
            switch (param)
            {
                case "Health":
                    HealthValue.text = (prevHealthValue + 1).ToString();
                    prevHealthValue++;
                    break;

                case "Attraction":
                    AttractionValue.text = (prevAttractionValue + 1).ToString();
                    prevAttractionValue++;
                    break;

                case "Knowledge":
                    KnowledgeValue.text = (prevKnowledgeValue + 1).ToString();
                    prevKnowledgeValue++;
                    break;

                case "Luck":
                    LuckValue.text = (prevLuckValue + 1).ToString();
                    prevLuckValue++;
                    break;

            }

            StatusPointValue.text = (prevStatusPoint - 1).ToString();
            prevStatusPoint--;

        } else
        {
            Debug.Log("스탯 부족");
            return;
        }

    }
    
    // alert 활성화 처리
    IEnumerator AlertCoroutine()
    {
        alertMsg.text = "능력치가 적용되었습니다.";
        alertPanel.SetActive(true);
        yield return new WaitForSeconds(2.0f);
        alertPanel.SetActive(false);

    }

    // 스탯 저장 처리
    public void StatusPointSave()
    {

        PlayerController.Instance.HealthValue = prevHealthValue;
        PlayerController.Instance.AttractionValue = prevAttractionValue;
        PlayerController.Instance.KnowledgeValue = prevKnowledgeValue;
        PlayerController.Instance.LuckValue = prevLuckValue;
        PlayerController.Instance.StatusPoint = prevStatusPoint;

        AbilityTextSetting();
        PopupPanelsControl();

        StartCoroutine(AlertCoroutine());

        StopCoroutine(AlertCoroutine());

    }
    
    // 스탯 취소 처리
    public void StatusPointCancel()
    {
    // 이전 스탯 값
        prevHealthValue = PlayerController.Instance.HealthValue;
        prevAttractionValue = PlayerController.Instance.AttractionValue;
        prevKnowledgeValue = PlayerController.Instance.KnowledgeValue;
        prevLuckValue = PlayerController.Instance.LuckValue;
        prevStatusPoint = PlayerController.Instance.StatusPoint;
        AbilityTextSetting();
        //PopupPanelsControl();
    }
    
    // GUI text 처리
    public void AbilityTextSetting()
    {
        // 초기 설정 getting
        HealthValue.text = PlayerController.Instance.HealthValue.ToString();
        AttractionValue.text = PlayerController.Instance.AttractionValue.ToString();
        KnowledgeValue.text = PlayerController.Instance.KnowledgeValue.ToString();
        LuckValue.text = PlayerController.Instance.LuckValue.ToString();
        ThinkingValue.text = PlayerController.Instance.ThinkingValue.ToString();
        LanguageValue.text = PlayerController.Instance.LanguageValue.ToString();
        FaithValue.text = PlayerController.Instance.FaithValue.ToString();
        StressValue.text = PlayerController.Instance.StressValue.ToString();
        StatusPointValue.text = PlayerController.Instance.StatusPoint.ToString();
    }
    
    
    void Awake()
    {
        //StartCoroutine(Access());

        // 초기 설정 getting
        AbilityTextSetting();

        // 이전 스탯 값
        prevHealthValue = PlayerController.Instance.HealthValue;
        prevAttractionValue = PlayerController.Instance.AttractionValue;
        prevKnowledgeValue = PlayerController.Instance.KnowledgeValue;
        prevLuckValue = PlayerController.Instance.LuckValue;
        prevStatusPoint = PlayerController.Instance.StatusPoint;

    }

시작할 때, 현재 설정되어있는 static 값을 이전 값 변수(prev)에 초기화하여 해당 이벤트에 따라 능력치 적용 여부 값을 처리하였습니다.

 

시각적 표현으로는 canvas에서 각각 Text 필드에 해당 오브젝트를 추가하여 확인할 수 있게 처리하였습니다.

(AbilityTextSetting() 메소드 호출시 해당 처리된 값으로 Text 필드가 초기화 됨)

 

canvas 인스펙터뷰는 다음과 같습니다.

 

해당 능력치에 (+)버튼을 누르면 StatusPointButton(string param) 메소드를 호출하게 됩니다. 각 버튼에는 해당 param값을 설정하여 해당 조건 스위치문에 값이 처리될 수 있게 하였습니다. prev 변수를 활용하여 실제 공유되는 값은 실제 값에 영향받지 않고 GUI만 보여준 후, 스탯 저장시 입력받은 스탯으로 실제 값이 저장됩니다. 만약 취소 버튼을 누르면 StatusPointCancel() 메소드를 호출하여 prev값을 기존 값으로 다시 초기화 합니다.

 

마지막으로 코루틴을 이용하여 저장 시, 알림 팝업창을 잠시 노출하고 없어지는 효과도 추가하여 그럴듯한(?) 효과도 추가해 보았습니다.

 

 

테스트 결과는 다음과 같습니다.

 

 

 

 

반응형