게임 개발에서 시간의 흐름은 플레이어의 몰입감을 높이는 중요한 요소입니다.
오늘은 Unity 3D에서 낮과 밤이 자연스럽게 전환되는 시스템을 구현하는 방법을 알아보겠습니다.
- 시간이 흐르면서 낮과 밤이 자연스럽게 전환되는 효과
- 횃불과 같이 어두울 때 주변을 밝힐 수 있도록 하는 물체 구현

- Directional Light는 Unity에서 태양빛이나 달빛 같은, 장면 전체에 걸쳐 균일하게 빛을 비추는 광원 역할을 하는 Light Component입니다.
이는 게임 씬에서 현실적인 조명 환경을 구현할 때 가장 기본적이면서도 중요한 요소입니다.
- 빛의 위치보다 방향이 중요한 조명입니다.
- 씬 전체에 동일한 세기를 가진 평행광을 제공하며, 특정 거리나 영역에 제한되지 않습니다.
- 그림자를 생성할 수 있어, 게임 환경에서 빛의 현실감을 더할 수 있습니다.
- Realtime, Baked, Mixed 모드를 통해 다양한 조명 효과를 구현할 수 있습니다.

- Skybox는 Unity에서 게임 씬의 하늘과 먼 배경을 표현하기 위해 사용하는 환경 맵 입니다.
단순히 하늘을 보여주는 역할만 하는 것이 아니라, 씬의 분위기를 조성하고 몰입감을 높이는 데 중요한 요소입니다.
특징
- 플레이어가 어느 방향을 보더라도 하늘과 먼 배경이 자연스럽게 보입니다.
- 스카이박스는 실제로는 아주 멀리 있는 텍스처처럼 보이지만, 실제로는 씬에 별도의 3D 오브젝트를 배치하지 않고도 이러한 효과를 제공하므로 성능에 영향을 덜 미칩니다.
- Lighting > Environment Lighting에서 스카이박스가 씬의 기본적인 조명과 반사를 설정하는 데 사용됩니다.
종류
- 6-Sided 스카이박스
- 하늘을 구성하는 텍스처를 6개의 면으로 나누어 사용하는 방식입니다
- Procedural 스카이박스
- 시간대(낮, 밤, 저녁 등)와 날씨에 따라 스카이박스를 변경하는 데 유용합니다

- 저의 경우에는 FastSky - Procedural Sky and Clouds URP 에셋에 존재하는
Procedural Sky를 가져와서 사용했습니다.- 사용하고자 하는 Scene에 해당 파일을 가지고 온 뒤
Window -> Rendering -> Environment의 부분을 따라하시면 됩니다.- 그리고 Fast_Skt_Sun_Color의 클래스 내용은 태양의 방향에 따른 밝기와 색상을 조절하는 클래스입니다.
public class DayNightCycle : MonoBehaviour
{
[Header("시간 설정")]
public float dayLengthInSeconds = 120f; // 하루 시간
[Range(0f, 1f)] public float initialTimeOfDay = 0.25f; // 오전 6시부터 시작 (0 = 자정, 0.25 = 오전 6시)
private float timeOfDay; // 현재 시간 비율 (0 ~ 1)
public float timeScale = 1f; // 시간 배속
[Header("Directional Light 설정")]
public Light directionalLight;
public float minSunAngle = -90f; // 자정에서의 각도
public float maxSunAngle = 270f; // 태양이 완전히 지는 각도
// 테스트용
public Text Text_Time;
public int hours; // 현재 시
public int minutes; // 현재 분
public int aliveDay; // 살아있는 시간
void Start()
{
// 초기 시간 설정 (오전 6시부터 시작)
timeOfDay = initialTimeOfDay;
}
void Update()
{
// 시간 진행
timeOfDay += (Time.deltaTime / dayLengthInSeconds) * timeScale;
// 하루가 지나면 다시 0으로 순환
if (timeOfDay > 1f)
{
timeOfDay -= 1f;
aliveDay++;
}
UpdateTimeDisplay();
UpdateSunPosition();
}
void UpdateSunPosition()
{
if (directionalLight != null)
{
// 시간에 따른 태양 각도 계산
float sunRotationX = Mathf.Lerp(minSunAngle, maxSunAngle, timeOfDay);
directionalLight.transform.rotation = Quaternion.Euler(new Vector3(sunRotationX, 90f, 0f));
}
}
void UpdateTimeDisplay()
{
int hours = Mathf.FloorToInt(timeOfDay * 24f);
int minutes = Mathf.FloorToInt((timeOfDay * 1440f) % 60);
Text_Time.text = $"{aliveDay}일 {hours:D2}:{minutes:D2}";
}
}
- 하루를 0 ~ 1의 범위로 표현하였습니다.
- 0 (자정), 0.25 (오전 6시), 0.5 (정오), 0.75 (오후 6시) 1 (자정)
- Light의 Rotation X의 값을 바꾸면서 태양의 각도를 Lerp하게 움직이게 하여 자연스럽게 해가 지고 뜨는것 처럼 구현하였습니다.

- 횃불의 경우에는 자신의 주위로 빛을 비쳐줘야하기 때문에 광원 타입을
Point 타입으로 설정합니다.- 플레이어 하위에 Light -> Point Light를 생성해줍니다.

- Color 같은 경우에는 횃불이기 때문에 Color값을 주황 - 빨강 사이에 Color로 설정합니다.
- Range의 경우 빛의 범위 입니다. 적당히 설정해줍시다.
- Intensity의 경우에는 빛의 밝기 입니다. 이것도 적당히 설정해줍시다.

- 횃불이라긴 보다는 랜턴의 느낌?이 강하여 횃불 처럼 빛이 흔들리는 효과가 필요해보입니다.
public class TorchFlicker : MonoBehaviour
{
public Light torchLight;
public float minIntensity = 1f;
public float maxIntensity = 5f;
public float flickerSpeed = 5f;
private float noiseTime;
void Update()
{
if (torchLight != null)
{
noiseTime += flickerSpeed * Time.deltaTime;
float noiseValue = Mathf.PerlinNoise(noiseTime, 0f);
// 값에 따라 밝기 변경
torchLight.intensity = Mathf.Lerp(minIntensity, maxIntensity, noiseValue);
}
}
}
- Mathf.PerlinNoise()를 사용하여 연속적이고 부드러운 랜덤값을 사용하여 반환하도록 합니다.
- minIntensity의 값과 maxIntensity값의 차이가 크면 흔들리는 느낌이 강화됩니다.
- flickerSpeed 변화의 속도입니다.

- 아직 횃불이라는 아이템이 없어 오른손에서만 빛이 나옵니다. 그래도 빛의 범위가 일정한 것 보다는 자연스럽게 나옵니다.

- 해의 각도를 움직이면서 자연스럽게 그림자의 위치도 바뀌며
UI도 시간 흐름을 잘 표현하고 있으며 시간 흐름에 따른 낮,밤도 잘 구현된 것 같습니다.
시간 흐름 클래스에서 옵저버 패턴을 사용하여 UI,캐릭터,몬스터의 시간에 따른 행동을 명령하는 것도 괜찮아 보입니다. 밤이되면 몬스터의 경우 잠을 잔다던지 더 공격적으로 변하는 등..
개인 프로젝트를 구현하면서 유용하게 쓰일 듯 합니다.
스카이박스는 6-Sided 밖에 몰랐는데 Procedural 스카이 박스가 더 좋은 것 같다고 느껴집니다..
- 제가 조사한 내용이 맞지 않거나 잘못 된 경우에 댓글로 잘못된 점 지적해주시면 감사합니다 ! (´._.`)