말감로그

[Unity] Valley - 씬 이동 시 페이드 인/아웃 효과 & 텍스트 효과 & 플레이어 돈 시간 저장(PlayerPrefs) 본문

TIL

[Unity] Valley - 씬 이동 시 페이드 인/아웃 효과 & 텍스트 효과 & 플레이어 돈 시간 저장(PlayerPrefs)

habbn 2024. 11. 20. 17:33
728x90

 

씬 이동 페이드 인/아웃 효과

타이틀 씬에서 인게임 씬으로 넘어갈 때 페이드 인/아웃 효과를 주도록 하였다. 코루틴을 사용하여 알파 값을 조정하여 효과를 주도록 하였지만, 타이틀에서 인게임 씬으로 넘어갈 때 페이드 인 효과는 나타나지 않고 바로 씬이 전환되고 MissingRefrence 에러가 발생했었다.

해당 에러는 Image 즉, fadePanel이 파괴되었는데 접근하려고 해서 생긴 에러였다.

FadeEffect라는 스크립트를 포함하는 게임오브젝트를 생성해주었고, 캔버스 아래에 fadePanel을 생성하고, 싱글톤으로 씬이 바뀌어도 사라지지않도록 했지만, 자꾸 사라지게 되고, 아예 Image 자체도 DonDestroyOnLoad() 해도 똑같은 상황이었다.

 

유튜브를 찾고 gpt에게 물어보니, 이러한 구조로 fadePanel은 Canvas의 자식, Canvas와 FadeEffect는 같은 GameObject에 포함되는 식으로 구조를 짜야 된다고 한다.

FadeEffect (GameObject)
└── Canvas (with FadeEffect and fadePanel)
    └── Image (fadePanel)

 

FadeEffect가 포함된 GameObject 전체를 DontDestroyOnLoad로 설정했으므로, 씬 전환 후에도 유지되기 때문이다.

 

지금까지는 FadeEffect 따로, 캔버스 따로 존재하는 상태에서 FadeEffect만을 DontDestroyOnLoad 했기 때문에 fadePanel은 자연스레 씬이 넘어가면서 destroy 되었던 것이다. 내가 왜 이생각을 못했는지, 당연한 문제를 헤매고 있었다는게 아쉬웠다.

그래서 이런 식으로 구조를 짜고, FadeEffect 스크립트는 FadeCanvas의 부모 오브젝트에 달아주었다.

 

using System.Collections;
using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class FadeEffect : MonoBehaviour
{
    public static FadeEffect instance;
    public Image fadePanel;
    public TextMeshProUGUI loadingText;

    private float fadeDuration = 3f;

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

    public IEnumerator FadeScreen(float targetAlpha)
    {
        float startAlpha = fadePanel.color.a;
        float elapsedTime = 0f;

        while (elapsedTime < fadeDuration)
        {
            elapsedTime += Time.deltaTime;
            float newAlpha = Mathf.Lerp(startAlpha, targetAlpha, elapsedTime / fadeDuration);
            fadePanel.color = new Color(0, 0, 0, newAlpha);
            yield return null;
        }

        fadePanel.color = new Color(0, 0, 0, targetAlpha);
        yield return new WaitForSeconds(1f);
    }

    public void FadeAndLoadScene(string sceneName)
    {
        StartCoroutine(FadeAndSwitchScene(sceneName));
    }

    private IEnumerator FadeAndSwitchScene(string sceneName)
    {
        yield return FadeScreen(1f);

        loadingText.gameObject.SetActive(true);
        loadingText.text = "로딩 중...";

        AsyncOperation asyncLoad = SceneManager.LoadSceneAsync(sceneName);
        asyncLoad.allowSceneActivation = false; // 씬이 로드되었으나 자동으로 활성화되지 않도록 설정

        while (!asyncLoad.isDone)
        {
            if (asyncLoad.progress >= 0.9f)
            {
                yield return new WaitForSeconds(2f);
                asyncLoad.allowSceneActivation = true;
            }
            yield return null;
        }

        loadingText.text = "로딩 완료!";
        yield return new WaitForSeconds(1f);
        loadingText.gameObject.SetActive(false);

        yield return FadeScreen(0f);
    }
}

 

 

페이드 아웃이 실행되어, 화면이 점점 어두워지고 "로딩 중.." 이라는 텍스트가 업로드 된 후, SceneManager.LoadSceneAsyn() 메서드를 호출하여 지정된 씬을 비동기적으로 로드하게 한다. 씬이 로드되었으나 자동으로 활성화되지 않도록 설정한 뒤, 씬 로드 진행률이 로드 완료 단계에 도달하면 2초 대기 후, 씬을 활성화시키고 페이드 인 하여 화면을 점점 밝힌다.

 

 

실시간으로 증가되는 머니 텍스트 효과

 

아이템을 팔고 다음날이 되면 판 금액이 플레이어의 금액으로 들어오는 효과를 만들었다.

마찬가지로 코루틴을 활용하여 시작 금액(현재 플레이어가 가지고 있는 돈) 부터, 목표 금액(판 금액) 까지 lerp를 활용하여 실시간으로  ui를 업데이트 해주면서 증가되는 효과를 보여주었다.

Mathf.RoundToInt() 함수를 통해 실수 값을 정수로 반올림하여 반환하고,

Mathf.Lerp() 함수를 통해 값을 보간하여 부드럽게 변화시키도록 했다.

    public void UpdateMoneyUI(int money)
    {
        moneyText.text = money.ToString();
    }

    public IEnumerator UpdateMoneyEffect(int startValue, int endValue)
    {
        yield return new WaitForSeconds(0.5f);

        float duration = 1f;
        float elapsedTime = 0f;

        while (elapsedTime < duration)
        {
            currentMoney = Mathf.RoundToInt(Mathf.Lerp(startValue, endValue, elapsedTime / duration));
            UpdateMoneyUI(currentMoney);
            elapsedTime += Time.deltaTime;
            yield return null;
        }

        GameManager.instance.player.money = endValue;
        UpdateMoneyUI(GameManager.instance.player.money);
    }

 

 

PostBox 열면 기본 아이템 주기

PostBox를 Raycast로 인식하여 클릭 할 시, PostPanel이 띄워지고, 시작 아이템들을 Toolbar에 추가시켜주도록 하였다.

private void OpenPostBox()
{
    rayHit = Physics2D.Raycast(rb.position, lastMoveDirection, 1f, LayerMask.GetMask("PostBox"));
    if (rayHit.collider != null)
    {
        if (UIManager.instance.speechBubble.activeSelf)
        {
            if (Input.GetMouseButtonDown(1))
            {
                UIManager.instance.ShowPostPanel();
            }
        }
    }
}
public void startItemAdd(string inventoryName)
{
    foreach (var item in startItems)
    {
        inventoryByName[inventoryName].Add(item);
    }
}

 

PostBoxPanel에 있는 버튼의 OnClick 메서드에 startItemAdd 함수와 postboxPanel를 꺼주는 기능을 추가해주었다.

 

 

 

플레이어의 돈과 시간 저장&로드하기

 

플레이어의 돈과 시간은 PlayerPrefs를 사용하여 저장해주었다. 저장과 로드 방식은 이전에 했던 것과 동일하기 때문에, 함수를 만들고 추가해주는 식으로 했다.

    public void SavePlayerData(int currentMoney, int currentDay, int currentDaysOfWeekIndex, int sellingPrice)
    {
        PlayerPrefs.SetInt("Money", currentMoney);
        PlayerPrefs.SetInt("Day", currentDay);
        PlayerPrefs.SetInt("DaysOfWeekIndex", currentDaysOfWeekIndex);
        PlayerPrefs.SetInt("SellingPrice", sellingPrice);
        PlayerPrefs.Save();
    }

    public void LoadPlayerData()
    {
        int currentMoney = PlayerPrefs.GetInt("Money");
        int currentDay = PlayerPrefs.GetInt("Day");
        int currentDayIndex = PlayerPrefs.GetInt("DayIndex");
        int sellingPrice = PlayerPrefs.GetInt("SellingPrice");

        GameManager.instance.player.money = currentMoney;
        GameManager.instance.timeManager.day = currentDay;
        GameManager.instance.timeManager.currentDayIndex = currentDayIndex;
        GameManager.instance.itemBox.sellingPrice = sellingPrice;

        if (sellingPrice > 0)
        {
            GameManager.instance.itemBox.SellItems();
            GameManager.instance.itemBox.ResetSellingPrice();
        }
    }
728x90

'TIL' 카테고리의 다른 글

[Unity] Valley - Sound Manager  (0) 2024.11.22
[Unity] Valley - Item Shop 구현  (0) 2024.11.21
[Unity] Valley - 동물 움직임 제어  (0) 2024.11.19
[Unity] Valley - Animated Tile  (0) 2024.11.15
[Unity] Valley - 식물 로드 버그 수정  (0) 2024.11.14