Unity - Trying to Calculate In-Game Time Relative to Sun/Moon Cycle
Hello,
I wrote a simple script for controlling a Sun/Moon object in my scene and that seems to be working although it's very primitive and has no shader to transition smoothly between skyboxes. That's irrelevant though.
I am now wracking my brain trying to figure out how to capture the current time of day per the game's circadian rhythm. That is I need to be able to launch other scripts in this off of the time of day relative to the in game time.
I have gotten it sorta working except I think an actual game second should be way faster than a real life second because we only have 120 seconds in a game day per my little experiment.
Here is my crappy code, any help is appreciated.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
public class DayNightCycle : MonoBehaviour
{
public static DayNightCycle instance;
public Light sun, moon;
public float secondsInFullDay = 3600f;
[Range(0, 1)]
public float currentTimeOfDay = 0f;
[HideInInspector]
public float timeMultiplier = 1f;
float sunInitialIntensity;
public Material skyboxDay, skyBoxNight;
public float gameTime;
public float currentSecond;
public int minutes, hours, days;
public int currentMinute, currentHour, currentDay;
public float speedOfASecond;
public float previousTime;
//private float secondsOfARealDay = 24 * 60 * 60;
private void Awake()
{
instance = this;
}
// Start is called before the first frame update
void Start()
{
sunInitialIntensity = sun.intensity;
currentSecond = 0f;
}
// Update is called once per frame
void Update()
{
UpdateSun();
currentTimeOfDay += (Time.deltaTime / secondsInFullDay) * timeMultiplier;
if (currentTimeOfDay >= 1)
{
currentTimeOfDay = 0;
}
// seconds / total seconds = percentage
// percentage * seconds = total seconds
// seconds = total seconds * percentage
currentSecond = (secondsInFullDay * currentTimeOfDay);
if (currentSecond >= 60)
currentMinute = (int)(currentSecond % 60);
if (currentMinute >= 60)
currentHour = (int)(currentMinute % 60);
if (currentHour >= 24)
IncrementDays();
previousTime = (int)gameTime;
}
void UpdateSun()
{
sun.transform.localRotation = Quaternion.Euler((currentTimeOfDay * 360f) - 90, 170, 0);
moon.transform.localRotation = Quaternion.Euler((currentTimeOfDay * 360f) - 90, 170, 0);
float intensityMultiplier = 1f;
float moonIntensityMult = 0.025f;
if (currentTimeOfDay <= 0.23f || currentTimeOfDay >= 0.75f)
{
RenderSettings.skybox = skyBoxNight;
intensityMultiplier = 0f;
moonIntensityMult = 0.025f;
}
else if (currentTimeOfDay <= 0.25f)
{
RenderSettings.skybox = skyBoxNight;
intensityMultiplier = Mathf.Clamp01((currentTimeOfDay - 0.23f) * (1 / 0.02f));
moonIntensityMult = 0f;
}
else if (currentTimeOfDay >= 0.73f)
{
RenderSettings.skybox = skyboxDay;
intensityMultiplier = Mathf.Clamp01(1 - ((currentTimeOfDay - 0.73f) * (1 / 0.02f)));
moonIntensityMult = 0f;
}
sun.intensity = sunInitialIntensity * intensityMultiplier;
moon.intensity = moonIntensityMult;
}
public float GetTimeOfDayInSeconds
{
get { return currentTimeOfDay; }
set { return; }
}
void IncrementDays()
{
currentDay++;
currentSecond = 0;
currentMinute = 0;
currentHour = 0;
}
}
Answer by mrchacko · Sep 08, 2020 at 12:54 AM
Okay I actually just figured out what I was doing wrong and here is the code for a full 24 hour cycle.
Note** This is a very sloppy version. The longer you want to handle how long a game day is the more broken this is going to get (because of the day increment, I wasn't sure how to do this smoothly before the currentTimeOfDay returned to 0). It works for like 3600 seconds of real time being a full 24 hours of game time.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
public class DayNightCycle : MonoBehaviour
{
public static DayNightCycle instance;
public Light sun, moon;
public float secondsInFullDay = 3600f;
[Range(0, 1)]
public float currentTimeOfDay = 0f;
[HideInInspector]
public float timeMultiplier = 1f;
float sunInitialIntensity;
public Material skyboxDay, skyBoxNight;
public double elapsedRealTime;
public float secondsPerDayMultiplier;
[SerializeField]
private float speedOfGameSecond, speedOfGameMinute, speedOfGameHour, speedOfGameDay;
[SerializeField]
private float currentGameSecond, currentGameMinute, currentGameHour, currentGameDay;
private bool stopIncrementingDay;
private void Awake()
{
instance = this;
}
// Start is called before the first frame update
void Start()
{
speedOfGameSecond = secondsInFullDay / 24 / 60 / 60;
speedOfGameMinute = secondsInFullDay / 24 / 60;
speedOfGameHour = secondsInFullDay / 24;
speedOfGameDay = secondsInFullDay;
sunInitialIntensity = sun.intensity;
}
// Update is called once per frame
void Update()
{
UpdateSun();
currentTimeOfDay += (Time.deltaTime / secondsInFullDay) * timeMultiplier;
if (currentTimeOfDay >= 1)
{
currentTimeOfDay = 0;
}
secondsPerDayMultiplier = currentTimeOfDay * secondsInFullDay;
// seconds / total seconds = percentage
// percentage * seconds = total seconds
// seconds = total seconds * percentage
currentGameSecond = secondsPerDayMultiplier / speedOfGameSecond;
currentGameMinute = secondsPerDayMultiplier / speedOfGameMinute;
currentGameHour = secondsPerDayMultiplier / speedOfGameHour;
if(!stopIncrementingDay && currentGameHour >= 23.999)
{
IncrementDay();
stopIncrementingDay = true;
} else if(currentGameHour <= 23.999)
{
stopIncrementingDay = false;
}
elapsedRealTime += Time.deltaTime;
previousTime = Time.deltaTime;
}
void UpdateSun()
{
sun.transform.localRotation = Quaternion.Euler((currentTimeOfDay * 360f) - 90, 170, 0);
moon.transform.localRotation = Quaternion.Euler((currentTimeOfDay * 360f) - 90, 170, 0);
float intensityMultiplier = 1f;
float moonIntensityMult = 0.025f;
if (currentTimeOfDay <= 0.23f || currentTimeOfDay >= 0.85f)
{
RenderSettings.skybox = skyBoxNight;
intensityMultiplier = 0f;
moonIntensityMult = 0.025f;
}
else if (currentTimeOfDay <= 0.25f)
{
RenderSettings.skybox = skyBoxNight;
intensityMultiplier = Mathf.Clamp01((currentTimeOfDay - 0.23f) * (1 / 0.02f));
moonIntensityMult = 0f;
}
else if (currentTimeOfDay >= 0.83f)
{
RenderSettings.skybox = skyboxDay;
intensityMultiplier = Mathf.Clamp01(1 - ((currentTimeOfDay - 0.83f) * (1 / 0.02f)));
moonIntensityMult = 0f;
}
sun.intensity = sunInitialIntensity * intensityMultiplier;
moon.intensity = moonIntensityMult;
}
public float GetTimeOfDayPercent
{
get { return currentTimeOfDay; }
set { return; }
}
public float GetSecondsPerDay()
{
return secondsInFullDay;
}
private void IncrementDay()
{
currentGameSecond = 0;
currentGameMinute = 0;
currentGameHour = 0;
currentGameDay++;
}
public void GetTimeOfDay()
{
// now to work on this
}
}
Answer by Maniacbob · Sep 07, 2020 at 11:34 PM
It might not exactly answer your question but a good starting point might be to look at UnityEvents. You could use an event tied to a specific time to trigger an event or action.
I'd probably create a class to inherit from that has three properties, an update function, and an event function. The first property would be the day for the trigger to occur on, the second would be a time format for when the trigger would go off that you could either tie directly to currentTimeofDay or break it out into hours, minutes, and seconds, and the third would be the event. The update function would listen to the day/night cycle and compare it to its time property and if the time has arrived to invoke its event. The event function would then be blank such that each implemented event could override it to follow its own unique event.
Something like that.
If you don't want to run each one independently, then you could forgo the update loop and add all the events to a List and check each one every update (or some subsection of time). Loop through the list and check to see if the time has passed the event and if so, then invoke the event.
I could go that route but I'd also like to be able to display the current in game time on clocks in the world.
I'm really just not sure how to compute the in game time once I can figure that out...
I think I just solved it using a datetime object. Nope never$$anonymous$$d.
Your answer
