[개발일지] 34[완결]. 야생 UI 수정 & 메인 씬 기능 추가

2025. 1. 31. 21:31·유니티 프로젝트/점토게임
목차
  1. 0. 들어가기 전에
  2. 1. 게임 오브젝트
  3. 1.1 메인 씬
  4. 1.2 야생 씬
  5. 2. 스크립트
  6. 2.1 BGM 스크립트
  7. 2.2 BGM 스크립트 설명
  8. 2.3 Player 스크립트
  9. 2.4 Player 스크립트 변경 사항 설명
  10. 2.5 GameManager 스크립트
  11. 2.6 GameManager 스크립트 변경 사항 설명
  12. 2.7 UIController 스크립트
  13. 2.8 UIController 스크립트 변경 사항 설명
  14. 2.9 MapSpawner 스크립트
  15. 2.10 ClayPanel 스크립트
  16. 2.11 ClayPanel 스크립트 변경 사항 설명
  17. 3. 결과물

0. 들어가기 전에

이번엔 야생 UI 를 손봤다. 체력바에 현재 체력을 표시하도록 했고, 화면 상단에 타이머를 야생이 끝나기 까지 남은 시간으로 설정하도록 했다.

 

그리고 야생의 난이도가 어려워질수록 배경이 어두워지는데 타일맵의 색은 그대로라 위화감이 있어서 Light2D 를 이용했다. 일단 플레이어한테 빛을 넣어놨고, 맵에 global light 을 만들어놨다. 맵이 어려워질수록 global light 을 어둡게 해서 타일맵의 색도 어두워지도록 했다.

 

그리고 야생에서 새로운 점토를 잡아왔을 때 메인 씬에서 점토 구매 버튼 위에 별표가 뜨도록 했다. 새로 잡은 점토 페이지로 도달하기 전까지는 별표가 없어지지 않는다.

 

 


 

 

1. 게임 오브젝트

메인 씬과 야생 씬으로 파트를 나누어서 설명하려고 한다.

 

1.1 메인 씬

 

1.1.1 New Alam 

야생에서 새로운 점토를 잡아오면 사진과 같이 별표가 뜨도록 했다. 잡아온 점토의 페이지로 도달할 때까지 별표가 활성화되어 있도록 했다.

 

1.2 야생 씬

야생 씬에는 빛 오브젝트를 추가했고, 게임 클리어 판넬에 NewText 게임 오브젝트를 추가했다. 그리고 BGM 게임 오브젝트도 만들었다. 

 

1.2.1 NewText

이번에 잡은 점토가 처음 만나는 점토라면 알리기 위해서 NewText 를 만들었다. 애니메이션도 만들어서 위아래로 움직이도록 했다.

 

 

1.2.2 Light 2D, light

Light2D 는 게임 화면을 어둡게 만들기 위해서 만들었고, 플레이어 속 light 는 플레이어 주변을 밝히기 위해 만들었다.

 

예시 모습은 다음과 같다.

 

 

1.2.3 BGM

BGM 게임 오브젝트를 추가해서 배경음을 야생 난이도에 맞게 설정할 수 있도록 했다.

 

 


 

 

2. 스크립트

이번에 새로 만든 스크립트는 BGM 이다. 

 

2.1 BGM 스크립트

더보기
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BGM : MonoBehaviour
{
    [Header("Audio")]
    private AudioSource bgmAudio;
    public AudioClip easyClip;
    public AudioClip normalClip;
    public AudioClip hardClip;

    private void Awake()
    {
        bgmAudio = GetComponent<AudioSource>();
    }

    private void Start()
    {
        SetBGM();
    }

    private void SetBGM()
    {
        // 야생 난이도에 맞는 브금 틀도록
        if (GameManager.instance.worldLevel == 0)
            bgmAudio.clip = easyClip;
        else if (GameManager.instance.worldLevel == 1)
            bgmAudio.clip = normalClip;
        else 
            bgmAudio.clip = hardClip;

        bgmAudio.Play(); // 재생!
    }

    public void StopBGM()
    {
        bgmAudio?.Stop();
    }
}

 

2.2 BGM 스크립트 설명

더보기

1. 변수

야생 단계에 맞게 브금을 설정하기 위한 변수이다.

[Header("Audio")]
private AudioSource bgmAudio;
public AudioClip easyClip;
public AudioClip normalClip;
public AudioClip hardClip;

 

 

2. Awake()

할당해줬다.

private void Awake()
{
    bgmAudio = GetComponent<AudioSource>();
}

 

 

3. Start()

브금을 틀도록 했다.

private void Start()
{
    SetBGM();
}

 

 

4. SetBGM()

야생 난이도에 맞게 브금을 설정하고 실행하도록 했다.

private void SetBGM()
{
    // 야생 난이도에 맞는 브금 틀도록
    if (GameManager.instance.worldLevel == 0)
        bgmAudio.clip = easyClip;
    else if (GameManager.instance.worldLevel == 1)
        bgmAudio.clip = normalClip;
    else 
        bgmAudio.clip = hardClip;

    bgmAudio.Play(); // 재생!
}

 

 

5. StopBGM()

브금을 끄는 메서드이다. 다른 스크립트에서 호출해서 사용한다.

public void StopBGM()
{
    bgmAudio?.Stop();
}

 

2.3 Player 스크립트

더보기
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Net;
using System.Runtime.InteropServices;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.Rendering.Universal;
using UnityEngine.UI;

public class Player : MonoBehaviour
{
    [Header("Player Info")]
    public int heart = 3; // 목숨 3개
    public float jumpPower = 500f; // 점프 힘

    public int jumpCount = 0; // 누적 점프 횟수(최대 두번 뛸 수 있도록)
    public bool isGrounded = false; // 바닥에 닿았는지 여부
    public bool isDead = false; // 사망 여부
    public bool isInvincibility = false; // 무적 여부

    public Rigidbody2D rigid; // 리지드바디 컴포넌트
    public Animator anim; // 애니메이터 컴포넌트
    public AudioSource playerAudio; // 사용할 오디오 소스 컴포넌트
    public SpriteRenderer spriteRenderer; // 스프라이트 렌더러

    public AudioClip deathClip; // 죽을 때 나는 소리
    public AudioClip jumpClip; // 점프할 때 나는 소리
    public AudioClip attackedClip; // 맞을 때 나는 소리
    public AudioClip gameClearClip; // 게임 성공할 때 나는 소리

    public float gamePlayTime = 30f; // 일단 1분으로..
    public float curTime = 0;


    [Header("World UI")]
    public BGM worldBGM;
    public Text time;
    public GameObject[] heartUIs;
    public Vector3[] heartUIsPos; // 애니메이션 수행하기 전 위치
    public int heartIdx;

    [Header("Light")]
    public Light2D playerLight;


    private void Start()
    {
        rigid = GetComponent<Rigidbody2D>();
        anim = GetComponent<Animator>();
        playerAudio = GetComponent<AudioSource>();
        spriteRenderer = GetComponent<SpriteRenderer>();


        for (int i=0; i<heartUIs.Length; i++)
        {
            // 위치 저장
            heartUIsPos[i] = heartUIs[i].transform.position;
        }

        time.gameObject.SetActive(false); // 게임 시작 전에 타이머 꺼놓기

        // 맵 레벨에 따라 설정
        if (GameManager.instance.worldLevel == 0)
            playerLight.gameObject.SetActive(false);

        if (GameManager.instance.worldLevel == 2)
            time.color = new Color(255, 255, 255, 255); // 텍스트 흰색으로 바꾸기..
    }

    private void Update()
    {
        // 아직 게임 시작 안 했으면 좀 기다리기..
        while (!GameManager.instance.isGameStart)
        {
            return;
        }

        time.gameObject.SetActive(true); // 게임 시작하면 활성화 켜기

        if (curTime >= gamePlayTime)
        {
            // 플레이 시간 지나면 더이상 진행하지 않음
            GameEnd();
        }

        if (isDead)
        {
            // 사망하면 더이상 진행하지 않음
            return;
        }

        if (Input.GetMouseButtonDown(0) && jumpCount < 2)
        {
            // 점프 횟수 증가
            jumpCount++;

            // 점프 직전에 속도를 0 으로 변경
            rigid.velocity = Vector3.zero;

            // 위쪽으로 힘주기
            rigid.AddForce(new Vector2(0, jumpPower));

            // 오디오 소스 재생
            PlaySound(jumpClip);
        }
        else if (Input.GetMouseButtonUp(0) && rigid.velocity.y > 0)
        {
            // 마우스 왼쪽 버튼에서 손을 떼는 순간 && 속도의 y 값이 양수(위로 상승 중)
            // 현재 속도를 절반으로 변경
            rigid.velocity = rigid.velocity * 0.5f;
        }

        // 애니메이터의 Grounded 파라미터를 isGrounded 값으로 갱신
        anim.SetBool("Grounded", isGrounded);

        curTime += Time.deltaTime; // 시간 더해주기

        // Time Text 에 시간 반영
        time.text = (int)(gamePlayTime - curTime + 1) + "s";
    }

    private void PlaySound(AudioClip clip)
    {
        playerAudio.clip = clip;
        playerAudio.Play();
    }

    public void GameEnd()
    {
        worldBGM.StopBGM(); // 스탑!

        // 오디오 소스 재생
        PlaySound(gameClearClip);

        rigid.simulated = false;

        // 여기서 게임 매니저 게임 종료(성공) 메서드 호출
        GameManager.instance.WorldGameClear();
    }

    public void Die()
    {
        worldBGM.StopBGM(); // 스탑!

        // 오디오 소스 재생
        PlaySound(deathClip);

        for (int i=heartIdx; i<heartUIs.Length; i++)
        {
            SetHeartUI(i); // 설정해용~~
        }

        StartCoroutine(DieCoroutine());
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        // Collider 를 통해 다른 객체가 경계를 통과했을 때 자동으로 호출되는 메서드
        // 두 객체 중 적어도 하나에 Collider 가 있고, Is Trigger 옵션이 활성화 되어 있어야함.


        // 체력 깎이는 부분은 무적 상태라면 수행 안 하고 걍 빠져나가기..
        if (isInvincibility) return;

        // 만약 플레이어가 체력 깎이는 바닥을 통과했을 때
        if (collision.tag == "AttackGround")
        {
            Die(); // 죽어
        }
    }

    private void OnCollisionEnter2D(Collision2D collision)
    {
        if (collision.gameObject.tag == "Ground")
        {
            // 충돌한 가장 낮은 지점 확인
            ContactPoint2D contact = collision.contacts[0];

            // 플레이어의 발보다 높은 곳에서 충돌했다면 무시
            if (contact.point.y > transform.position.y) return;

            isGrounded = true; // 땅에 닿았음 표시
            jumpCount = 0; // 리셋
        }
        else if (collision.gameObject.tag == "Attack")
        {
            if (isInvincibility) return; // 무적 상태면 그냥 나가기..

            // 장애물에 닿았으면 heart 값 -1 해주기..

            Attacked();
        }
        else if (collision.gameObject.tag == "Monster")
        {
            if (isInvincibility) return; // 무적 상태면 그냥 나가기..

            // 충돌한 가장 낮은 지점 확인
            ContactPoint2D contact = collision.contacts[0];

            // 만약 플레이어가 몬스터보다 위에 있고, y 축의 속도가 감소하는 중이라면 몬스터를 밟은 거임
            if (transform.position.y >= contact.point.y /*&& rigid.velocity.y <= 0*/)
            {
                // 몬스터 머리 밟으면 다시 이단 점프 가능하도록..
                isGrounded = true; // 땅에 닿았음 표시
                jumpCount = 0; // 리셋

                // 몬스터의 Die 메서드 호출
                collision.transform.GetComponent<Monster>().Die();
            }
            else
            {
                Attacked();
            }
        }
    }

    private void OnCollisionExit2D(Collision2D collision)
    {
        if (collision.gameObject.tag == "Ground")
        {
            isGrounded = false;
        }
    }

    private void Attacked()
    {
        // 오디오 소스 재생
        PlaySound(attackedClip);

        // 피 깎기
        heart--;
        SetHeartUI(heartIdx);
        heartIdx++;

        if (heart == 0)
        {
            Die(); // 죽어
            return;
        }

        // 잠시 무적 상태로..
        StartCoroutine(Invincibility());
    }

    private void SetHeartUI(int idx)
    {
        heartUIs[idx].GetComponent<Animator>().Play("Idle", 0, 0f); // 특정 애니메이션 초기화
        heartUIs[idx].GetComponent<Animator>().enabled = false;
        heartUIs[idx].transform.position = heartUIsPos[idx]; // 위치 바꿩
        heartUIs[idx].GetComponent<Image>().color = new Color32(255, 255, 255, 40);
    }

    private IEnumerator Invincibility()
    {
        isInvincibility = true;
        spriteRenderer.color = new Color32(255, 0, 0, 180); // 반투명하게..(빨갛게)
        gameObject.layer = 9; // PlayerDamaged 레이어는 9번임
        anim.SetTrigger("Hit"); // 애니메이션 수행

        yield return new WaitForSeconds(2f); // 2초 동안 무적

        gameObject.layer = 8; // Player 레이어는 8번임
        spriteRenderer.color = new Color32(255, 255, 255, 255); // 원래 상태로..
        isInvincibility = false; // 다시 false 로 바꾸고 빠져나가기..
    }

    private IEnumerator DieCoroutine()
    {
        // 여기서 게임 종료(실패) 로직 수행할거임
        GameManager.instance.WorldGameFail(); // 게임 실패 정보 세팅

        // 애니메이터의 Die 트리거 파라미터를 세팅함
        anim.SetTrigger("Die");

        // 오디오 소스 클릅을 deathClip 으로 변경
        playerAudio.clip = deathClip;

        // 오디오 실행
        playerAudio.Play();

        // 속도를 제로로 변경
        rigid.velocity = Vector2.zero;

        // 사망 상태 true 로
        isDead = true;

        yield return new WaitForSeconds(3f);

        gameObject.SetActive(false); // 비활성화
    }
}

 

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

더보기

1. 변수

야생의 체력바 UI 를 관리할 수 있도록 변수를 선언했다. 그리고 플레이어의 자식 오브젝트인 light 를 관리하기 위한 변수도 선언했다.

[Header("World UI")]
public BGM worldBGM;
public Text time;
public GameObject[] heartUIs;
public Vector3[] heartUIsPos; // 애니메이션 수행하기 전 위치
public int heartIdx;

[Header("Light")]
public Light2D playerLight;

 

 

2. Start()

애니메이션을 수행하기 전의 체력바 위치를 저장하도록 했다. 체력이 까이면 해당 체력바가 더이상 애니메이션을 수행하지 않도록 해야한다. 그때 위치가 잘못 설정될 수 있어서 애니메이션을 멈춘 후 따로 위치를 다시 설정해주기 위해 필요하다.

 

그리고 게임 시작 전엔 time 게임 오브젝트를 꺼서 보이지 않도록 했다.

private void Start()
{
    rigid = GetComponent<Rigidbody2D>();
    anim = GetComponent<Animator>();
    playerAudio = GetComponent<AudioSource>();
    spriteRenderer = GetComponent<SpriteRenderer>();


    for (int i=0; i<heartUIs.Length; i++)
    {
        // 위치 저장
        heartUIsPos[i] = heartUIs[i].transform.position;
    }

    time.gameObject.SetActive(false); // 게임 시작 전에 타이머 꺼놓기

    // 맵 레벨에 따라 설정
    if (GameManager.instance.worldLevel == 0)
        playerLight.gameObject.SetActive(false);

    if (GameManager.instance.worldLevel == 2)
        time.color = new Color(255, 255, 255, 255); // 텍스트 흰색으로 바꾸기..
}

 

 

3. Update()

야생 클리어까지 남은 시간을 표시하기 위해 Update 문에서 time 변수의 텍스트를 조정해줬다.

private void Update()
{
    // 아직 게임 시작 안 했으면 좀 기다리기..
    while (!GameManager.instance.isGameStart)
    {
        return;
    }

    time.gameObject.SetActive(true); // 게임 시작하면 활성화 켜기

    if (curTime >= gamePlayTime)
    {
        // 플레이 시간 지나면 더이상 진행하지 않음
        GameEnd();
    }

    if (isDead)
    {
        // 사망하면 더이상 진행하지 않음
        return;
    }

    if (Input.GetMouseButtonDown(0) && jumpCount < 2)
    {
        // 점프 횟수 증가
        jumpCount++;

        // 점프 직전에 속도를 0 으로 변경
        rigid.velocity = Vector3.zero;

        // 위쪽으로 힘주기
        rigid.AddForce(new Vector2(0, jumpPower));

        // 오디오 소스 재생
        PlaySound(jumpClip);
    }
    else if (Input.GetMouseButtonUp(0) && rigid.velocity.y > 0)
    {
        // 마우스 왼쪽 버튼에서 손을 떼는 순간 && 속도의 y 값이 양수(위로 상승 중)
        // 현재 속도를 절반으로 변경
        rigid.velocity = rigid.velocity * 0.5f;
    }

    // 애니메이터의 Grounded 파라미터를 isGrounded 값으로 갱신
    anim.SetBool("Grounded", isGrounded);

    curTime += Time.deltaTime; // 시간 더해주기

    // Time Text 에 시간 반영
    time.text = (int)(gamePlayTime - curTime + 1) + "s";
}

 

 

4. GameEnd()

게임이 종료(성공)될 때 브금을 멈추고 효과음을 재생시켰다. 

public void GameEnd()
{
    worldBGM.StopBGM(); // 스탑!

    // 오디오 소스 재생
    PlaySound(gameClearClip);

    rigid.simulated = false;

    // 여기서 게임 매니저 게임 종료(성공) 메서드 호출
    GameManager.instance.WorldGameClear();
}

 

 

5. Die()

플레이어가 죽을 때 브금을 종료하고, 게임 실패 효과음을 재생시켰다. 그리고 현재 남아있던 체력 UI 를 모두 까인 모습으로 설정해줬다.

public void Die()
{
    worldBGM.StopBGM(); // 스탑!

    // 오디오 소스 재생
    PlaySound(deathClip);

    for (int i=heartIdx; i<heartUIs.Length; i++)
    {
        SetHeartUI(i); // 설정해용~~
    }

    StartCoroutine(DieCoroutine());
}

 

 

6. Attacked()

피가 깎인 걸 UI 에 반영하도록 했다. SetHeartUI 메서드를 호출했다.

private void Attacked()
{
    // 오디오 소스 재생
    PlaySound(attackedClip);

    // 피 깎기
    heart--;
    SetHeartUI(heartIdx);
    heartIdx++;

    if (heart == 0)
    {
        Die(); // 죽어
        return;
    }

    // 잠시 무적 상태로..
    StartCoroutine(Invincibility());
}

 

 

7. SetHeartUI(int idx)

체력바 UI 를 설정하는 메서드이다. 체력이 까이면 호출된다.

private void SetHeartUI(int idx)
{
    heartUIs[idx].GetComponent<Animator>().Play("Idle", 0, 0f); // 특정 애니메이션 초기화
    heartUIs[idx].GetComponent<Animator>().enabled = false;
    heartUIs[idx].transform.position = heartUIsPos[idx]; // 위치 바꿩
    heartUIs[idx].GetComponent<Image>().color = new Color32(255, 255, 255, 40);
}

 

2.5 GameManager 스크립트

더보기
using System;
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.Rendering.Universal;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using static UnityEditor.Experimental.GraphView.Port;

public class GameManager : MonoBehaviour
{
    [Header("Game Data")]
    public float love; // 애정
    public float gold; // 골드
    public bool[] unLockedClays; // 점토들의 해금 여부
    public bool[] catchedClays; // 야생에서 잡아왔는지 확인용
    public int clayHouseLevel = 1; // 점토 아파트 레벨
    public int clayClickLevel = 1; // 점토 클릭 레벨
    public int[] clayHouseLoveList; // 업그레이드 비용 
    public int[] clayClickLoveList; // 업그레이드 비용
    public int curPossibleClayNum = 1; // 최대로 키울 수 있는 점토의 개수(1레벨은 1마리, 2레벨은 2마리...)

    [Header("Game Manager")]
    public static GameManager instance; // 싱글톤 이용하기 위함
    public string curScene;
    public bool isInitialized = false; // 데이터 초기화 완료 여부
    private Coroutine dataSetCoroutine; // 데이터 초기화 코루틴 저장

    [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;

    [Header("Effect")]
    // 0: 점토 레벨업, 1: 점토 판매, 2: 점토 해금, 3: 업그레이드
    public ParticleSystem[] effectsPrefabs; // 프리팹 넣어놓기
    public ParticleSystem[] effects; // 관리용 변수
    public string[] effectGameObjectNames;

    [Header("Toy Control")]
    public int curToyIdx = -1; // 현재 선택된 장난감
    public RuntimeAnimatorController[] clayToyAnimators; // 가구랑 상호작용하는 애니메이터
    public string[] toyInfo; // 가구를 클릭하면 안내 판넬에 띄울 내용
    public delegate void SetClayHouseLevel(int houseLevel, int clickLevel);
    public SetClayHouseLevel OnSetClayHouseInfo;

    // Light & UI Control
    public delegate void SetLightHandler(bool flag);
    public event SetLightHandler OnSetLightHandler; // 여기에 빛 관리하는 메서드 연결해놓을 것(점토의 드래그 시작되면 이 델리게이트에 연결된 메서드를 호출하도록..)


    // 야생 콘텐츠 관련
    [Header("World Manager")]
    // 게임 시작 종료 여부
    public bool isGameStart = false; 
    public bool isGameEnd = false;
    public bool isGameClear = false;
    public int worldLevel = 0; // 월드 게임 난이도(0: 쉬움, 1: 보통, 2: 어려움)
    public int getClayIdx; // 얻은 점토 인덱스(이 값으로 새로운 점토를 소환할 것!) 씬 로드할 때 하면 될 듯?
    public int isFirst = -1; // 잡은 점토가 처음이면 isFirst 가 해당 점토으 인덱스로.. 처음 잡힌게 아니면 걍 -1임

    [Header("New Alam")]
    public GameObject newAlam;

    private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
    {
        // 여기서 데이터 세팅하기
        // DataManager 준비될 때까지 기다려!
        if (dataSetCoroutine != null)
            StopCoroutine(dataSetCoroutine); // 이미 시작한 코루틴 있으면 끝내고 다시 시작

        dataSetCoroutine = StartCoroutine(OnSceneLoadedSetting()); // 정보 세팅
    }

    private void Awake()
    {
        // 싱글톤 이용
        if (instance != null && instance != this)
        {
            // 만약 이미 존재하면 그냥 없애
            Destroy(gameObject);
            return;
        }

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

    private void OnEnable()
    {
        // 씬이 로드될 때마다 알아서 호출될 수 있도록..
        SceneManager.sceneLoaded += OnSceneLoaded; // 이벤트에 메서드 연결
    }

    private void OnDisable()
    {
        // 게임 오브젝트가 비활성화 될 때 이벤트에 연결해놓은 메서드 없애기
        SceneManager.sceneLoaded -= OnSceneLoaded;
    }


    // 씬 로드될 때 수행되어야 하는 로직 모음집..
    private IEnumerator OnSceneLoadedSetting()
    {
        // 데이터 매니저 준비될 때까지 기다려!!!
        // DataManager 초기화 완료 기다리기
        while (!DataManager.instance.isInitialized)
        {
            yield return null;
        }

        Debug.Log("음 이제 DataManager 이용할 수 있어용~");


        curScene = SceneManager.GetActiveScene().name; // 씬 이름 가져오기


        // 씬에 따라 정보 세팅 다르게..
        if (curScene == "ClayHouse")
        {
            // 현재 씬이 클레이 하우스인 경우에만 호출 되도록..
            poolManager = GameObject.Find("PoolManager").GetComponent<PoolManager>(); // 풀매니저 찾아서 할당
            gameDataUI = GameObject.Find("GameDataUIController").GetComponent<GameDataUIController>(); // 게임 데이터 UI 찾아서 할당

            for (int i = 0; i < effectsPrefabs.Length; i++)
            {
                // 이펙트 생성해서 넣어놓기
                effects[i] = Instantiate(effectsPrefabs[i], GameObject.Find(effectGameObjectNames[i]).transform);
                effects[i].gameObject.SetActive(false); // 비활성화
            }

            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); // 게임 종료 메서드 연결

            newAlam = GameObject.Find("CanvasParent").transform.Find("Canvas1").transform.Find("Left Button").transform.Find("Clay Button").transform.Find("NewAlam").gameObject;


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

            LoadDataSet(); // 데이터 반영
        }

        isInitialized = true; // 데이터 반영 완료
    }


    private void LoadDataSet()
    {
        if (curScene == "World") return; // 만약 현재 씬이 야생이면 그냥 빠져나가도록..

        // 저장된 게임 데이터가 있는 경우 데이터 가져와서 반영
        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];
            }
        }

        // 저장된 게임 수치 데이터가 있는 경우 데이터 가져와서 반영
        if (DataManager.instance.data.valueDatas != null)
        {
            // 저장된 데이터 반영해서 가져오기
            gold = DataManager.instance.data.valueDatas.gold;
            love = DataManager.instance.data.valueDatas.love;
            clayHouseLevel = DataManager.instance.data.valueDatas.clayHouseLevel;
            clayClickLevel = DataManager.instance.data.valueDatas.clayClickLevel;
            curPossibleClayNum = DataManager.instance.data.valueDatas.curPossibleClayNum;

            SetGoldLove(); // 로드한 데이터 반영해서 데이터 UI 업데이트..
            SetUpgradePanel(); // 델리게이트 호출
        }
    }

    public void SetUpgradePanel()
    {
        if (curScene == "World") return; // 만약 현재 씬이 야생이면 그냥 빠져나가도록..

        OnSetClayHouseInfo?.Invoke(clayHouseLevel, clayClickLevel); // UpgradePanel 클래스의 SetUpgardePanel() 메서드 호출
    }

    public void SetGoldLove()
    {
        if (curScene == "World") return; // 만약 현재 씬이 야생이면 그냥 빠져나가도록..

        // 로드한 데이터에 맞게 데이터 UI 변경할 수 있도록..

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

        updateTextUICoroutine = StartCoroutine(gameDataUI.UpdateTextUI("gold", gold, gold));
        updateTextUICoroutine = StartCoroutine(gameDataUI.UpdateTextUI("love", love, love));
    }

    // 재화 얻는 함수
    public void GetGold(float capacity)
    {
        if (curScene == "World") return; // 만약 현재 씬이 야생이면 그냥 빠져나가도록..

        // 이미 코루틴이 종료되지 않은 중에 동일한게 또 들어오면 겹쳐서 반영이 돼서 이상하게 될 수 있으므로 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)
    {
        if (curScene == "World") return; // 만약 현재 씬이 야생이면 그냥 빠져나가도록..

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

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

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

    public void SetSaveData()
    {
        if (curScene == "World") return; // 만약 현재 씬이 야생이면 그냥 빠져나가도록..

        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]); // 포획 여부 저장
        }

        // 수치 데이터 저장
        DataManager.instance.data.valueDatas = new ValueDatas();
        DataManager.instance.data.valueDatas.gold = gold;
        DataManager.instance.data.valueDatas.love = love;
        DataManager.instance.data.valueDatas.clayHouseLevel = clayHouseLevel;
        DataManager.instance.data.valueDatas.clayClickLevel = clayClickLevel;
        DataManager.instance.data.valueDatas.curPossibleClayNum = curPossibleClayNum;
    }


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

    
    public void StartInfoPanel(string text)
    {
        if (curScene == "World") return; // 만약 현재 씬이 야생이면 그냥 빠져나가도록..

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

    public void SetLightAndUI(bool flag)
    {
        if (curScene == "World") return; // 만약 현재 씬이 야생이면 그냥 빠져나가도록..

        OnSetLightHandler?.Invoke(flag); // flag 값을 전달해서 델리게이트에 연결된 메서드 호출 
    }

    public void MoveScene()
    {
        // 게임 매니저와 데이터 매니저의 isInitailized 값을 다시 false 로 바꿔주기
        isInitialized = false; // 다시 false 로..
        DataManager.instance.isInitialized = false;

        if (curScene == "ClayHouse")
        {
            DataManager.instance.SaveGameData(); // 씬 전환 하기 전 데이터 저장!

            
            ResetWorldGame(); // 월드 게임 정보 초기화


            curScene = "World"; // 씬 이름 바꿔주깅
            // 현재가 점토 집인 경우에는 World 씬으로 이동
            SceneManager.LoadScene("World");
        }
        else if (curScene == "World")
        {
            // 야생일 때는 딱히 저장할 데이터 없음

            curScene = "ClayHouse";
            // 현재 World 씬인 경우 점토 집 씬으로 이동 
            SceneManager.LoadScene("ClayHouse");
        }
    }

    public void ResetWorldGame()
    {
        // 야생으로 넘어갈 때 호출되는 메서드
        isGameStart = false;
        isGameEnd = false;
        isGameClear = false;
    }

    public void WorldGameClear()
    {
        // 야생에 성공했을 때 호출되는 메서드
        isGameStart = false;
        isGameEnd = true;
        isGameClear = true;
    }

    public void WorldGameFail()
    {
        // 야생에 성공했을 때 호출되는 메서드
        isGameStart = false;
        isGameEnd = true;
        isGameClear = false;
    }
}

 

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

더보기

1. 변수

다음과 같은 변수가 추가됐다. isFirst 는 현재 잡은 점토가 처음인지 아닌지 판단하기 위해 선언했다. 만약 처음 잡힌 점토라면 newAlam 게임 오브젝트를 활성화 하도록 했다.

public int isFirst = -1; // 잡은 점토가 처음이면 isFirst 가 해당 점토으 인덱스로.. 처음 잡힌게 아니면 걍 -1임

[Header("New Alam")]
public GameObject newAlam;

 

2.7 UIController 스크립트

더보기
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEditor.SearchService;
using UnityEngine;
using UnityEngine.UI;

public class UIController : MonoBehaviour
{
    [Header("Heart UI")]
    public GameObject[] hearts;

    // 게임 시작, 종료 판넬
    [Header("GamePanel")]
    public GameObject gameStartPanel;
    public Button gameStartButton;

    public GameObject gameOverPanel;
    public Button gameOverButton;
    public Animator gameOverAnim;

    public GameObject gameClearPanel;
    public Button gameClearButton;
    public Animator gameClearAnim;
    public GameObject rewardClay;
    public Sprite[] clayImages;
    public GameObject newText; // 점토가 처음 잡힌 애면 newText 뜨도록!

    private void Awake()
    {
        // 버튼 정보 세팅하는 메서드 호출
        SetGameStartButton();
        SetGameEndButton();


        // 게임 시작 판넬 띄우도록
        gameStartPanel.SetActive(true);
    }

    private IEnumerator Start()
    {
        // 아직 게임 시작 안 했으면 좀 기다리기..
        while (!GameManager.instance.isGameStart)
        {
            yield return null;
        }

        for (int i=0; i<hearts.Length; i++)
        {
            // 하트 애니메이션 수행
            hearts[i].GetComponent<Animator>().Play("Move", -1, i*0.2f);
        }

        StartCoroutine(OpenGameEndPanel()); // 게임 종료 판넬 띄우는 코루틴 시작
    }

    public void CloseSelf(GameObject obj)
    {
        // 오브젝트 비활성화
        obj.SetActive(false);
    }

    public void GameStart()
    {
        // 게임 시작 신호 주기
        GameManager.instance.isGameStart = true;
    }

    public void SetGameStartButton()
    {
        // 게임 시작 버튼에 연결
        gameStartButton.onClick.AddListener(() => CloseSelf(gameStartPanel));
        gameStartButton.onClick.AddListener(GameStart);
    }

    public void SetGameEndButton()
    {
        // 집에 돌아가야행~~

        gameOverButton.onClick.AddListener(() => CloseSelf(gameOverPanel));
        gameClearButton.onClick.AddListener(() => CloseSelf(gameClearPanel));

        gameOverButton.onClick.AddListener(GameManager.instance.MoveScene);
        gameClearButton.onClick.AddListener(GameManager.instance.MoveScene);
    }

    public IEnumerator OpenGameEndPanel()
    {
        // 게임이 종료될 때까지 기다려
        while (!GameManager.instance.isGameEnd)
        {
            yield return null;
        }

        // 게임 성공 여부에 따라 판넬 띄우기
        if (GameManager.instance.isGameClear)
        {
            gameClearPanel.SetActive(true);

            // 보상 점토 이미지 설정
            rewardClay.GetComponent<Image>().sprite = clayImages[GameManager.instance.getClayIdx];
            rewardClay.GetComponent<Image>().SetNativeSize(); // UI 갱신
            Canvas.ForceUpdateCanvases();

            gameClearAnim.SetTrigger("Show"); // 애니메이션 수행

            // 처음으로 잡힌 점토면 new Text
            if (GameManager.instance.catchedClays[GameManager.instance.getClayIdx] == false)
            {
                newText.SetActive(true); // 활성화!
                GameManager.instance.isFirst = GameManager.instance.getClayIdx;
            }    
        }
        else if (!GameManager.instance.isGameClear)
        {
            gameOverPanel.SetActive(true);
            gameOverAnim.SetTrigger("Show"); // 애니메이션 수행
        }
    }
}

 

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

더보기

1. 변수

다음과 같은 변수를 추가했다.

 

rewardClay 는 게임 클리어 판넬에 현재 얻은 점토의 이미지를 띄우기 위해서 선언했다. clayImages 는 띄울 점토의 이미지를 가져오기 위해서 선언했다. 마지막으로 newText 는 만약 현재 잡은 점토가 처음 잡은 점토라면 new! 글자를 뜨게 하기 위해 선언했다.

public GameObject rewardClay;
public Sprite[] clayImages;
public GameObject newText; // 점토가 처음 잡힌 애면 newText 뜨도록!

 

 

2. OpenGameEndPanel()

처음으로 잡힌 점톤지 확인하고 그에 맞게 게임 클리어 판넬을 설정하는 로직을 추가했다.

public IEnumerator OpenGameEndPanel()
{
    // 게임이 종료될 때까지 기다려
    while (!GameManager.instance.isGameEnd)
    {
        yield return null;
    }

    // 게임 성공 여부에 따라 판넬 띄우기
    if (GameManager.instance.isGameClear)
    {
        gameClearPanel.SetActive(true);

        // 보상 점토 이미지 설정
        rewardClay.GetComponent<Image>().sprite = clayImages[GameManager.instance.getClayIdx];
        rewardClay.GetComponent<Image>().SetNativeSize(); // UI 갱신
        Canvas.ForceUpdateCanvases();

        gameClearAnim.SetTrigger("Show"); // 애니메이션 수행

        // 처음으로 잡힌 점토면 new Text
        if (GameManager.instance.catchedClays[GameManager.instance.getClayIdx] == false)
        {
            newText.SetActive(true); // 활성화!
            GameManager.instance.isFirst = GameManager.instance.getClayIdx;
        }    
    }
    else if (!GameManager.instance.isGameClear)
    {
        gameOverPanel.SetActive(true);
        gameOverAnim.SetTrigger("Show"); // 애니메이션 수행
    }
}

 

2.9 MapSpawner 스크립트

맵 난이도에 맞게 야생 씬의 global light 색을 바꾸는 로직을 추가했다. 단순해서 딱히 설명은 길게 하지 않는다.

더보기
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.Rendering.Universal;

public class MapSpawner : MonoBehaviour
{
    [Header("Map Contoller")]
    public GameObject[] mapPrefabs; // 현재 맵 프리팹
    public GameObject[] easyMapPrefabs;
    public GameObject[] normalMapPrefabs;
    public GameObject[] hardMapPrefabs;
    public List<GameObject>[] pool;


    public GameObject easyBackground; // 쉬움 단계 배경
    public GameObject normalBackground; // 보통 단계 배경
    public GameObject hardBackground; // 어려움 단계 배경


    public float curTime = 0;
    public float targetTime = 0.5f; // targetTime 마다 맵 생성
    public int mapCount;
    public int mapLevel; // 0: 쉬움, 1: 보통, 2: 어려움
    
    private Coroutine mapCoroutine;

    [Header("Light")]
    public Light2D mapLight; // 맵 난이도에 따라 배경 빛 색깔 다르도록..

    private void Awake()
    {
        mapLevel = GameManager.instance.worldLevel; // 게임 매니저의 맵 레벨로 설정해주기
        Color32 col = new Color32(255, 255, 255, 255); // 디폴트값

        // 맵 난이도에 맞게 mapCount 설정..
        if (mapLevel == 0)
        {
            easyBackground.SetActive(true); // 배경 활성화 
            mapPrefabs = easyMapPrefabs; // 현재 팹 프리팹을 이지맵으로 설정
        }
        else if (mapLevel == 1)
        {
            normalBackground.SetActive(true); // 배경 활성화 
            mapPrefabs = normalMapPrefabs; // 현재 팹 프리팹을 노멀맵으로 설정
            col = new Color32(150, 150, 150, 150);
        }
        else if (mapLevel == 2)
        {
            hardBackground.SetActive(true); // 배경 활성화 
            mapPrefabs = hardMapPrefabs; // 현재 팹 프리팹을 하드맵으로 설정
            col = new Color32(120, 120, 120, 120);
        }

        mapLight.color = col; // 색 설정
        mapCount = mapPrefabs.Length; // 크기 설정

        pool = new List<GameObject>[mapCount]; // 배열 만들기
        for (int i=0; i<mapCount; i++)
        {
            pool[i] = new List<GameObject>(); // 리스트 새로 만들기
        }
    }

    private IEnumerator Start()
    {
        // 무한 루프..
        // 야생 게임이 시작될 때까지 기다리기..
        while (!GameManager.instance.isGameStart)
        {
            yield return null;
        }

        mapCoroutine = StartCoroutine(SpawnMap()); // 맵 생성 코루틴 시작   
        StartCoroutine(GameEnd()); // 게임 종료 코루틴 시작
    }


    private IEnumerator SpawnMap()
    {
        while (true)
        {
            int mapIdx = Random.Range(0, mapCount);
            GameObject select = null;

            foreach (GameObject map in pool[mapIdx])
            {
                // 만약 놀고 있는 맵 게임 오브젝트를 발견하면 그거 활성화
                if (map.activeSelf == false)
                {
                    select = map;
                    map.SetActive(true); // 맵 활성화
                    break;
                }
            }

            // 발견 못 하면 새로 생성
            if (select == null)
            {
                select = Instantiate(mapPrefabs[mapIdx], transform);
                pool[mapIdx].Add(select); // 새로 생성한 게임 오브젝트를 풀에 넣기
            }

            yield return new WaitForSeconds(targetTime); // targetTime 만큼 기다리기
        }
    }

    private IEnumerator GameEnd()
    {
        while (!GameManager.instance.isGameEnd)
            yield return null;

        StopCoroutine(mapCoroutine); // 게임 끝났으니까 종료!
    }
}

 

2.10 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 Button closeButton;
    public GameObject lockedPage; // 잠금 페이지
   

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

    [Header("Effect")]
    public int effectIdx = 2;

    [Header("Audio")]
    private AudioSource clayPanelAudio;
    public AudioClip unlockClip;
    public AudioClip buyClip;
    public AudioClip failClip;
    public AudioClip showClip;


    private void Awake()
    {
        clayPanelAudio = GetComponent<AudioSource>();
    }

    private IEnumerator Start()
    {
        // 게임 매니저가 준비 될 때까지 기다령~~
        while (!GameManager.instance.isInitialized)
            yield return null;

        maxIdx = GameManager.instance.poolManager.clayPrefabs.Length;

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

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

        // 잡아온 점토가 처음으로 잡힌 애면 별표 켜지도록..
        if (GameManager.instance.isFirst != -1)
            GameManager.instance.newAlam.SetActive(true);
    }

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

        ResetClayPanel();
    }

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

    public void SetClayPanel()
    {
        // 새로 잡아온 점토 페이지를 확인하면 점토 구매 버튼 위 별표 비활성화
        if (GameManager.instance.isFirst == pageIdx)
        {
            GameManager.instance.newAlam.SetActive(false);
        }

        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) {
            GameManager.instance.StartInfoPanel("마지막 페이지입니다.");
            PlaySound(failClip); // 효과음
            return; // 빠져나가기..
        }
        pageIdx++;

        SetButtonInfo();
        PlaySound(showClip); // 효과음
    }
    public void DownPageIdx()
    {
        if (pageIdx <= 0) {
            GameManager.instance.StartInfoPanel("처음 페이지입니다.");
            PlaySound(failClip); // 효과음
            return; // 빠져나가기..
        }
        pageIdx--;
        SetButtonInfo();
        PlaySound(showClip); // 효과음
    }

    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("야생에서 잡아와야 해요!");
            PlaySound(failClip); // 효과음
            return;
        }

        GameManager.instance.unLockedClays[idx] = true;
        PlayEffect(effectIdx); // 이펙트 소환
        SetClayPanel();
        PlaySound(unlockClip); // 효과음
    }

    public void PlayEffect(int idx)
    {
        if (GameManager.instance.effects[idx].gameObject.activeSelf == false)
            GameManager.instance.effects[idx].gameObject.SetActive(true); // 활성화하기
        GameManager.instance.effects[idx].Play();
    }

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

        // 돈이 충분하고 공간이 있으면 점토 구매
        if (GameManager.instance.gold >= price && (GameManager.instance.curPossibleClayNum > GameManager.instance.poolManager.curClayNum))
        {
            GameManager.instance.GetGold(-price);
            GameManager.instance.poolManager.GetGameObject(idx); // 동물 get!
            GameManager.instance.poolManager.curClayNum++; // 점토 개수 증가
            
            
            PlaySound(buyClip); // 효과음
        }
        else if (GameManager.instance.gold < price)
        {
            // 안내 판넬 띄우기
            GameManager.instance.StartInfoPanel("돈이 부족해요 ㅠ_ㅠ");
            PlaySound(failClip); // 효과음
            return;
        }
        else if (GameManager.instance.curPossibleClayNum <= GameManager.instance.poolManager.curClayNum) {
            // 안내 판넬 띄우기
            GameManager.instance.StartInfoPanel("집이 너무 좁아요 ㅠ_ㅠ");
            PlaySound(failClip); // 효과음
            return;
        }  
    }

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

    private void PlaySound(AudioClip clip)
    {
        clayPanelAudio.clip = clip;
        clayPanelAudio.Play();
    }
}

 

2.11 ClayPanel 스크립트 변경 사항 설명

더보기

1. SetClayPanel()

새로 잡아온 점토 페이지를 확인하면 점토 구매 버튼 위 별표를 비활성화 하는 로직을 추가했다.

public void SetClayPanel()
{
    // 새로 잡아온 점토 페이지를 확인하면 점토 구매 버튼 위 별표 비활성화
    if (GameManager.instance.isFirst == pageIdx)
    {
        GameManager.instance.newAlam.SetActive(false);
    }

    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 + ""; // 점토 가격 가져오기      
}

 

 


 

 

3. 결과물

 

 

 

 

  1. 0. 들어가기 전에
  2. 1. 게임 오브젝트
  3. 1.1 메인 씬
  4. 1.2 야생 씬
  5. 2. 스크립트
  6. 2.1 BGM 스크립트
  7. 2.2 BGM 스크립트 설명
  8. 2.3 Player 스크립트
  9. 2.4 Player 스크립트 변경 사항 설명
  10. 2.5 GameManager 스크립트
  11. 2.6 GameManager 스크립트 변경 사항 설명
  12. 2.7 UIController 스크립트
  13. 2.8 UIController 스크립트 변경 사항 설명
  14. 2.9 MapSpawner 스크립트
  15. 2.10 ClayPanel 스크립트
  16. 2.11 ClayPanel 스크립트 변경 사항 설명
  17. 3. 결과물
'유니티 프로젝트/점토게임' 카테고리의 다른 글
  • [개발일지] 33. 메인 씬 오디오 적용 & UI 뒤쪽 게임 오브젝트 클릭 방지
  • [개발일지] 32. 야생에서 잡아온 점토 생성
  • [개발일지] 32. 씬 전환시 데이터 저장&적용
  • [개발일지] 31. 야생 판넬 제작 & 체력바 애니메이션 적용 & 씬 이동
dubu0721
dubu0721
dubu0721 님의 블로그 입니다.
dubu0721 님의 블로그dubu0721 님의 블로그 입니다.
  • dubu0721
    dubu0721 님의 블로그
    dubu0721
  • 전체
    오늘
    어제
    • 분류 전체보기 (355) N
      • 프로그래밍언어론 정리 (5)
      • 컴퓨터네트워크 정리 (5)
      • 알고리즘&자료구조 공부 (64)
        • it 취업을 위한 알고리즘 문제풀이 입문 강의 (60)
        • 학교 알고리즘 수업 (3)
        • 실전프로젝트I (0)
      • 백준 문제 (207) N
        • 이분탐색 (7)
        • 투포인트 (10)
        • 그래프 (11)
        • 그리디 (24)
        • DP (25)
        • BFS (22) N
        • MST (7)
        • KMP (4)
        • Dijkstra (3)
        • Disjoints Set (4)
        • Bellman-Ford (2)
        • 시뮬레이션 (3)
        • 백트래킹 (15)
        • 위상정렬 (6) N
        • 자료구조 (25)
        • 기하학 (1)
        • 정렬 (11)
        • 구현 (8)
        • 재귀 (8)
        • 수학 (8)
        • 트리 (1)
      • 유니티 공부 (11)
        • 레트로의 유니티 게임 프로그래밍 에센스 (11)
        • 유니티 스터디 자료 (0)
        • C# 공부 (0)
      • 유니티 프로젝트 (48)
        • 케이크게임 (13)
        • 점토게임 (35)
      • 언리얼 공부 (10)
        • 이득우의 언리얼 프로그래밍 (10)
      • 진로 (1)
      • 논문 읽기 (2)
  • 블로그 메뉴

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

  • 공지사항

  • 인기 글

  • 태그

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

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
dubu0721
[개발일지] 34[완결]. 야생 UI 수정 & 메인 씬 기능 추가

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.