메타버스기반게임콘텐츠기획/그날의 강의

(10-2) 유니티unity 클리커 게임 만들기 2 - 클릭하면 골드가 올라가는 스크립트

Queenut 2021. 12. 28. 22:05

어제에 이어서

이번엔 클릭하면 골드가 올라가도록 만들어 보자.

 

 

일단 UI에 '골드량'과 '클릭 당 골드량'을 볼 수 있어야 한다.

(봐야 잘못된 걸 알고 수정하니까...)

 

 

 * UI를 관리하는 오브젝트 만들기

어제는 데이터 총관리(DataController)를 만들었으니 이번엔 UI 총관리(UIManager)를 만들어보면...

 

새로운 C# 스크립트 - 제목은 UIManager .

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

UnityEngine.UI : 네임스페이스 추가. 유니티엔진의 UI 클래스를 가져오겠다는 의미.

 

 

public class UIManager : MonoBehaviour
{
    public Text goldDisplayer;
    public Text goldPerClickDisplayer;
    public DataController dataController;
...

1. 2개의 디스플레이 텍스트를 각각 public 수식어로 넣어주고

2. DataController 인스턴스화.

 

 

    void Update()     //매 업데이트마다 적용되도록.
    {
        goldDisplayer.text = "Gold : " + dataController.GetGold();
        goldPerClickDisplayer.text = "Gold Per Click : " + dataController.GetGoldPerClick();
    }

매 프레임 업데이트마다 적용되도록 Update 메서드에

각 디스플레이가 어떻게 보여야 하는지 설정한다.

 

.text는 각 디스플레이에 우리가 변수로 설정한게 text라서 그렇고,

 

또한 여기에 접근 가능한 이유는 우리가 위에 .UI를 추가했기 때문이다.

 

text로 쓴 만큼 이 곳에 들어갈 수 있는 것은 문자열 뿐이라서 "Gold : " 가 있는 것. 만약 숫자만 넣어주고 싶다면

= dataController.GetGold().ToString()

으로 형변환해서 쓸 수도 있다.

아예 저걸 ""로 묶으면 저 글씨가 그대로 디스플레이에 나타난다...

 

 

보조강사님 꿀팁+++자료형별 최대나 최소값은 Int32.MaxValue 같은 식으로 C#에서 상수형태로 가져올 수 있으니 나중에 조건식 같은거 만드실때 참고.

 

 

완성된 스크립트.

UIManager.cs
0.00MB

 

 

 


 

 

 

그럼 이제 이 UIManager를 어떤 오브젝트에 넣어주느냐?

모든 UI가 들어있는 Canvas에 넣어주도록 하자.

각 디스플레이는 같은 이름을 가진 각 오브젝트를,

데이터 컨트롤러에는 데이터 컨트롤러 오브젝트를.

 

 


 

 

 * 클릭당 골드량을 업데이트 한다!

비록 업데이트에 골드가 소비되지만, 결과적으론 클릭 당 골드량이 올라가서 더 많은 골드를 얻을 수 있게 만든다.

 

새로운 C# 스크립트 : UpgradeButton 생성.

 

진행하기에 앞서 그렇게 '추가된 클릭 당 골드량'을 저장하는 메서드를 만든다.

    public void AddGoldPerClick(int newGoldPerClick)
    {
        m_goldPerClick += newGoldPerClick;
        SetGoldPerClick(m_goldPerClick);
    }

이 메서드는 DataController에 만들어야 한다!!!

 

 

 

다시 UpgradeButton 클래스에 들어가서,

using UnityEngine.UI;

유니티 엔진의 API를 가져오겠다고 선언하고,

 

 

앞으로 써먹게 될 전역변수를 설정해주자.

public class UpgradeButton : MonoBehaviour
{
    public DataController dataController;

    public Text upgradeDisplayer;
    public string upgradeName;                // 이 '업그레이드'의 이름.

    public int goldByUpgrade;                  // 업그레이드로 증가하는 골드량
    public int startGoldByUpgrade = 1;      // 업그레이드로 증가하는 골드량의 초기값

    public int currentCost;                       // 업그레이드 비용.
    public int startCurrentCost = 1;           // 업그레이드 비용의 초기값

    public int level = 1;                          // 레벨

    public float upgradePow = 1.14f;
    public float costPow = 1.24f;
...

pow는 거듭제곱이란 의미이다. 여기서의 pow는 그냥 변수 이름이지만 뒤에서 제대로 쓰이게 된다.

Pow변수는 이후에 설명한다.

 

 

 

실행 첫 프레임에 실행할 두 메서드.

    void Start()
    {
        dataController.LoadUpgradeButton(this);
        UpdateUI();
    }

LoadUpgradeButton(this)의 this는 현재 이 메서드가 존재하는 이 클래스(UpgradeButton)를 말하는 것이다.

 

DataController로 다시 가서...

    public void LoadUpgradeButton(UpgradeButton upgradeButton)
    {
        string key = upgradeButton.upgradeName;
        upgradeButton.level = PlayerPrefs.GetInt(key + "_level", 1);
        upgradeButton.goldByUpgrade = PlayerPrefs.GetInt(key + "_goldByUpgrade", upgradeButton.goldByUpgrade)
        upgradeButton.currentCost = PlayerPrefs.GetInt(key + "_cost", upgradeButton.currentCost);
    }

LoadUpgradeButton()메서드는 UpgradeButton클래스를 매개변수로 받는다.

문자열 변수 key를 UpgradeButton의 upgradeName에서 가져와 대입하고,

PlayerPrefs 에 저장된 _level , _goldByUpgrade , _cost 라는 3개의 데이터를 가져오는(GetInt) 함수이다.

GetInt의 두 번째 매개변수는 문자열의 int값이 없다면 반환하는 값이다.

 

☆★Save 메서드보다 Load 메서드를 먼저 넣어야 한다!!!!

: 시작할 때 로드를 하기 때문에.

 

 

이제 UpgradeButton으로 돌아와서.

UpdateUI()의 메서드.

    public void UpdateUI()
    {
        upgradeDisplayer.text = "부위 이름: "+ upgradeName + "\n"
                                     + "필요 비용: " + currentCost + "\n"
                                     + "레벨: " + level + "\n"
                                     + "획득 가능 골드 +" + goldByUpgrade;
    }

UI에 업데이트를 해주려는 메서드이다.

업그레이드 버튼에 표시하려고 하는데, 총 4줄(\n 하면 줄바꿈 된다)을 표시한다.

이 값들은 업그레이드될 때마다 같이 업데이트된다.

 

좌, 실행하기 전의 게임 화면 / 우, 플레이 모드를 켠 후의 게임 화면

 


 

 

오늘 하는 과정의 가장 중요한 부분,

업그레이드 버튼을 누르면(=구매하면) 실행되는 것들에 대한 메소드이다.

    public void PurchaseUpgrade()
    {
        if(dataController.GetGold() >= currentCost)
        {
            dataController.SubGold(currentCost);
            level += 1;
            dataController.AddGoldPerClick(goldByUpgrade);

            //클릭 당 골드 변경된 부분들 저장하는 부분.
            UpdateUpgrade();
            UpdateUI();
            dataController.SaveUpgradeButton(this);
        }
    }

if문을 통해 현재 가진 골드량과 업그레이드 비용을 계산한다.

업그레이드 비용이 더 많다면 아무 일도 일어나지 않고,

만약 가지고 있는 골드가 비용보다 더 많다면....?

 

데이터컨트롤러의 SubGold()메서드를 불러와서, 비용만큼의 값을 뺀다.

그리고 레벨을 1 올려주며,

위에서 데이터컨트롤러에 만든 AddGoldPerClick()메서드를 사용해 '업그레이드되는 골드량(goldByUpgrade)'의 값을 '클릭 당 골드량(m_goldPerClick. DataController에 있다.)'에 추가한다.

 

여기까지는 클릭 후 발생되는 결과에 대한 내용이고,

이렇게 변화한 값에 대해, 클릭과 동시에 저장해야 하기 때문에 3줄을 더 추가해야 한다.

 

 

 

먼저 UpdateUpgrade()메서드는 계산식인데, 얼마나 업그레이드를 할건지를 계산하는 부분이다.

    public void UpdateUpgrade()
    {
        goldByUpgrade = startGoldByUpgrade * (int)Mathf.Pow(upgradePow, level);
        currentCost = startCurrentCost * (int)Mathf.Pow(costPow, level);
    }

업그레이드로 증가하는 골드량은

업그레이드로 증가하는 골드량의 초기값(1) × upgradePow값(1.14f)을 level만큼 제곱한 것이다.

 

업그레이드 비용 역시

업그레이드 비용의 초기값(1) × costPow값(1.24f)을 level만큼 제곱한 것이다.

 

 * Mathf.Pow(A , B)

이 메서드는 float 형을 가진 두 개의 숫자(A, B)를 인수로 갖는다.

그리고 A의 값에 B만큼 제곱한 값을 돌려준다.

 

다만, 위의 스크립트에선 goldByUpgradecurrentCost의 값이 정수int형이기 때문에 (int)를 붙여 형변환을 시킨 것이다.

 

 

Q. 어차피 startGoldByUpgrade와 startCurrentCost 변수는 여기서밖에 사용하지 않는데 그냥 처음부터 goldByUpgrade 변수와 currentCost 변수를 선언할 때 1로 초기화하면 되지 않나?? 이렇게.

public class UpgradeButton : MonoBehaviour
{
    ...
    public int goldByUpgrade = 1;
    public int currentCost = 1;
    ...

A. 해봤는데, 각 변수가 1로 유지되는 것이 아니라 늘어나는 만큼 UpdateUpgrade()시 기하급수적으로 수치가 늘더라...

 

 

Q. 그러면 startGoldByUpgrade와 startCurrentCost 변수를 1로 바꾸고, goldByUpgrade 변수와 currentCost 변수를 1로 초기화하면 되지 않을까?

        goldByUpgrade = 1 * (int)Mathf.Pow(upgradePow, level);
        currentCost = 1 * (int)Mathf.Pow(costPow, level);

A. ....그러게??

A. 보조강사님 답변: 상수는 코드 내에서 쓰지 말자는 프로그래머들 사이의 합의가 있다(매직넘버). 지금 이 코드야 여기에만 사용했지만, 만약 나중에 수정할 일이 있을 때 변수로 만들어서 코드에 넣었다면 그냥 변수의 값을 수정하면 된다. 하지만 일일이 1이란 상수로 값을 넣었다면 지옥이 펼쳐질 수 있기 때문에... 사용하지 않는다.

 

 * 매직넘버?

 : 설명 없이 무작정 등장하는 상수

 

 

UpdateUI()는 이미 앞서 나왔기에 생략.

 

SaveUpgradeButton()는 데이터 컨트롤러에 있는데, 업그레이드된 값들을 Reference에 저장하는 메서드이다.

    public void SaveUpgradeButton(UpgradeButton upgradeButton)
    {
        string key = upgradeButton.upgradeName;
        PlayerPrefs.SetInt(key + "_level", upgradeButton.level);
        PlayerPrefs.SetInt(key + "_goldByUpgrade", upgradeButton.goldByUpgrade);
        PlayerPrefs.SetInt(key + "_Cost", upgradeButton.currentCost);
    }

1. key 라는 이름의 문자열 변수를 만들고 upgradeName으로 초기화.

2. 그리고 PlayerPrefs에 있는 문자열, key + " " 로 식별되는 각각의 데이터에

3. 두 번째 인수의 값(upgradeButton.level , upgradeButton.goldByUpgrade , upgradeButton.currentCost)을 저장하는(SetInt) 것이다.

 

문자열 변수 key를 UpgradeButton의 upgradeName에서 가져와 대입하고,

PlayerPrefs 에 저장된 _level , _goldByUpgrade , _cost 라는 3개의 데이터를 가져오는(GetInt) 함수이다.

GetInt의 두 번째 매개변수는 문자열의 int값이 없다면 반환하는 값이다.

 

 

 

완성된 스크립트

UpgradeButton.cs
0.00MB

 

 

이제 업그레이드 버튼을 만든다.

Hierarchy 우클릭 → UI → Button.

 

오브젝트의 이름을 알기 쉽게 UpgradeButton으로 설정하고

앞서 만든 스크립트를 붙여준다.

 

그럼 아래의 사진처럼 목록이 뜨는데,

UpgradeButton 오브젝트의 UpgradeButton 스크립트.

Data Controller에는 DataController의 오브젝트를,

Upgrade Displayer 는 이 오브젝트에 자동으로 생기는 자식 오브젝트, Text를 넣는다.

프로젝트에 있는 것이 아니라 Herarchy에 있는 것으로!

 

 

그리고 정말 중요한 부분이 있는데...

원래 UpgradeButton 스크립트를 넣으면 이렇게 되어 있다.

스크립트에서 값을 주지 않았기 때문에 0.

이 상태로 플레이를 해보면.... 숫자가 조금 이상하게 올라간다. 한 단계를 건너 뛴 기분??

진짜 이것 때문에 한참 헤멘걸 생각하면....ㅡㅡ

최소 1의 값을 넣어줘야 실행이 부자연스럽지 않다.

 

 

그리고 UpgradeButton 오브젝트의 Button 컴포넌트에서

해당 부분에 '클릭 시 실행될 것'을 지정해줘야 한다.

None으로 된 부분에 이 업그레이드 버튼 오브젝트를 넣고,

No Function → 마지막 항목 → PurchaseUpgrade().

 

 

 

 

Q. 수정하고 플레이 하다보니까 수치가 자꾸 커지는데... 처음부터 다시 할 순 없나?

A. DataController 의 Awake() 메서드에 가장 먼저

PlayerPrefs.DeleteAll();

를 넣어보자! 실행과 동시에 PlayerPrefs에 있는 모든 값이 초기화된다. 사용한 이후엔 지우거나, 최소한 주석처리( // )를 해서 없애야 한다.

 

 

 

Q. 자꾸 오류가 나는데, 어디에서 나는지 모르겠어요.

A. 코드를 비교할 때 쓸 수 있는 프로그램이 있다.

http://www.acrosoft.pe.kr/board/download/20561

 

다운로드 - AcroEdit 0.9.30.156 Installer(설치 파일)

이번 버전에서 변경된 사항은 아래와 같습니다. 버그 수정 사항 한글 조합 중 커서 위치가 변경될 때 한글 조합이 완성되지 않는 문제를 수정했습니다. 모두 닫기 실행 시 발생하는 오류를 수정

www.acrosoft.pe.kr

같이 설치되는 프로그램 AcroDiff 를 사용하면 되는데, 양 쪽에 비교할 소스코드를 넣고 비교를 돌리면 노란 줄로 표시가 된다.

단, 주석까지 검색하므로 주석 없는 파일로 비교하는 것이 더 편하다.