[개발일지] 13. 안내창 구현

2025. 1. 14. 23:28·유니티 프로젝트/점토게임

0. 들어가기 전에

이번엔 게임 화면에 안내 문구를 띄우는 기능을 만들었다. 점토를 구매할 때 돈이 부족하거나, 점토를 해금할 때 불가능하거나, 다 자라지 않은 점토를 판매하려고 하는 등의 상황에 안내 문구를 나타나게 해서 플레이어가 알 수 있도록 했다.

 

 


 

 

1. 게임 오브젝트

이번엔 Info Panel 게임 오브젝트를 추가했다.

더보기

1. 하이어라키 창 모습

 

 

2. 인스펙터 창 모습

 

 

3. 애니메이터

안내 문구 판넬에 애니메이션을 적용하기 위해서 애니메이터를 만들고, 애니메이션도 만들었다.

 

애니메이터의 상태는 다음 사진과 같다.

 

Started 가 체크 되면 Start 애니메이션이 수행되고 끝나면 Exit 로 이동하도록 했다. Start 에는 직접 만든 애니메이션을 넣어놓았다.

 

 


 

 

2. 스크립트

이번에 새로 만든 스크립트는 InfoPanelController 이고 수정한 스크립트는 ClaySellController, ClayPanel, GameManager 이다.

 

2.1 InfoPanelController 스크립트

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

public class InfoPanelController : MonoBehaviour
{
    [Header("Animation")]
    public Animator anim;

    [Header("UI")]
    public Text infoText;

    private void Start()
    {
        anim = gameObject.GetComponent<Animator>(); // 할당하기

        // 메서드 연결
        GameManager.instance.OnSetInfoPanel -= SetAndPlayInfoPanel;
        GameManager.instance.OnSetInfoPanel += SetAndPlayInfoPanel;
    }

    public void SetAndPlayInfoPanel(string text)
    {
        infoText.text = text; // 안내 문구 설정

        anim.SetTrigger("Started"); // 애니메이션 실행
    }
}

 

2.2 InfoPanelController 스크립트 설명

더보기

1. 변수

anim, infoText 변수가 존재한다. anim 은 안내 문구 판넬에 애니메이션을 적용하기 위해서 필요하고, infoText 는 안내 문구를 설정하기 위해 필요하다.

[Header("Animation")]
public Animator anim;

[Header("UI")]
public Text infoText;

 

 

2. Start()

anim 에 현재 안내 문구 판넬 게임 오브젝트의 Animator 컴포넌트를 할당한다.

 

그리고 GameManager 의 OnSetInfoPanel 델리게이트에 SetAndPlayInfoPanel 메서드를 연결해서 신호를 주면 연결된 메서드가 호출될 수 있도록 했다.

private void Start()
{
    anim = gameObject.GetComponent<Animator>(); // 할당하기

    // 메서드 연결
    GameManager.instance.OnSetInfoPanel -= SetAndPlayInfoPanel;
    GameManager.instance.OnSetInfoPanel += SetAndPlayInfoPanel;
}

 

 

3. SetAndPlayInfoPanel(string text)

입력 받은 값으로 안내 문구 판넬의 문구를 설정하고 애니메이션을 실행하는 메서드이다.

public void SetAndPlayInfoPanel(string text)
{
    infoText.text = text; // 안내 문구 설정

    anim.SetTrigger("Started"); // 애니메이션 실행
}

 

2.3 GameManager 스크립트

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

public class GameManager : MonoBehaviour
{
    [Header("Game Data")]
    public float love; // 애정
    public float gold; // 골드
    public bool[] unLockedClays; // 점토들의 해금 여부
    public bool[] catchedClays; // 야생에서 잡아왔는지 확인용

    [Header("Game Manager")]
    public static GameManager instance; // 싱글톤 이용하기 위함

    [Header("GameDataUI")]
    public GameDataUIController gameDataUI;
    public delegate void SetInfoPanelHandler(string text); // 델리게이트 선언 
    public event SetInfoPanelHandler OnSetInfoPanel;

    [Header("Pool Manager")]
    public PoolManager poolManager;

    [Header("Coroutine")]
    public Coroutine updateTextUICoroutine;

    [Header("Game Exit")]
    public Button gameExitButton;

    private void Awake()
    {
        // 싱글톤 패턴
        if (instance != null && instance != this)
        {
            // 이미 존재하면 새로 만든거 없애
            Destroy(gameObject);
            return;
        }

        instance = this;
        DontDestroyOnLoad(gameObject); // 얘는 다른 씬으로 전환되어도 안 없앨 거임

        poolManager = GameObject.Find("PoolManager").GetComponent<PoolManager>(); // 풀매니저 찾아서 할당
    }


    void Start()
    {
        gameExitButton = GameObject.Find("OptionPanelParent").transform.Find("Option Panel").transform.Find("Image").transform.Find("Exit Button").GetComponent<Button>();
        gameExitButton.onClick.AddListener(DataManager.instance.SaveGameData); // 게임 데이터 저장 메서드 연결
        gameExitButton.onClick.AddListener(GameExit); // 게임 종료 메서드 연결

        GetLove(0);
        GetGold(1000);

        // 저장된 게임 데이터가 있는 경우 데이터 가져와서 반영
        if (DataManager.instance.data.unlockClays != null)
        {
            // 저장된 데이터 반영해서 가져오기
            for (int i = 0; i < unLockedClays.Length; i++)
            {
                unLockedClays[i] = DataManager.instance.data.unlockClays[i];
                catchedClays[i] = DataManager.instance.data.catchClays[i];
            }
        }

        // 메서드 연결하기
        DataManager.instance.OnSave -= SetSaveData; // 중복 방지하기 위해 먼저 빼줌
        DataManager.instance.OnSave += SetSaveData;
    }


    // 재화 얻는 함수
    public void GetGold(float capacity)
    {
        // 이미 코루틴이 종료되지 않은 중에 동일한게 또 들어오면 겹쳐서 반영이 돼서 이상하게 될 수 있으므로 null 인지 판단해야함. 
        if (updateTextUICoroutine != null)
        {
            StopCoroutine(updateTextUICoroutine);
        }

        updateTextUICoroutine = StartCoroutine(gameDataUI.UpdateTextUI("gold", gold + capacity, gold));
        gold += capacity;

        //PlayerPrefs.SetFloat("Gold", gold); // 데이터 저장
    }

    public void GetLove(float capacity)
    {
        // 이미 코루틴이 종료되지 않은 중에 동일한게 또 들어오면 겹쳐서 반영이 돼서 이상하게 될 수 있으므로 null 인지 판단해야함. 
        if (updateTextUICoroutine != null)
        {
            StopCoroutine(updateTextUICoroutine);
        }

        updateTextUICoroutine = StartCoroutine(gameDataUI.UpdateTextUI("love", love + capacity, love));
        love += capacity;

        //PlayerPrefs.SetFloat("Love", love); // 데이터 저장
    }

    public void SetSaveData()
    {
        int size = unLockedClays.Length;

        DataManager.instance.data.unlockClays = new List<bool>();
        DataManager.instance.data.catchClays = new List<bool>();

        for (int i=0; i<size; i++)
        {
            DataManager.instance.data.unlockClays.Add(unLockedClays[i]); // 해금 여부 저장
            DataManager.instance.data.catchClays.Add(catchedClays[i]); // 포획 여부 저장
        }
    }


    public void GameExit()
    {
        // 게임 종료
        Application.Quit();
    }

    
    public void StartInfoPanel(string text)
    {
        // 연결된 메서드 실행시키기
        OnSetInfoPanel?.Invoke(text);
    }
}

 

2.4 GameManager 스크립트 변경 사항 설명

더보기

1. 변수

아래와 같은 변수가 추가되었다. 일단 OnSelInfoPanel 이라는 이름의 델리게이트를 선언했다. 여기에 메서드를 연결해서 호출할 수 있도록 했다.

public delegate void SetInfoPanelHandler(string text); // 델리게이트 선언 
public event SetInfoPanelHandler OnSetInfoPanel;

 

 

2. StartInfoPanel(string text)

얘는 OnSetInfoPanel 에 연결된 메서드를 호출한다. OnSetInfoPanel 에는 InfoPanelController 의 SetAndPlayInfoPanel 메서드가 연결되어 있다.

 

즉, StartInfoPanel 메서드를 호출하면 SetAndPlayInfoPanel 메서드를 호출하는 것이다.

public void StartInfoPanel(string text)
{
    // 연결된 메서드 실행시키기
    OnSetInfoPanel?.Invoke(text);
}

 

2.5 ClayPanel 스크립트

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

public class ClayPanel : MonoBehaviour
{
    [Header("UI")]
    public Button pageLeftButton; // 페이지 왼쪽 버튼
    public Button pageRightButton; // 페이지 오른쪽 버튼
    public Button buyClayButton; // 점토 구매 버튼
    public Button unlockClayButton; // 점토 해금 버튼

    public Image lockedImage; // 잠금된 점토 이미지
    public Image clayImage; // 점토 이미지
    public Text clayName; // 점토 이름
    public Text buyPrice; // 점토 가격

    public GameObject lockedPage; // 잠금 페이지

    [Header("Control")]
    public int pageIdx = 0; // 페이지 인덱스
    public int maxIdx;
    public int minIdx = 0;

    private void Start()
    {
        maxIdx = GameManager.instance.poolManager.clayPrefabs.Length;

        pageLeftButton.onClick.AddListener(DownPageIdx);
        pageLeftButton.onClick.AddListener(SetClayPanel);

        pageRightButton.onClick.AddListener(UpPageIdx);
        pageRightButton.onClick.AddListener(SetClayPanel);
    }

    private void OnEnable()
    {
        // 활성화 될 때 호출되는 함수

        ResetClayPanel();
    }

    public void ResetClayPanel()
    {
        pageIdx = 0;
        SetButtonInfo(); // 버튼 설정해주기
    }

    public void SetClayPanel()
    {
        Clay clay = GameManager.instance.poolManager.clayPrefabs[pageIdx].GetComponent<Clay>();
        if (GameManager.instance.unLockedClays[pageIdx] == false)
        {
            lockedPage.SetActive(true); // 해금이 안된 경우엔 잠금 판넬 활성화..
        }
        else
        {
            lockedPage.SetActive(false); // 해금된 경우엔 잠금 판넬 비활성화..
        }

        // 페이지 인덱스에 맞게 설정
        lockedImage.sprite = clay.clay; // 점토의 이미지 가져오기
        clayImage.sprite = clay.clay; 
        clayName.text = clay.clayName; // 점토 이름 가져오기
        buyPrice.text = clay.buyPrice + ""; // 점토 가격 가져오기      
    }

    public void UpPageIdx()
    {
        if (pageIdx >= maxIdx - 1) return; // 빠져나가기..
        pageIdx++;

        SetButtonInfo();
    }
    public void DownPageIdx()
    {
        if (pageIdx <= 0) return; // 빠져나가기..
        pageIdx--;
        SetButtonInfo();
    }

    private void SetButtonInfo()
    {
        ColorBlock col = unlockClayButton.colors;

        // 만약 야생에서 점토를 잡아왔으면 해금하기 버튼 노란색으로 바꿔주기
        if (GameManager.instance.catchedClays[pageIdx])
        {
            col.normalColor = new Color32(255, 220, 90, 255); // 노란색
            col.highlightedColor = new Color32(255, 220, 90, 255); // 노란색

            unlockClayButton.colors = col; // 색 만들어 놓은거 할당해주기
        }
        else
        {
            col.normalColor = new Color32(255, 255, 255, 255); // 흰색
            col.highlightedColor = new Color32(255, 255, 255, 255); // 흰색

            unlockClayButton.colors = col; // 색 만들어 놓은거 할당해주기
        }

        unlockClayButton.onClick.RemoveAllListeners(); // 일단 다 지웡
        unlockClayButton.onClick.AddListener(() => Unlock(pageIdx)); // Unlock 메서드 추가

        buyClayButton.onClick.RemoveAllListeners(); // 일단 다 지웡
        buyClayButton.onClick.AddListener(() => BuyClay(pageIdx)); // BuyClay 메서드 추가
    }

    public void Unlock(int idx)
    {
        // 야생에서 아직 안 잡았으면 해금 못하도록..
        if (!GameManager.instance.catchedClays[pageIdx])
        {
            // 안내 판넬 띄우기
            GameManager.instance.StartInfoPanel("야생에서 잡아와야 해요!");
            return;
        }

        GameManager.instance.unLockedClays[idx] = true;
        SetClayPanel();
    }

    public void BuyClay(int idx)
    {
        int price = GameManager.instance.poolManager.clayPrefabs[idx].GetComponent<Clay>().buyPrice;

        // 돈이 충분하면 구매
        if (GameManager.instance.gold >= price)
        {
            GameManager.instance.GetGold(-price);
            GameManager.instance.poolManager.GetGameObject(idx); // 동물 get!
        }
        else
        {
            // 안내 판넬 띄우기
            GameManager.instance.StartInfoPanel("돈이 부족해요 ㅠ_ㅠ");
        }
    }

    public void ClosePanel()
    {
        gameObject.SetActive(false); // 활성화 끄기..
    }
}

 

2.6. ClayPanel 스크립트 변경 사항 설명

더보기

1. Unlock(int idx)

아래와 같이 Unlock 메서드의 일부를 수정했다. 해금하기 버튼을 눌렀는데 해금이 불가능한 상황이라면 안내 판넬을 띄우도록 했다.

// 야생에서 아직 안 잡았으면 해금 못하도록..
if (!GameManager.instance.catchedClays[pageIdx])
{
    // 안내 판넬 띄우기
    GameManager.instance.StartInfoPanel("야생에서 잡아와야 해요!");
    return;
}

 

 

2. BuyClay(int idx)

아래와 같이 일부 코드를 수정했다. 돈이 부족한 경우에 안내 판넬을 띄우도록 했다.

// 돈이 충분하면 구매
if (GameManager.instance.gold >= price)
{
    GameManager.instance.GetGold(-price);
    GameManager.instance.poolManager.GetGameObject(idx); // 동물 get!
}
else
{
    // 안내 판넬 띄우기
    GameManager.instance.StartInfoPanel("돈이 부족해요 ㅠ_ㅠ");
}

 

2.7 ClaySellController 스크립트

using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.EventSystems;

public class ClaySellController : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
    [Header("Clay Info")]
    public PoolManager poolManager;
    public Clay sellClay; // 판매할 점토

    private void Start()
    {
        poolManager.OnSellClay += SellClay; // 델리게이트에 메서드 연결
    }

    private void OnDestroy()
    {
        poolManager.OnSellClay -= SellClay; // 이벤트 구독 해제
    }

    public void OnPointerEnter(PointerEventData eventData)
    {
        poolManager.isSellZone = true;

        // 만약 점토가 점토 판매 버톤으로 드래그되어서 들어온다면..
        if (poolManager.curClay.isDragging)
            sellClay = poolManager.curClay; // 판매할 점토를 현재 드래그 중인 클레이로 설정..
    }

    public void OnPointerExit(PointerEventData eventData)
    {
        poolManager.isSellZone = false;
        sellClay = null;
    }

    public void SellClay()
    {
        if (sellClay != null)
        {
            if (sellClay.clayLevel == 5) // 성체만 판매 가능
            {
                poolManager.ReturnToPool(sellClay.gameObject); // 비활성화시키기..
                GameManager.instance.GetGold(sellClay.sellPrice); // 돈 얻기
            }
            else
            {
                // 안내 문구 시작
                GameManager.instance.StartInfoPanel("성체가 된 점토만 판매할 수 있어요!");
                return;
            }
        }
    }
}

 

2.8 ClaySellController 스크립트 변경 사항 설명

더보기

1. SellClay()

아래와 같이 일부 코드만 수정했다. 점토를 판매 버튼에 드래그&드롭 했는데 만약 성체가 아니라면 팔지 않고 나가도록 한다. 메서드를 빠져나가기 전에 안내 문구를 띄우도록 했다.

if (sellClay.clayLevel == 5) // 성체만 판매 가능
{
    poolManager.ReturnToPool(sellClay.gameObject); // 비활성화시키기..
    GameManager.instance.GetGold(sellClay.sellPrice); // 돈 얻기
}
else
{
    // 안내 문구 시작
    GameManager.instance.StartInfoPanel("성체가 된 점토만 판매할 수 있어요!");
    return;
}

 

 


 

 

3. 결과물

 

 

 

 

'유니티 프로젝트/점토게임' 카테고리의 다른 글
  • [개발일지] 15. 이펙트 효과 적용
  • [개발일지] 14. 업그레이드 판넬 제작&기능 구현&데이터 저장
  • [개발일지] 12. 점토 구매 UI 창 수정 & 저장 로직 수정 & 옵션 판넬 제작
  • [개발일지] 11. UI 창 구축 & 점토 구매 UI 창 꾸미기 & 기능 구현
dubu0721
dubu0721
dubu0721 님의 블로그 입니다.
  • dubu0721
    dubu0721 님의 블로그
    dubu0721
  • 전체
    오늘
    어제
    • 분류 전체보기 (351)
      • 프로그래밍언어론 정리 (5)
      • 컴퓨터네트워크 정리 (5)
      • 알고리즘&자료구조 공부 (64)
        • it 취업을 위한 알고리즘 문제풀이 입문 강의 (60)
        • 학교 알고리즘 수업 (3)
        • 실전프로젝트I (0)
      • 백준 문제 (204)
        • 이분탐색 (7)
        • 투포인트 (10)
        • 그래프 (11)
        • 그리디 (24)
        • DP (25)
        • BFS (21)
        • MST (7)
        • KMP (4)
        • Dijkstra (3)
        • Disjoints Set (4)
        • Bellman-Ford (2)
        • 시뮬레이션 (3)
        • 백트래킹 (15)
        • 위상정렬 (5)
        • 자료구조 (25)
        • 기하학 (1)
        • 정렬 (11)
        • 구현 (8)
        • 재귀 (8)
        • 수학 (8)
        • 트리 (1)
      • 유니티 공부 (11)
        • 레트로의 유니티 게임 프로그래밍 에센스 (11)
        • 유니티 스터디 자료 (0)
        • C# 공부 (0)
      • 유니티 프로젝트 (48)
        • 케이크게임 (13)
        • 점토게임 (35)
      • 언리얼 공부 (10)
        • 이득우의 언리얼 프로그래밍 (10)
      • 진로 (1)
      • 논문 읽기 (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    BFS
    바킹독
    레트로의 유니티 프로그래밍
    정렬
    해시
    백트래킹
    맵
    이분탐색
    골드메탈
    수학
    투포인터
    언리얼
    큐
    유니티 공부 정리
    유니티
    우선순위큐
    이벤트 트리거
    스택
    C#
    자료구조
    이득우
    오블완
    재귀
    유니티 프로젝트
    그래프
    그리디
    백준
    티스토리챌린지
    dp
    시뮬레이션
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
dubu0721
[개발일지] 13. 안내창 구현
상단으로

티스토리툴바