김김김의 게임개발
  • 유니티 게임개발 - 게임 개발 심화 팀 과제 #4
    2023년 10월 20일 19시 31분 31초에 업로드 된 글입니다.
    작성자: noun06

    [스킨 상점 시스템]

    상점 씬에서 게임 내 사용할 수 있는 스킨을 관리하는 클래스 SkinPanel 내에서는 스킨SO 데이터를 받아와 정보를 저장합니다. 또한 PlayerPurchase 클래스의 플레이어 구매 스킨 관련 데이터를 처리하는 인스턴스를 저장합니다. EquipSkin() 메서드 내에서 스킨이 잠겨 있지 않고 구매되어 있으면 스킨을 장착하거나 구매를 시도합니다.

    using System.Collections;
    using System.Collections.Generic;
    using TMPro;
    using UnityEngine;
    using UnityEngine.UI;
    
    public class SkinPanel : MonoBehaviour
    {
        public SkinSO skinInfo;
        public TMP_Text buttonText;
        public PlayerPurchase playerPurchase;
    
        private void Start()
        {
            UpdateSkinInfo();
            skinInfo.locked = !playerPurchase.IsSkinPurchased(skinInfo);
        }
    
        public void UpdateSkinInfo()
        {
            UpdateButtonText();
        }
    
        public void EquipSkin()
        {
            if (!skinInfo.locked)
            {
                SkinLoadController.skinToLoad = skinInfo.skinPrefab;
            }
            else
            {
                TryPurchaseSkin();
            }
        }
    
        private void UpdateButtonText()
        {
            if (!skinInfo.locked)
            {
                buttonText.text = "EQUIP";
            }
            else
            {
                if (playerPurchase.IsSkinPurchased(skinInfo))
                {
                    buttonText.text = "EQUIP";
                    skinInfo.locked = false;
                }
                else
                {
                    buttonText.text = "BUY [" + skinInfo.price + "G]";
                }
            }
        }
    
        private void TryPurchaseSkin()
        {
            if (playerPurchase.playerData.coins >= skinInfo.price && !playerPurchase.IsSkinPurchased(skinInfo))
            {
                playerPurchase.PurchaseSkin(skinInfo);
                UpdateSkinInfo();
            }
        }
    }

     

    SkinLoadController 클래스는 게임 시작 시 특정 스킨을 로드하고 기본 스킨을 경우에 따라 제거합니다. 로드할 스킨을 저장하는 정적 변수가 있으며 skinToLoad 에 스킨이 지정되어 있으면 해당 스킨을 복제하고 기본 스킨을 제거하며 필요한 경우 캐릭터 컨트롤러의 애니메이터와 모델을 업데이트합니다.

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class SkinLoadController : MonoBehaviour
    {
        public static GameObject skinToLoad;
        [SerializeField] private GameObject defaultSkin;
    
        private void Awake()
        {
            if (skinToLoad != null)
            {
                GameObject skinClone = Instantiate(skinToLoad, transform);
                Destroy(defaultSkin);
                CharacterController characterController = GetComponent<CharacterController>();
    
                if (characterController != null)
                {
                    Animator skinAnimator = skinClone.GetComponent<Animator>();
                    characterController.animator = skinAnimator;
                    characterController.characterBody = skinClone.transform;
                }
            }
        }
    }

     

    [데이터 매니저]

    PlayerDataManager 클래스는 플레이어 데이터를 관리하고 저장하는 역할을 합니다. 플레이어 데이터를 저장하는 SO를 참조하는 변수를 통해 플레이어의 코인, 구매한 스킨, 스코어 등의 정보를 저장합니다.

    싱글톤 패턴을 사용하여 다양한 게임 로직에서 쉽게 메서드를 호출하여 사용할 수 있습니다. 

    LoadPlayerData와 SavePlayerData는 PlayerPrefs를 사용하여 플레이어 데이터 중 코인 데이터를 로드하고 저장합니다.

    SaveBestScore 메서드는 특정 미니게임에 대한 최고 점수를 저장하고 reverse 매개변수에 따라 최고 점수를 업데이트합니다. 미니게임의 값은 전역 열거형을 통해서 관리되어집니다. LoadBestScore은 특정 미니게임에 대한 최고 점수를 불러오며 게임 선택 씬에서 HighScoreUI 클래스를 통해 불러올 수 있습니다.

    using UnityEngine;
    
    public class PlayerDataManager : MonoBehaviour
    {
        public PlayerSO playerData;
    
        public static PlayerDataManager Instance { get; private set; }
    
        private void Awake()
        {
            if (Instance == null)
            {
                Instance = this;
                DontDestroyOnLoad(gameObject);
            }
            else
            {
                Destroy(gameObject);
            }
        }
    
        private void Start()
        {
            LoadPlayerData();
            SavePlayerData();
        }
    
        private void OnApplicationQuit()
        {
            SavePlayerData();
        }
    
        private void LoadPlayerData()
        {
            if (PlayerPrefs.HasKey("Coins"))
            {
                playerData.coins = PlayerPrefs.GetInt("Coins");
            }
        }
    
        private void SavePlayerData()
        {
            PlayerPrefs.SetInt("Coins", playerData.coins);
            PlayerPrefs.Save();
        }
    
        public void SaveBestScore(MiniGame scene, int score, bool reverse = false)
        {
            int currentBestScore = 0;
    
            if (reverse)
            {
                currentBestScore = int.MaxValue;
                currentBestScore = PlayerPrefs.GetInt(scene.ToString() + "_BestScore", 0);
                if (score < currentBestScore)
                {
                    PlayerPrefs.SetInt(scene.ToString() + "_BestScore", score);
                    PlayerPrefs.Save();
                }
            }
            else
            {
                currentBestScore = PlayerPrefs.GetInt(scene.ToString() + "_BestScore", 0);
                if (score > currentBestScore)
                {
                    PlayerPrefs.SetInt(scene.ToString() + "_BestScore", score);
                    PlayerPrefs.Save();
                }
            }
    
        }
    
        public int LoadBestScore(MiniGame scene)
        {
            return PlayerPrefs.GetInt(scene.ToString() + "_BestScore", 0);
        }
    
        public void ResetData()
        {
            PlayerPrefs.DeleteAll();
        }
    }
    using TMPro;
    using UnityEngine;
    
    public class HighScoreUI : MonoBehaviour
    {
        [SerializeField] private TMP_Text memoryGameBestScoreText;
        [SerializeField] private TMP_Text rotateGameBestScoreText;
        [SerializeField] private TMP_Text packmanGameBestScoreText;
        [SerializeField] private TMP_Text GoingUpGameBestScoreText;
        [SerializeField] private TMP_Text ParkStageGameBestScoreText;
        [SerializeField] private TMP_Text infiniteStairGameBestScoreText;
        [SerializeField] private TMP_Text ParkStageScene2StairGameBestScoreText;
    
        private void Start()
        {
            UpdateBestScoreText(memoryGameBestScoreText, MiniGame.MemoryGame);
            UpdateBestScoreText(rotateGameBestScoreText, MiniGame.RotateGame);
            UpdateBestScoreText(infiniteStairGameBestScoreText, MiniGame.InfiniteStairScene);
            UpdateBestScoreText(GoingUpGameBestScoreText, MiniGame.GoingUp);
            UpdateBestScoreText(packmanGameBestScoreText, MiniGame.packmanGameScene);
            UpdateBestScoreText(ParkStageGameBestScoreText, MiniGame.ParkStageScene);
            UpdateBestScoreText(ParkStageScene2StairGameBestScoreText, MiniGame.ParkStageScene2);
        }
    
        void UpdateBestScoreText(TMP_Text textComponent, MiniGame game)
        {
            textComponent.text = "최고점수: " + PlayerDataManager.Instance.LoadBestScore(game).ToString();
        }
    }
    댓글