[ URP 설정 ]
2D에서 빛을 이용해 낮과 밤을 만들고 싶다면 URP 설정이 되어있어야 한다.
URP는 Universal Render Pipeline으로 빌트 인(Built-In) 보다 향상된 그래픽 품질을 제공하는 파이프 라인이다.
- 유니티 버전 2022.3.17f1
빌트 인으로 시작했더라도 패키지 매니저에서 URP를 설치하면 사용할 수 있다. URP를 검색해서 Install을 누르면 자동으로 설치된다.
이후 렌더링 토글에 생성 가능한 URP 파일들이 생기는데, URP Asset (with Universal Renderer)을 누르면 프로젝트 탭에 두 파일이 생성된다.
프로젝트 세팅에서 Graphics의 Scriptable Render Pipeline Settings에 아까 생성되었던 파일 중 _Asset이 붙어있지 않은 파일을 드래그 앤 드롭한다. 그러면 UniversalRenderPipelineGlobalSettings 파일이 생성된다.
같은 렌더링 토글에서 URP 2D Renderer을 클릭하면 New 2D Renderer Data 파일이 생성된다.
New Universal Reneder Pipeline Asset의 인스펙터 창에서 Renderer List에 아까 생성되었던 파일을 드래그 앤 드롭한다.
하이어아키 창에서 끝에 2D가 붙은 Light가 추가된 것을 확인할 수 있다. Global Light 2D를 선택해서 적용시켜 봤다.
왼쪽은 UPR 설정 이후, 오른쪽은 이전에 생성한 것인데, 왼쪽만 빛이 적용되었다. 그 이유는 머터리얼에 Lit이라는 단어가 있어야 영향을 받기 때문이다.
[ 하루 및 다음 날 구현 ]
아침 6시부터 시작해서 시간이 흐르고, 24시가 지나면 다음 날로 넘어간다. 시간에 따라서 빛의 색상과 세기를 조절해서 낮밤을 보여준다.
전체 코드
public class TimeManager : Singleton<TimeManager>
{
private float secondsOfDay = 86400f; // 초 단위 하루 시간
private float timeScale = 60f; // 실제 1초 = 게임 세계 1분(실제 작동: 60, 테스트용: 3600)
[SerializeField] private Color dayLightColor; // 낮 빛 색상
[SerializeField] private Color nightLightColor; // 밤 빛 색상
[SerializeField] private AnimationCurve lightCurve; // 낮 -> 밤 빛 세기 조절해서 자연스럽게 변화
[SerializeField] private Light2D globalLight; // Light2D 인스펙터 창에서 할당
[SerializeField] private Text timeText;
[SerializeField] private Text dayText;
private float time = 21600f; // 현재 시간(시작 시간: 오전 6시)
private int days = 0; // 날짜
private float Hours { get { return time / 3600f; } } // 시 계산
private float Minutes { get { return time % 3600f / 60f; } } // 분 계산
private void Update()
{
time += Time.deltaTime * timeScale; // 시간 흐름
int hour = (int)Hours; // 현재 시간
int minute = (int)Minutes; // 현재 분
timeText.text = hour.ToString("00") + ":" + minute.ToString("00");
dayText.text = days.ToString() + "일째";
float curve = lightCurve.Evaluate(Hours); // 시간의 커브 값
Color lightColor = Color.Lerp(dayLightColor, nightLightColor, curve); // 낮 밤 사이의 비율에 위치한 색
globalLight.color = lightColor; // 색 적용
if (time > secondsOfDay) // 하루 지났는지 확인
StartCoroutine(NextDay());
}
IEnumerator NextDay()
{
days++; // 다음 날
time = 0; // 시간 초기화
yield break;
}
}
코드 설명
private float secondsOfDay = 86400f; // 초 단위 하루 시간
private float timeScale = 60f; // 실제 1초 = 게임 세계 1분(실제 작동: 60, 테스트용: 3600)
[SerializeField] private Color dayLightColor; // 낮 빛 색상
[SerializeField] private Color nightLightColor; // 밤 빛 색상
[SerializeField] private AnimationCurve lightCurve; // 낮 -> 밤 빛 세기 조절해서 자연스럽게 변화
[SerializeField] private Light2D globalLight; // Light2D 인스펙터 창에서 할당
[SerializeField] private Text timeText;
[SerializeField] private Text dayText;
private float time = 21600f; // 현재 시간(시작 시간: 오전 6시)
private int days = 0; // 날짜
24시간을 초로 환산하여 하루 전체 시간을 86400으로 설정한다. timeScale은 실제 1초가 게임 상 1분과 같도록 해준다.
Color은 낮과 밤의 빛 색상을 설정한다. 낮에는 에셋의 원색을 보여주고 싶다면 = Color.white;로 미리 색을 설정해도 된다.
그리고 낮에서 밤으로 변화할 때 색이 뚝뚝 끊겨서 보이지 않고 자연스럽게 보이게 하기 위해서 설정할 커브를 생성한다.
Light2D는 사용할 빛 오브젝트를 할당하면 되고, Text도 마찬가지로 현재 시간과 날짜를 나타낼 텍스트 UI를 할당한다.
time은 게임을 실행했을 때 시작할 시간대이고, days는 첫날부터 시작한다면 0으로 설정한다.
private float Hours { get { return time / 3600f; } } // 시 계산
private float Minutes { get { return time % 3600f / 60f; } } // 분 계산
현재 시간과 분을 계산하는 메서드이다.
시 → 분 → 초 계산을 할 때 *60을 하니까, 반대로 초 → 분 → 시 계산을 할 때는 /60을 해준다.
그래서 시 계산은 /3600을 해서 구할 수 있다.
분 계산은 60분(1시간)을 채우지 못한 시간들만 계산하면 되므로, 3600으로 나눈 나머지에서 분 → 초 계산을 위해 /60을 해서 구할 수 있다.
private void Update()
{
time += Time.deltaTime * timeScale; // 시간 흐름
int hour = (int)Hours; // 현재 시간
int minute = (int)Minutes; // 현재 분
timeText.text = hour.ToString("00") + ":" + minute.ToString("00");
dayText.text = days.ToString() + "일째";
float curve = lightCurve.Evaluate(Hours); // 시간의 커브 값
Color lightColor = Color.Lerp(dayLightColor, nightLightColor, curve); // 낮 밤 사이의 비율에 위치한 색
globalLight.color = lightColor; // 색 적용
if (time > secondsOfDay) // 하루 지났는지 확인
StartCoroutine(NextDay());
}
time에 시간을 더해서 계속 흐르게 하고, timeScale을 곱해줌으로써 현실의 1초와 게임의 1분이 같게 만든다.
hour와 minute은 각각 Hours 메서드와 Minutes 메서드를 호출해서 float 시간 값을 받아오고, int로 자료형을 변환한다.
timeText는 일의 자리 단위에서도 항상 십의 자리까지 보이도록 "00"을 넣어준다.
curve는 반환된 시간에 맞는 빛의 세기를 lightCurve에서 가져온다. 0은 0시이고, 24는 24시이다. 0으로 갈수록 어둡고, 1로 갈수록 밝다.
이 0~1 사이의 값을 lightColor에서 실제 낮의 색과 밤의 색 사이에 적용시켜서 그래프를 따라 빛이 자연스럽게 변하게 한다. 그리고 실제 빛 오브젝트에 적용시켜 주면 게임 씬에서 변하는 모습을 확인할 수 있다.
그리고 현재 시간이 전체 하루 시간을 초과한다면 다음 날로 넘어가는 코루틴을 실행한다.
IEnumerator NextDay()
{
days++; // 다음 날
time = 0; // 시간 초기화
yield break;
}
코루틴이 실행되면 days에 하루를 추가하고, time은 0으로 초기화해서 0시부터 다시 시간이 흐를 수 있게 한다. 이 작업이 반복되면 안 되므로 break로 코루틴을 끝낸다.
하루가 넘어가면 다음 날까지의 텀이 길고, Update 메서드에서 조건을 만족하면 다시 코루틴을 호출하기 때문에 매 프레임마다 확인할 필요가 없어서 yield return null 대신 yield break를 사용한다.
<참고 자료>
- [C#][Unity] 낮과 밤 만들기: https://stickode.tistory.com/509
'Coding > Unity' 카테고리의 다른 글
[내일배움캠프 59일차 TIL] 수면 시스템 구현하기 (0) | 2024.07.09 |
---|---|
[내일배움캠프 50일차 TIL] 오브젝트 풀 객체 초기화 (0) | 2024.06.26 |
[내일배움캠프 48일차 TIL] 오브젝트 풀에서 큐의 동작 원리 (0) | 2024.06.24 |
[내일배움캠프 46일차 TIL] JSON 직렬화로 데이터 저장, 불러오기 (0) | 2024.06.20 |
[내일배움캠프 43일차 TIL] Input System C# 제너레이트 활용 (0) | 2024.06.18 |