I maked a simple day/night cycle for my game, it work perfectly, rotating my directional light around X axis using this code:
using UnityEngine;
using System.Collections;
//0.125 degrees rotation corresponds to 1 minute. A global rotation of 90 is equivalent to midday, 270 is equivalent to midnight. 0 degrees is the dawn, 180 is the sunset.
public class DayLightCycle : MonoBehaviour
{
#region Components
public GameObject SunLight;
public Transform SunTransform;
public Light LightComponent;
#endregion
#region H/M
//Variabili per l'orologio globale
public int Hour;
public int Minutes;
#endregion
#region Rotation constraint
public Vector3 MidnightStartDay = new Vector3(0, 0, 0);
public Vector3 MidnightEndDay = new Vector3(180, 0, 0);
public const float GradForMinute = 0.125f;
#endregion
private Vector3 RotationComponent;
public float TimeConstraint = 1;
void Start () {
LightComponent = SunLight.GetComponent<Light>();
SunTransform = SunLight.GetComponent<Transform>();
}
#region Rotation
void Update()
{
//percentual interpolation for lerping Day and night.
float PI = 0;
if (PI <= 0)
{
PI += (Time.deltaTime * TimeConstraint)/10;
RotationComponent = Vector3.Lerp(MidnightStartDay, MidnightEndDay, PI);
}
SunTransform.Rotate(RotationComponent);
//Here is the problem, the time displayed isn't exact.
Hour = ((int)SunTransform.eulerAngles.x) / 15;
Debug.Log(SunTransform.eulerAngles.x);
}
#endregion
}
At dawn it says 2 Hour, at the early night it says 15, then it jumps to 23 and go 22, 21, 20, 7, 6…
From my understanding a full day cycle is 360°, so I would expect that MidnightEndDay is something like Vector3(360, 0, 0).
A side note: Although I can’t see where you use it GradForMinute should be 0.25.
Even with 360 the things not change a lot. it stabilize the hour cycle, but they are still wrong… (and maybe i foudn the problem, but first:
Just checked with my calculator, and yeah, you are right!
My theory now: in the script im assuming: 0 grad rotation equal dawn, but also 0 hours. Here comes the error, when is dawn isnt 0, but 6-7 AM depending on the current season. I can simply add a base value to be added to the hour calculation, like 6, but this works apparently, because when is 24 it returns 30.
Still looking for a solution…
I tried changing the script in this way:
using UnityEngine;
using System.Collections;
public class DayLightCycle : MonoBehaviour
{
#region Components
public GameObject SunLight;
public Transform SunTransform;
public Light LightComponent;
#endregion
#region H/M
public int Hour;
public int Minutes;
#endregion
#region Rotation constraint
public Vector3 MidnightStartDay = new Vector3(0, 0, 0);
public Vector3 MidnightEndDay = new Vector3(360, 0, 0);
public const float GradForMinute = 0.25f;
#endregion
private Vector3 RotationComponent;
public float TimeConstraint = 1;
void Start () {
LightComponent = SunLight.GetComponent<Light>();
SunTransform = SunLight.GetComponent<Transform>();
}
#region Rotation
void Update()
{
float PI = 0;
if (PI <= 0)
{
PI += (Time.deltaTime * TimeConstraint)/10;
RotationComponent = Vector3.Lerp(MidnightStartDay, MidnightEndDay, PI);
}
SunTransform.Rotate(RotationComponent);
Hour = ((int)SunTransform.eulerAngles.x) / 15 + 6;
Debug.Log(SunTransform.eulerAngles.x);
}
#endregion
}
well, when is night it go to the 30 and return to 6… Im investigating this issue with breakpoints…
I’m new to Unity and C# ; but I would think the easiest route would be a terrain with 2 spheres(children) 1.TheSun which could also be linked(parented) to the 2nd larger sphere (sundial) then you’d need only to manipulated the dial on its X axis ; Again this is simple maybe even crude but it is the bare bones of my recent project-
PS I’m not much of a coder (Hands On) -
The your solution isn’t good, the my problem isn’t related to rotating the sun, i already have it rotatin without depend on frame rate. The my problem is calculating the time using sun rotation. Your solution is: heavvy and complicated, and if you not have a terrain or a gameobject to attach the light? You have a lot to learn in optimization
Ok, so… Now it works, until it arrives to 12:00, the he goes reverse, to 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 and ther returns to work good… Maybe is a gimbal lock issue? (im using euler angles and not quaternions, because i not understand quaternions math…
What you’re doing sounds complicated. Why don’t you use 2 Timers? 1 Timer for day, and when it expires, it starts the Timer for night, which starts the Timer for day upon expiring.
Isn’t complicated, is strange, when the rotation is more of 90 it goes reverse, im thinking this have something related to gimbal lock, use of 2 timers will be more complex, the problem isn’t the algoritmh for calculating the time, is why it not works…
So the result is more than 680 logs in console after 1 day cycle (and this is strange, the code should output only 2 messages for hour… )
I report here only 2 strings per hours:
0, 0.25
1, 15.28277
2, 30.4822
3, 45.31
4, 61.58843
5, 75.99202
6, 90
5, 86.3589
An then it go back to 0. So i think is someything related to gimbal lock and the way unity solve this converting from euler angles to quaternions.
It’s unclear to me what you mean; you got an error ?
RotationComponent is a Vector3 calculated in line 39 (post 3#). You use it to rotate the suntransform. Instead of grabbing the transform.eulerangles.x later on, you can simply use the Vector3.x component, being RotationComponent.x
For some reasons (like a variable name that seem like a function from the unity namespace. Or a the fact i
was really tired that day) i readed it like a function and i searched it in the scripting api documentation.
Obiusly i found nothing.
When im at home ill test and give you the result.
(Orthographic errors = written from smartphone)