카테고리 없음

2025.05.29 8주차 목요일

mochoa 2025. 5. 29. 21:36

주요 구현 내용 요약

1.인트로 건너뛰기 기능 구현 

2. 게임 클리어 & 게임 오버 처리, UI 페이드 연출


3. 위치 저장 및 불러오기 기능 구현 

 

1.인트로 건너뛰기 기능 구현 (Unity)

목표

  • 게임을 불러오기(load) 한 경우에는 인트로 Timeline이 실행되지 않고, 바로 플레이어와 UI가 등장하게 만들기

문제 상황

  • CameraIntroController.cs의 Start()에서 항상 director.Play()를 호출해서 인트로가 재생됨
  • "불러오기"를 눌러도 무조건 인트로 영상이 실행됨

해결 방법

1. 플래그 변수 추가

  • SaveManager.cs에 static 변수 추가
public static bool IsNewGame = true; // 새 게임 여부 판별

2. TitleUIManager.cs에서 상태 설정

  • 새 게임이면 true, 불러오기면 false로 설정
public void OnClickNewGame()
{
    SaveManager.IsNewGame = true; // ✅ 새 게임 시작
    SaveManager.Instance.ResetData();
    SaveManager.Instance.SaveData(new SaveData());
    sceneFader.FadeToScene("GameScene");
}

public void OnClickLoadGame()
{
    if (SaveManager.Instance.HasSavedData())
    {
        SaveManager.IsNewGame = false; // ✅ 불러오기 시작
        SaveManager.Instance.LoadData();
        sceneFader.FadeToScene("GameScene");
    }
    else
    {
        // 저장 데이터 없음 처리...
    }
}

 

3. CameraIntroController.cs에서 조건 분기

void Start()
{
    if (!SaveManager.IsNewGame)
    {
        // 불러오기는 인트로 건너뜀
        player.SetActive(true);
        uiRoot.SetActive(true);
        mainCamera?.SetActive(false);
        playerCamera?.SetActive(true);
        IsIntroPlaying = false;
        return;
    }

    // 새 게임이면 인트로 재생
    player.SetActive(false);
    uiRoot.SetActive(false);
    playerCamera.SetActive(false);
    IsIntroPlaying = true;

    director.stopped += OnFinished;
    director.Play();
}​

 

결과

시작 방식 인트로 재생플레이어  등장 시점
새 게임 YES 인트로 종료 후
불러오기 NO 씬 진입 직후

 

깨달은 점

  • 인트로 영상은 무조건 재생되면 안 되고, **게임 상태(신규/불러오기)**에 따라 분기 처리를 해줘야 UX가 좋아진다.
  • 간단한 static 변수로도 상태 관리가 가능하며, 장기적으로는 GameStateManager처럼 따로 빼는 것도 고려해볼 수 있다.
  •  

2. Unity 게임 클리어 & 게임 오버 처리, UI 페이드 연출

구현한 기능 요약

1. 게임 클리어 조건 (3일 경과)

  • GameClock에 currentDay, OnDayChanged 이벤트 추가
  • 매 자정마다 currentDay 증가 → 4일차 진입 시 게임 클리어 처리
  • GameManager.CheckGameClearCondition()으로 클리어 조건 감지

2. 게임 클리어 / 게임 오버 분기 처리

  • GameManager.ClearGame()
    → "유배 종료" 로그 출력
    → 클리어용 UI 오브젝트 clearUI.SetActive(true)
  • GameManager.GameOver()
    → "선비가 죽었습니다..." 로그 출력
    → 게임오버 UI gameOverUI.SetActive(true)
  • 테스트용 버튼 TestGameOver() 도입하여 인스펙터에서 수동 테스트 가능

3. 공통 페이드 연출 처리

  • UIFader.cs 작성:
    • CanvasGroup 기반 알파값을 Lerp()로 서서히 변화
    • FadeIn() → 서서히 나타남, FadeOut() → 서서히 사라짐
    • Action onComplete 콜백 추가로, 페이드 완료 후 로직 연결 가능
  • GameManager에서 Fader.FadeIn(() => { clearUI.SetActive(true); }); 식으로 연동

4. UI 중복 활성화 문제 해결

  • ClearGame() 수행 시 gameOverUI.SetActive(false) 선처리
  • GameOver() 수행 시 clearUI.SetActive(false) 처리하여 UI 중복 방지
  • Start() 시점에서 두 UI 모두 SetActive(false) 초기화

5. UI 시간 표시 기능 구현

  • MainUI에서 GameClock의 OnTimeChanged 이벤트 구독
  • TextMeshProUGUI timeTextTMP를 통해 게임 내 현재 시간(HH:MM) 표시
  • TextMeshPro 사용에 맞게 Text → TextMeshProUGUI로 타입 변경

느낀 점

  • CanvasGroup + 코루틴 방식으로 UI 페이드 처리하면 애니메이터 없이도 연출이 부드럽고 관리가 쉬움
  • 게임 종료 조건을 GameClock처럼 중앙 시스템에 위임하면, 다른 시스템과 확장 연결이 수월함
  • UI 연출은 **"타이밍"**이 매우 중요하며, onComplete 콜백 구조를 잘 쓰면 유지보수가 쉬움
  • Inspector에서 GameObject 연결 실수를 주의할 것! gameOverUI, clearUI 같은 필드는 서로 다른 오브젝트로 정확히 연결해야 예상대로 작동함

3. 위치 저장 및 불러오기 기능 구현 

목표

  • GameScene에서 플레이어 위치까지 저장 및 복원 가능한 시스템 구축

1. 저장 시스템 보완

  • 기존에는 PlayerStatus, GameClock 정보만 저장하고 있었음
  • 플레이어 위치도 저장하도록 SaveData에 아래 필드 추가함:
public float playerPosX;
public float playerPosY;
public float playerPosZ;

2. 위치 저장 로직 추가

  • GameManager.SaveAll()에 위치 저장 코드 삽입:
if (playerStatus != null)
{
    playerStatus.WriteSaveStatus(data);
    Vector3 pos = playerStatus.transform.position;
    data.playerPosX = pos.x;
    data.playerPosY = pos.y;
    data.playerPosZ = pos.z;
}
  • 기존 체력, 스태미나, 시간 정보 등과 함께 자동 저장됨

3. 위치 불러오기 구현

  • GameManager.Start()에서 저장된 위치 정보 불러와 플레이어 위치 적용:
if (!SaveManager.IsNewGame)
{
    var data = SaveManager.Instance.CurrentData;
    if (data != null)
    {
        playerStatus.ApplySaveStatus(data);
        clock.ApplySaveClock(data);

        // 위치 복원
        playerStatus.transform.position = new Vector3(
            data.playerPosX,
            data.playerPosY,
            data.playerPosZ
        );
    }
}

4. 문제 해결 과정

  • SaveAll()이 자동 호출되지만 위치 저장이 되지 않던 문제 분석
  • 이유: Start()에서 저장된 위치를 불러오지 않고 초기 위치 유지해서 저장되던 것
  • 해결: IsNewGame을 기준으로 불러오기 시 위치를 직접 복원하도록 수정

 


체크포인트

  • SaveManager.IsNewGame 플래그를 활용하여 불러오기 시 인트로 생략 및 초기화 방지
  • SaveManager.Instance.CurrentData로 현재 세션 저장 데이터에 접근

느낀점

  • 위치까지 저장하려면 단순히 저장만 하는 게 아니라, 불러와서 적용하는 과정도 반드시 짝을 맞춰야 함
  • 구조적으로는 GameManager가 중심이 되어 상태 관리하는 구조가 깔끔하고 유지보수가 쉬움