시간에 따라 레벨의 Directional Light를 제어하는 SunManager를 별도로 구현했다.
처음엔 이것도 Subsystem으로 만들까 고민했지만,
결국 레벨에 배치된 Directional Light 하나만 관리하면 되었기 때문에
그냥 액터 기반 SunManager로 구현했다.
레벨에 배치된 빛을 참조해서 회전만 제어하는 구조다.

단순히 Pitch만 돌리면:
그래서 실제 지구처럼:
에 따라 태양의 일출 지점과 경로가 달라지도록 공식을 유도했다.
게임 시작 전 결정되는 값은:
SunTiltAngle (자전축)뿐이다.
즉, 밸런싱 과정에서 낮/밤의 비율이 바뀌어도, 자동으로 자연스러운 태양 궤적이 다시 계산되도록 만들고 싶었다.
그래서:
를 런타임에 계산하도록 구현했다.

삼각함수를 이용해 낮/밤 비율에 맞는 일출·일몰 지점의 각도(w)를 유도했다.

void ASunManager::SetSunInitRotator_Implementation(int32 InInitWaveTime)
{
RotationPerMSec = 360 * 0.1f / TotalWaveTime;
float SafeAlpha = FMath::Clamp(NightAngle, 0.001f, 179.9f);
float SafeTheta = FMath::Clamp(SunTiltAngle, 0.001f, 179.f);
float AlphaRad = FMath::DegreesToRadians(SafeAlpha);
float ThetaRad = FMath::DegreesToRadians(SafeTheta);
float TanPart = FMath::Tan(AlphaRad / 2.0f);
float SinPart = FMath::Sin(ThetaRad);
float W_Rad = FMath::Atan(TanPart * SinPart);
float W_Deg = FMath::RadiansToDegrees(W_Rad);
SunRise = FRotator(0, -(180 - W_Deg), 0); // 언리얼에서의 동서남북을 맞추기 위한 각도 수정
Sun->SetActorRotation(SunRise);
}
태양은 단순 Rotator가 아니라 Quaternion 기반으로 회전시켰다.
이유는:
이었기 때문이다.
그래서:
회전축 = 자전축
회전각 = (360 / 하루시간) * DeltaTime
형태로 Timer로 회전시켰다.
void ASunManager::RotateSun()
{
FRotator SunRotator = Sun->GetActorRotation();
FRotator BaseRotator(SunRotator);
FQuat QBase = BaseRotator.Quaternion();
FQuat QDelta = FQuat(CustomAxis, FMath::DegreesToRadians(RotationPerMSec));
FQuat QResult = QDelta * QBase;
Sun->SetActorRotation(QResult);
}
시간은 GameState에서 복제되고 있으며,
클라이언트는 OnRep 시 현재 태양 위치를 다시 보정한다.
그리고 평소에는 0.1초 단위로 로컬에서 계속 회전시켜 자연스럽게 움직이게 했다.
즉:
하는 구조다.
최종적으로:
을 만들 수 있었다.
