using UnityEngine; using UnityEngine.SceneManagement; using TMPro; // 게임 오버 상태를 표현하고, 게임 점수와 UI를 관리하는 게임 매니저 // 씬에는 단 하나의 게임 매니저만 존재할 수 있다. public class GameManager : MonoBehaviour { public static GameManager instance; // 싱글톤을 할당할 전역 변수 public bool isGameover = false; // 게임 오버 상태 public TextMeshProUGUI scoreText; // 점수를 출력할 UI 텍스트 public GameObject gameoverUI; // 게임 오버시 활성화 할 UI 게임 오브젝트 private int score = 0; // 게임 점수 private int currentLife; // 현재 남은 목숨 private int stageMileage = 0; // 현재 플레이 중 획득한 마일리지 private int totalMileage = 0; // 누적 보유 마일리지 public int maxLife = 3; // 시작 목숨 public int initialMileage = 500; // 첫 시작시 지급할 초기 마일리지 public bool grantInitialMileage = true; // 초기 마일리지 지급 여부 public bool saveMileageImmediately = true; // 스테이지 정산 전까지는 획득 즉시 누적한다. private const string TotalMileageKey = "UniRun.TotalMileage"; private const string InitialMileageGrantedKey = "UniRun.InitialMileageGranted"; // 게임의 스피드를 올리는 변수 public float gameSpeed = 1f; public float minGameSpeed = 1f; public float speedIncreaseRate = 0.05f; public float maxGameSpeed = 2f; public float hitSpeedPenalty = 0.3f; // 게임 시작과 동시에 싱글톤을 구성 void Awake() { // 싱글톤 변수 instance가 비어있는가? if (instance == null) { // instance가 비어있다면(null) 그곳에 자기 자신을 할당 instance = this; } else { // instance에 이미 다른 GameManager 오브젝트가 할당되어 있는 경우 // 씬에 두개 이상의 GameManager 오브젝트가 존재한다는 의미. // 싱글톤 오브젝트는 하나만 존재해야 하므로 자신의 게임 오브젝트를 파괴 Debug.LogWarning("씬에 두개 이상의 게임 매니저가 존재합니다!"); Destroy(gameObject); } } private void Start() { currentLife = maxLife; totalMileage = PlayerPrefs.GetInt(TotalMileageKey, 0); if(grantInitialMileage && PlayerPrefs.GetInt(InitialMileageGrantedKey, 0) == 0) { totalMileage += initialMileage; PlayerPrefs.SetInt(TotalMileageKey, totalMileage); PlayerPrefs.SetInt(InitialMileageGrantedKey, 1); PlayerPrefs.Save(); } UpdateScoreUI(); } void Update() { // 게임 오버 상태에서 게임을 재시작할 수 있게 하는 처리 if(isGameover && Input.GetMouseButtonDown(0)) { SceneManager.LoadScene(SceneManager.GetActiveScene().name); } if (!isGameover) { // 게임 진행시 게임 속도는 시간에 따라 증가 gameSpeed += speedIncreaseRate * Time.deltaTime; // 게임 최대 속도는 max를 넘어서지 못하게 gameSpeed = Mathf.Min(gameSpeed, maxGameSpeed); UpdateScoreUI(); } } // 점수를 증가시키는 메서드 public void AddScore(int newScore) { if(!isGameover) { score += newScore; UpdateScoreUI(); } } // 마일리지 토큰을 먹었을 때 호출되는 메서드 public void AddMileage(int amount) { if(isGameover) { return; } stageMileage += amount; score += Mathf.Max(1, amount / 10); if(saveMileageImmediately) { totalMileage += amount; PlayerPrefs.SetInt(TotalMileageKey, totalMileage); PlayerPrefs.Save(); } UpdateScoreUI(); } // 플레이어가 장애물에 부딪혔을 때 목숨과 속도를 줄이는 메서드 public bool TakeDamage(int damage = 1) { if(isGameover) { return false; } currentLife -= damage; currentLife = Mathf.Max(currentLife, 0); gameSpeed -= hitSpeedPenalty; gameSpeed = Mathf.Max(gameSpeed, minGameSpeed); UpdateScoreUI(); return currentLife <= 0; } // 플레이어 캐릭터가 사망시 게임 오버를 실행하는 메서드 public void OnPlayerDead() { isGameover = true; gameoverUI.SetActive(true); } private void UpdateScoreUI() { scoreText.text = "Score : " + score + "\nLife : " + currentLife + "/" + maxLife + "\nMileage : " + stageMileage + "\nTotal : " + totalMileage + "\nSpeed : " + gameSpeed.ToString("0.0"); } }