[CT] 07. testest (ゲームマル2026夏コンテスト)
[ERROR-CODE-H 개발일지] 6주차 — 공통 UI 프리팹을 실제 플레이 씬에 통합하다
개발 기간: 2026.08.10 ~ 2026.08.14 담당 영역: 공통 UI 통합, Pause 상태창, Restart 및 실제 플레이 씬 적용
지난 5주 동안에는 HUD와 Pause 화면을 각각 만들고, 필요한 기능을 하나씩 추가하는 작업을 진행했다.
Heat와 Core를 화면에 표시하는 것부터 시작해 HP, Skill, 사망 연출, Pause 화면, 볼륨 설정까지 조금씩 기능을 확장해 왔다.
그리고 마지막 6주차에는 지금까지 만든 UI를 실제 게임 전체에서 사용할 수 있는 하나의 인터페이스로 정리하고 통합하는 작업을 진행했다.
이번 주의 주요 목표는 다음과 같았다.
- Heat UI의 형태와 Shader 최종 조정
- Core별 Skill 아이콘 리메이크 및 데이터 연결
- HP UI를 Heat UI와 통일된 디자인으로 수정
- Pause 화면에 HP·Heat·Core·Skill 상태 표시
- UI 전체를 공통
Canvas.prefab으로 정리 - 공통 UI Prefab을 실제 플레이 씬에 일괄 적용
- Pause와 OverClock 사이의 시간 제어 충돌 수정
- 중복 EventSystem 및 입력 잠금 충돌 방지
- Pause 화면의 Quit 버튼을 제거하고 Restart 기능 추가
- 사망 상태에서도 현재 씬을 다시 시작할 수 있도록 연결
이번 주는 새로운 UI 하나를 추가했다기보다는, 지금까지 개별적으로 만들어온 기능을 실제 게임 구조에 맞게 묶고 안정적으로 동작하도록 만드는 통합 단계에 가까웠다.
실제 플레이 씬 통합을 위한 UI 최종 정리
UI를 실제 플레이 씬에 연결하기 전에, 기존 UI 에셋과 데이터 구조를 한 차례 정리했다.
먼저 Core별 Skill 아이콘을 새롭게 제작하고, 각 Core 데이터에서 해당 아이콘과 설명을 직접 가져올 수 있도록 CoreData를 확장했다.
기존에는 Core 자체의 아이콘만 가지고 있었지만, 수정 후에는 Core마다 두 개의 Skill 아이콘과 UI 설명을 별도로 지정할 수 있도록 했다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[SerializeField] private Sprite skill1Icon;
[SerializeField] private Sprite skill2Icon;
[Header("UI Descriptions")]
[SerializeField, TextArea] private string coreHoverDescription;
[SerializeField, TextArea] private string skill1HoverDescription;
[SerializeField, TextArea] private string skill2HoverDescription;
public Sprite Skill1Icon => skill1Icon;
public Sprite Skill2Icon => skill2Icon;
public string CoreHoverDescription => coreHoverDescription;
public string Skill1HoverDescription => skill1HoverDescription;
public string Skill2HoverDescription => skill2HoverDescription;
이렇게 데이터를 CoreData에 모아두면 HUD나 Pause 화면에서 이미지와 설명을 각각 직접 지정할 필요가 없다.
현재 장착 중인 Core의 데이터만 받아오면, 그 Core가 사용할 아이콘과 설명을 함께 가져올 수 있다.
Skill HUD를 담당하는 SkillDrawer에서도 전달받은 CoreData를 기준으로 각 슬롯의 이미지를 갱신하도록 수정했다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public void SetCore(CoreData coreData)
{
if (skillSlots == null || skillSlots.Length == 0)
return;
for (int i = 0; i < skillSlots.Length; i++)
{
SkillSlotUI slot = skillSlots[i];
if (slot == null || slot.skillImage == null)
continue;
slot.skillImage.sprite = GetSkillIcon(coreData, i);
}
}
private Sprite GetSkillIcon(CoreData coreData, int slotIndex)
{
if (coreData == null)
return null;
switch (slotIndex)
{
case 0:
return coreData.Skill1Icon != null
? coreData.Skill1Icon
: coreData.CoreIcon;
case 1:
return coreData.Skill2Icon != null
? coreData.Skill2Icon
: coreData.CoreIcon;
default:
return coreData.CoreIcon;
}
}
Skill 아이콘이 아직 지정되지 않은 Core가 있더라도 빈 이미지가 표시되지 않도록, 해당 Core의 기본 아이콘을 대체 이미지로 사용하도록 했다.
이제 Core가 변경되면 Core HUD뿐 아니라 Skill HUD도 같은 데이터를 기준으로 함께 갱신된다.
[캡처 1 삽입 — Core 1·2·3의 최종 Skill 아이콘]
각 Core 데이터에 전용 Skill 아이콘과 설명을 추가해 HUD와 Pause 화면에서 동일한 정보를 사용할 수 있도록 구성했다.
Pause 화면에 현재 Core와 Skill 정보 표시
4~5주차에 제작한 Pause 화면은 단순히 게임을 멈추는 메뉴에서 조금씩 상태창의 형태로 발전하고 있었다.
6주차에는 우측 영역에 현재 플레이어의 상태를 실제로 표시하도록 구성했다.
Pause 화면에는 다음 정보가 표시된다.
- 현재 HP
- 현재 Heat
- 장착 중인 Core
- 현재 Core의 Skill 1
- 현재 Core의 Skill 2
현재 Core가 변경되면 Pause 화면의 Core와 Skill 이미지 역시 함께 변경되도록 CoreManager의 변경 이벤트와 연결했다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private void HandleCoreChanged(CoreData coreData)
{
UpdateIcons(coreData);
}
private void UpdateIcons(CoreData coreData)
{
coreImage.sprite = coreData != null
? coreData.CoreIcon
: null;
skill1Image.sprite = coreData != null
? (coreData.Skill1Icon != null
? coreData.Skill1Icon
: coreData.CoreIcon)
: null;
skill2Image.sprite = coreData != null
? (coreData.Skill2Icon != null
? coreData.Skill2Icon
: coreData.CoreIcon)
: null;
}
UI가 매 프레임 현재 Core를 직접 확인하는 대신, 실제 Core가 변경된 순간에만 필요한 이미지를 갱신하도록 했다.
Core와 Skill 아이콘에는 Hover 기능도 추가했다.
마우스를 올리면 해당 아이콘이 잠시 확대되고, 별도의 설명 영역에 CoreData에 저장해둔 설명이 표시된다.
Pause 상태에서는 Time.timeScale이 0이기 때문에 일반적인 Time.deltaTime을 사용하면 UI 애니메이션도 함께 멈출 수 있다.
따라서 Hover 애니메이션에서는 Time.unscaledDeltaTime을 사용해 게임 시간이 멈춰 있어도 UI는 계속 움직일 수 있도록 했다.
[캡처 2 삽입 — Pause 화면 전체 상태창]
Pause 화면 우측에 현재 HP·Heat·Core·Skill 정보를 표시해 플레이 도중 캐릭터의 상태를 한눈에 확인할 수 있도록 했다.
[캡처 3 삽입 — Core 및 Skill Hover 전후]
Core 또는 Skill 아이콘에 마우스를 올리면 아이콘이 확대되고, 해당 기능에 대한 설명이 표시된다.
이 부분은 정적인 이미지보다 실제 Hover 움직임과 설명이 나타나는 모습을 GIF로 보여주는 편이 더 적합할 것 같다.
Pause 화면에서도 현재 HP와 Heat를 확인할 수 있도록 연결
Pause 화면을 실제 상태창으로 사용하려면, 게임을 멈춘 순간의 HP와 Heat가 정확하게 표시되어야 했다.
이를 위해 Pause 화면을 활성화할 때 현재 플레이어의 데이터를 다시 읽어오는 RefreshPauseStatusUI()를 구성했다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
private void RefreshPauseStatusUI()
{
if (playerHealth != null && pauseHPDrawer != null)
{
int currentHP = playerHealth.CurrentHP;
int maxHP = playerHealth.MaxHP;
pauseHPDrawer.SetHP(currentHP, maxHP);
bool isLowHP =
maxHP > 0 &&
(float)currentHP / maxHP <= lowHPThreshold;
pauseHPDrawer.SetLowHP(isLowHP);
}
if (heatManager != null && pauseHeatDrawer != null)
{
float currentHeat = heatManager.CurrentHeat;
float maxHeat = heatManager.MaxHeat;
bool isHighHeat =
maxHeat > 0f &&
currentHeat / maxHeat >= highHeatThreshold;
bool isOverHeat =
maxHeat > 0f &&
currentHeat / maxHeat >= overHeatThreshold;
pauseHeatDrawer.SetHeat(currentHeat, isHighHeat);
pauseHeatDrawer.SetOverHeat(isOverHeat);
}
}
현재 수치만 복사하는 것이 아니라 Low HP, High Heat, OverHeat 같은 상태 역시 동일하게 계산했다.
따라서 Pause 화면에서도 평상시 HUD와 같은 기준으로 다음 상태를 확인할 수 있다.
- 일반 HP
- Low HP
- 일반 Heat
- High Heat
- OverHeat
Pause 화면을 여는 순간 현재 값을 새롭게 읽기 때문에, 플레이 도중 변경된 수치가 그대로 Pause 상태창에 반영된다.
[캡처 4 삽입 — 인게임 HUD와 Pause 상태창 비교]
Pause 화면을 여는 시점에 현재 HP와 Heat를 다시 읽어, 인게임 HUD와 동일한 상태를 표시하도록 했다.
[캡처 5 삽입 — Low HP 및 OverHeat 상태]
Pause 상태창에서도 Low HP, High Heat, OverHeat와 같은 위험 상태를 동일하게 구분할 수 있도록 구성했다.
HP UI를 Heat UI와 통일된 방식으로 수정
이번 주에는 HP UI 역시 Heat UI와 비슷한 시각적인 규칙을 사용하도록 수정했다.
기존에는 일반적인 Unity UI Image의 fillAmount를 이용했다면, 이번에는 Heat UI처럼 Material에 현재 HP 비율을 직접 전달해 Shader 내부에서 Fill 영역을 계산하도록 했다.
1
2
3
4
5
6
float normalizedHP = (float)current / max;
if (materialInstance != null)
{
materialInstance.SetFloat("_Fill", normalizedHP);
}
현재 HP를 최대 HP로 나누어 0~1 사이의 값으로 정규화한 뒤, Shader의 _Fill 값으로 전달한다.
예를 들어 최대 HP가 100이고 현재 HP가 30이라면 다음과 같다.
1
normalizedHP = 30 / 100 = 0.3
Shader는 전달받은 0.3을 기준으로 HP 영역의 30%만 표시한다.
이 방식을 사용한 이유는 단순한 직사각형 게이지에 한정되지 않고, 사이버펑크 스타일의 비정형 프레임이나 발광 효과를 그대로 유지하면서 게이지를 표현하기 위해서였다.
또한 HP가 감소하는 경계 부분에 Particle 효과가 계속 따라갈 수 있도록 좌표 계산 역시 보완했다.
Particle System이 Local 좌표를 사용하는지 World 좌표를 사용하는지에 따라 위치를 구분해서 처리하여, Canvas 구조가 변경되더라도 피해 효과가 최대한 HP Fill의 끝부분을 따라가도록 했다.
[캡처 6 삽입 — HP·Heat UI 최종 디자인]
HP UI에도 Shader 기반 Fill 표현을 적용해 Heat·Core HUD와의 시각적 통일성을 높였다.
[캡처 7 삽입 — HP 감소 과정]
현재 HP 비율을 Shader에 전달하고, HP가 감소하는 경계에 Particle 효과를 배치해 피해 상황을 직관적으로 표현했다.
모든 UI를 공통 Canvas Prefab으로 정리
지금까지는 HUD, Pause, Death UI를 조금씩 확장하며 사용해 왔다.
하지만 이를 각 플레이 씬에 개별적으로 배치한다면 이후 UI를 수정할 때마다 모든 씬을 직접 열어 같은 변경을 반복해야 한다.
씬마다 UI 설정이 조금씩 달라질 가능성도 있고, 어느 한 씬에서만 수정 사항이 빠질 수도 있다.
그래서 6주차에는 지금까지 만든 UI 전체를 하나의 공통 Canvas.prefab으로 정리했다.
공통 Canvas Prefab에는 다음 요소들이 포함되었다.
- HP HUD
- Heat HUD
- Core HUD
- Skill HUD
- Skill Reference Manager
- Death UI
- Pause Panel
- Pause 전용 HP·Heat·Core·Skill 상태창
- Resume 및 Restart 버튼
- Master·BGM·SFX Volume Slider
- Pause 배경 Shader
- Pause Manager
- Volume Controller
- Hover Info UI
각 UI를 씬마다 독립적인 오브젝트로 관리하는 대신, 하나의 Prefab 안에서 관리하도록 변경했다.
덕분에 이후 디자인이나 구조를 수정할 때 원본 Prefab을 기준으로 여러 씬에 동일한 변경을 반영할 수 있다.
이번 통합에서 중요했던 것은 단순히 UI를 한곳에 모으는 것만은 아니었다.
HUD, Pause, Death UI가 동일한 Player·Health·Heat·Core 등의 상태 데이터를 공유할 수 있도록 구조를 다시 정리하는 것이 핵심이었다.
[캡처 8 삽입 — Canvas.prefab 전체 Hierarchy]
개별적으로 제작했던 HUD, Pause, Death UI를 하나의 공통 Canvas Prefab으로 정리해 전체 플레이 씬에서 동일한 구조를 사용하도록 했다.
[캡처 9 삽입 — 실제 플레이 씬의 Prefab Instance]
실제 플레이 씬에서는 공통 Canvas Prefab을 사용하므로, 원본 Prefab의 수정 사항을 여러 씬에 공통으로 반영할 수 있다.
공통 UI를 실제 플레이 씬에 적용
정리한 Canvas.prefab을 실제 플레이에서 사용되는 씬에 연결했다.
이번 작업에서 UI가 적용된 주요 씬은 다음과 같다.
1HRoom2CoreRoom3street4top15top26top37top4
이전까지는 테스트 씬에서 HUD와 Pause 기능을 확인하는 경우가 많았다.
이번 주부터는 게임의 시작 구간부터 후반부 옥상 구간까지 동일한 UI를 사용할 수 있도록 실제 플레이 흐름에 적용했다.
씬마다 Canvas를 복사하는 것이 아니라 동일한 Prefab을 참조하기 때문에, 이후 UI의 위치나 디자인을 변경하더라도 공통 Prefab을 기준으로 수정할 수 있다.
물론 단순히 Prefab을 씬에 넣는 것만으로 끝나는 작업은 아니었다.
각 씬마다 Player, Camera, Health, Heat Manager 등의 위치가 다를 수 있기 때문에 다음과 같은 참조를 함께 확인해야 했다.
- 현재 씬의 Player와 HP UI 연결
HeatManager와 Heat UI 연결CoreManager와 Core·Skill UI 연결- Main Camera와 Canvas Render Camera 연결
PauseManager와PlayerController연결- Pause Panel 버튼 이벤트 연결
- 씬별 EventSystem 중복 여부
테스트 씬에서 정상적으로 동작하던 기능이 실제 씬에서도 그대로 동작하도록 만드는 것이 이번 통합 작업의 핵심이었다.
[캡처 10 삽입 — 대표 플레이 씬 3종 UI 비교]
공통 Canvas Prefab을 실내, 거리, 옥상 등 서로 다른 실제 플레이 씬에 적용해 모든 구간에서 동일한 HUD를 사용할 수 있도록 했다.
대표적으로 1HRoom, 3street, 7top4 정도를 비교하면 실내·야외·후반 구간이라는 차이가 잘 보여서 적합할 것 같다.
Pause와 OverClock의 시간 제어 충돌 수정
Pause 기능은 Time.timeScale = 0으로 설정해 게임 시간을 멈추는 방식으로 구현했다.
그런데 프로젝트에는 OverClock처럼 Time.timeScale과 Time.fixedDeltaTime을 변경하는 또 다른 기능도 존재했다.
이 상태에서 Pause를 해제할 때 항상 다음과 같이 처리한다면 문제가 발생할 수 있다.
1
Time.timeScale = 1f;
Pause 직전에 OverClock 등의 영향으로 시간 배율이 변경되어 있었다면, Resume하는 순간 해당 상태가 사라져버리기 때문이다.
이를 해결하기 위해 Pause 직전의 시간 상태를 저장하도록 구조를 변경했다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
private void Pause()
{
if (isPaused)
return;
isPaused = true;
timeScaleBeforePause = Time.timeScale;
fixedDeltaTimeBeforePause = Time.fixedDeltaTime;
hasTimeStateSnapshot = true;
heatStateController?.SetPauseMenuStatePaused(true);
Time.timeScale = 0f;
playerController.SetInputEnabled(false);
pauseInputLockApplied = true;
DisableDuplicatePausePanelEventSystems();
pausePanel.SetActive(true);
RefreshPauseStatusUI();
Cursor.visible = true;
}
Pause에 진입하기 직전의 Time.timeScale과 Time.fixedDeltaTime을 저장한다.
Resume할 때는 기본값을 강제로 넣는 대신, 저장해둔 값으로 복원한다.
1
2
3
4
5
6
7
8
9
10
private void RestoreTimeStateBeforePause()
{
if (!hasTimeStateSnapshot)
return;
Time.timeScale = timeScaleBeforePause;
Time.fixedDeltaTime = fixedDeltaTimeBeforePause;
hasTimeStateSnapshot = false;
}
이제 일반 상태에서 Pause했다면 일반 속도로 돌아가고, OverClock처럼 다른 시스템에서 시간 배율을 변경한 상태였다면 Resume 이후에도 해당 상태로 돌아갈 수 있다.
Pause가 적용한 입력 잠금 역시 다른 시스템의 입력 제한과 구분할 수 있도록 pauseInputLockApplied를 별도로 기록했다.
이를 통해 Pause가 직접 변경한 상태만 Pause가 복원하도록 구조를 조정했다.
이번 수정은 Pause를 독립적인 하나의 기능으로 보는 것이 아니라, 기존의 OverClock과 Heat, Player Input 시스템과 함께 동작하도록 만드는 과정이었다.
[캡처 11 삽입 — OverClock 중 Pause 테스트]
Pause 직전의
timeScale과fixedDeltaTime을 저장해, Resume 이후 기존 시간 상태로 복구되도록 수정했다.
Prefab 통합 과정에서 EventSystem 충돌 대응
공통 Canvas Prefab을 여러 씬에 적용하면서 또 하나 확인해야 했던 부분이 EventSystem이었다.
일부 씬에는 기존 EventSystem이 이미 존재할 수 있고, Prefab 내부에도 EventSystem이 포함되어 있다면 하나의 씬 안에 두 개 이상의 EventSystem이 활성화될 수 있다.
Unity에서 EventSystem이 중복되면 버튼 선택이나 마우스 입력이 두 번 처리되는 등 예상하지 못한 문제가 발생할 수 있다.
이를 줄이기 위해 Pause Panel 내부의 EventSystem을 확인하고, 현재 사용하는 EventSystem을 제외한 중복 인스턴스를 비활성화하도록 처리했다.
1
2
3
4
5
6
7
8
9
10
11
12
13
EventSystem[] pausePanelEventSystems =
pausePanel.GetComponentsInChildren<EventSystem>(true);
foreach (EventSystem eventSystem in pausePanelEventSystems)
{
if (eventSystem == null ||
eventSystem == EventSystem.current)
{
continue;
}
eventSystem.enabled = false;
}
공통 Prefab을 여러 씬에 적용하면서 생길 수 있는 구조적인 충돌을 코드에서도 한 번 더 방어한 것이다.
통합 과정에서는 폰트 에셋도 함께 정리했다.
개인 작업 폴더나 테스트 폴더에 동일한 폰트 파일이 여러 개 존재하면 .meta 파일이나 TextMesh Pro Font Asset 변경 사항이 Merge 과정에서 충돌할 가능성이 있다.
따라서 실제 UI에서 사용하는 폰트를 공통 TextMesh Pro/Fonts 경로에서 관리하도록 정리했다.
[캡처 12 삽입 — 중복 EventSystem 구조 또는 폰트 정리 결과]
공통 UI Prefab을 여러 씬에 적용하면서 EventSystem과 폰트 리소스가 중복되지 않도록 구조를 정리했다.
Quit 버튼 대신 Restart 기능 추가
초기 Pause 화면에서는 Resume, Setting, Quit 등의 메뉴를 배치하는 것을 생각했다.
하지만 실제 공모전 빌드의 플레이 흐름을 고려했을 때, 게임을 완전히 종료하는 기능보다는 현재 구간을 다시 시작하는 기능이 더 유용하다고 판단했다.
따라서 Pause 화면의 Quit 항목을 제거하고 Restart 버튼을 추가했다.
Restart 기능은 현재 활성화되어 있는 씬의 Build Index를 가져와 같은 씬을 다시 불러오는 방식으로 구현했다.
1
2
3
4
5
6
7
8
9
10
11
12
13
public void RestartScene()
{
Time.timeScale = 1f;
Time.fixedDeltaTime = fixedDeltaTimeBeforePause;
isPaused = false;
hasTimeStateSnapshot = false;
pauseInputLockApplied = false;
SceneManager.LoadScene(
SceneManager.GetActiveScene().buildIndex
);
}
Pause 상태에서는 Time.timeScale이 0이므로, 씬을 다시 불러오기 전에 시간 상태와 Pause 상태를 먼저 초기화한다.
그다음 현재 활성화된 씬을 다시 로드한다.
씬 이름을 문자열로 직접 지정하는 대신 현재 씬의 Build Index를 사용했기 때문에, 각 플레이 씬마다 별도의 Restart 로직을 만들 필요 없이 같은 기능을 재사용할 수 있다.
Restart 버튼은 Pause 화면뿐 아니라 Death UI에도 연결했다.
이제 플레이어가 어느 구간에서 사망하더라도 별도의 씬 이름을 지정하지 않고 현재 플레이 중인 구간을 그대로 다시 시작할 수 있다.
[캡처 13 삽입 — Quit 제거 및 Restart 버튼]
공모전 빌드의 실제 플레이 흐름에 맞춰 Quit을 제거하고 현재 씬을 다시 불러오는 Restart 버튼을 추가했다.
[캡처 14 삽입 — 사망 상태 Restart]
Restart 기능을 사망 화면에도 연결해, 플레이어가 사망한 위치의 현재 플레이 구간을 바로 다시 시작할 수 있도록 했다.
Pause → Restart와 Death → Restart 과정은 짧은 GIF로 만들어도 좋을 것 같다.
6주차 Git 작업 흐름
이번 주 작업은 다음과 같은 순서로 진행되었다.
8월 10일 — Volume 컨트롤 및 Heat UI 개편
- Master·BGM·SFX Volume 컨트롤 정리
- Heat UI 위치와 형태 조정
- 변경된 UI 구조에 맞춰 Heat Shader 수정
8월 12일 — Skill 아이콘 및 텍스트 문제 수정
- Core별 Skill 아이콘 리메이크
CoreData에 Skill 아이콘 및 설명 데이터 추가- HUD와 Pause 화면에서 Core별 Skill 아이콘 표시
- 한글 텍스트 깨짐 문제 대응을 위한 폰트 추가 및 정리
- Pause 화면 Hover 설명 기능 추가
8월 12일 — Pause 기능 및 HP UI 완성
- Pause 우측 상태창 구성
- Pause 화면에 HP·Heat·Core·Skill 정보 표시
- HP UI를 Heat UI와 통일된 Shader 기반 구조로 수정
- 공통
Canvas.prefab제작 - Resume 및 Volume UI 연결
8월 12일 — Merge 충돌 정리
- 중복 폰트 에셋 정리
- 폰트 및 UI 참조 구조 조정
- 개인 작업 폴더와 공통 폴더 사이의 중복 파일 정리
8월 13일 — 실제 플레이 씬 UI 통합
- 공통 Canvas Prefab을 실제 플레이 씬에 연결
1HRoom부터7top4까지 총 7개 플레이 씬에 UI 적용- Pause와 OverClock의 시간 상태 충돌 수정
- Pause 입력 잠금 및 EventSystem 중복 문제 대응
8월 13일 — Restart 기능 추가
- Pause 화면에서 Quit 제거
- Restart 버튼 추가
- 현재 활성화된 씬을 다시 불러오는 기능 구현
- Death UI에서도 Restart를 사용할 수 있도록 연결
[캡처 15 삽입 — 6주차 GitHub 커밋 기록]
개별 UI 기능을 마무리한 뒤 충돌을 정리하고, 공통 Prefab을 실제 플레이 씬에 통합하는 순서로 작업을 진행했다.
6주차 결과
이번 주에는 지금까지 제작한 UI를 실제 게임 전체에서 사용할 수 있는 형태로 통합했다.
최종적으로 완료한 작업은 다음과 같다.
- Heat UI 형태 및 Shader 수정
- HP UI를 Heat UI와 통일된 디자인으로 개선
- Core별 Skill 아이콘 및 설명 데이터 추가
- 현재 Core에 맞춰 HUD와 Pause Skill 아이콘 갱신
- Pause 화면에 HP·Heat·Core·Skill 상태 표시
- Pause 화면의 Core·Skill Hover 및 설명 기능 구현
- HUD·Pause·Death UI를 공통 Canvas Prefab으로 정리
- 공통 Canvas Prefab을 7개의 실제 플레이 씬에 적용
- Pause와 OverClock 사이의 시간 제어 충돌 수정
- Pause 입력 잠금과 중복 EventSystem 처리
- 폰트 에셋 및 UI 참조 구조 정리
- Quit 제거 및 Restart 기능 추가
- Pause 및 사망 상태에서 현재 씬 Restart 기능 연결
이번 작업을 통해 UI를 단순히 화면 위에 표시하는 기능에서 끝내지 않고, 여러 플레이 씬에서 공통으로 사용할 수 있는 실제 게임 인터페이스 구조로 정리할 수 있었다.
특히 Prefab을 중심으로 UI를 관리하도록 바꾸면서 이후 디자인이나 기능을 수정할 때 모든 씬을 개별적으로 수정할 필요가 크게 줄어들었다.
또한 Pause와 OverClock처럼 서로 다른 시스템이 동시에 Time.timeScale 같은 전역 상태를 변경할 수 있는 상황에서는, 각 기능이 단순히 값을 덮어쓰는 방식으로는 안정적으로 동작하기 어렵다는 점도 확인했다.
결국 중요한 것은 기존 상태를 저장하고, 자신이 변경한 부분만 다시 복원하는 구조였다.
6주차를 마치며
이번 주에 가장 많은 시간이 필요했던 것은 새로운 UI 에셋을 만드는 작업이 아니었다.
이미 만들어둔 UI를 실제 게임의 구조 안에 넣고, 서로 다른 씬과 시스템 속에서도 같은 방식으로 동작하도록 정리하는 과정이었다.
테스트 씬에서는 멀쩡하게 동작하던 UI도 실제 플레이 씬에 넣자 새로운 문제들이 하나씩 나타났다.
- 씬마다 Player와 Manager의 위치가 다른 문제
- Canvas의 Render Camera 연결
- Prefab 내부 Reference와 씬별 Reference의 차이
- EventSystem 중복
- 폰트 에셋 및
.meta파일 충돌 - Pause와 OverClock이 동시에 시간 배율을 변경하는 문제
- Pause 입력 잠금과 다른 입력 제한 기능의 충돌
- 사망 상태에서 Restart 기능을 호출할 수 있는지 여부
결국 공통 Prefab을 만든다는 것은 단순히 오브젝트를 한 번만 만들어 복사하지 않는다는 의미는 아니었다.
Prefab이 실제 유지보수에 도움이 되려면, 데이터 참조와 이벤트 연결, 각 씬에서 달라지는 Override의 범위까지 함께 설계해야 했다.
Pause 기능도 마찬가지였다.
처음에는 단순히 Time.timeScale을 0과 1 사이에서 바꾸면 충분하다고 생각했지만, OverClock처럼 같은 전역 상태를 사용하는 기능이 생기면서 그렇게 단순한 문제는 아니라는 것을 알게 되었다.
Pause 이전의 상태를 저장하고 다시 복구하는 방식으로 수정하면서, 여러 시스템이 하나의 전역 상태를 공유할 때에는 각 시스템이 무엇을 바꾸었고 어디까지 되돌려야 하는지를 분명하게 구분해야 한다는 점을 배웠다.
그리고 이번 6주차를 마지막으로, 1주차부터 만들어온 UI 작업도 하나의 흐름으로 이어졌다.
1주차에는 Heat와 Core라는 두 개의 값을 화면에 표시하는 것에서 시작했다.
2주차에는 HP와 피해 피드백을 추가했고, 3주차에는 Shader와 Skill, 사망 연출을 통해 『ERROR-CODE-H』만의 분위기를 입혔다. 4주차에는 Pause 화면과 동적인 인터페이스를 만들었고, 5주차에는 Resume와 Volume 등 실제 메뉴 기능을 추가했다.
그리고 마지막 6주차에는 그동안 만들어 온 모든 요소를 하나의 Canvas.prefab으로 묶어 실제 플레이 씬 전체에 적용했다.
처음에는 테스트 씬 한쪽에 놓여 있던 작은 Heat 게이지 하나에 불과했다.
그 작은 UI가 6주 동안 HP와 Core, Skill, Pause, Death UI로 확장되고, Shader와 데이터, 다른 팀원이 만든 시스템들과 연결되면서 마지막에는 게임 전체에서 사용하는 하나의 인터페이스가 되었다.
이번 프로젝트를 통해 UI는 단순히 정보를 예쁘게 보여주는 요소가 아니라는 것을 배울 수 있었다.
플레이어의 입력, 게임의 시간, 다른 시스템의 상태, 데이터 구조, 씬 구성까지 모두 연결되어야 비로소 하나의 UI가 실제 게임 안에서 제대로 동작한다.
그리고 6주 동안 이어진 『ERROR-CODE-H』의 UI 작업은, 그렇게 실제 게임 속 하나의 인터페이스로 마무리되었다.