1

I have been following two different tutorials regarding in-game day night cycles. One is for a TimeTickSystem that enables fires to light up as specific events. The other is for a DayNight cycle that rotates the sun and enables starts to fade in and out when night comes. Now I want those two to play together nicely so that I can have both a day night cycle with stars fading and also the fires starting and stopping.

1st Script : TimeTickSystem provides float timeOfDay, OnLightFires and OnExtinguishFires events as well as public void TestTimeEventsOnSetTime()

2nd Script: DayNightController script. Provides "time" float and calculates it in the same way as TimeTickSystem's "timeOfDay". I need these two scripts to be able to work together in a way that their times are always the same and their events happen at the same time.

using System;
using UnityEngine;

public static class TimeTickSystem
{
    public class OnTimeEventArgs : EventArgs
    {
        public float timeOfDay;
    }

    public static event EventHandler<OnTimeEventArgs> OnLightFires;
    public static event EventHandler<OnTimeEventArgs> OnExtinguishFires;

    private static GameObject timeTickSystemObject;
    private static TimeTickSystemObject timeTickSystemComponent;
    private static float timeOfDay, timeOfDayPrevious = 43200f;
    private static float secondsPerSecond = 1000;
    private static bool areFiresLit;
    private static Vector3 hmsOfDay;

    public static void Create()
    {
        if (timeTickSystemObject == null)
        {
            timeTickSystemObject = new GameObject("TimeTickSystem");
            timeTickSystemComponent = timeTickSystemObject.AddComponent<TimeTickSystemObject>();
        }
    }

    public static bool AreFiresLit
    {
        get { return areFiresLit; }
    }

    public static float SecondsPerSecond
    {
        get { return secondsPerSecond; }
        set { secondsPerSecond = value; }
    }

    public static float TimeOfDay
    {
        get { return timeOfDay; }
        set
        {
            timeOfDay = value;
            timeOfDayPrevious = timeOfDay; // Could subtract a very small number;
            hmsOfDay = FloatToHMS(timeOfDay);
            timeTickSystemComponent.TestTimeEventsOnSetTime();
        }
    }

    public static Vector3 HMSOfDay
    {
        get { return hmsOfDay; }
        set
        {
            TimeOfDay = HMSToFloat(hmsOfDay.x, hmsOfDay.y, hmsOfDay.z);
        }
    }

    public static float HMSToFloat(float hour, float minute, float second)
    {
        return 3600f * hour + 60f * minute + second;
    }

    public static Vector3 FloatToHMS(float time)
    {
        Vector3 temp = Vector3.zero;
        temp.x = Mathf.Floor(time / 3600);
        time -= temp.x * 3600f;
        temp.y = Mathf.Floor(time / 60);
        temp.z = time - temp.y * 60f;
        return temp;
    }

    public static bool TimeFallsBetween(float currentTime, float startTime, float endTime)
    {
        if (startTime < endTime)
        {
            if (currentTime >= startTime && currentTime <= endTime) return true;
            else return false;
        }
        else
        {
            if (currentTime < startTime && currentTime > endTime) return false;
            else return true;
        }
    }

    private class TimeTickSystemObject : MonoBehaviour
    {
        private void Update()
        {
            timeOfDay += Time.deltaTime * secondsPerSecond;
            if (timeOfDay > 86400f) // 24 hours * 60 minutes * 60 seconds = 86400 = Midnight
            {
                //days += 1;
                timeOfDay -= 86400f;
            }
            TestTimeEvents();
            timeOfDayPrevious = timeOfDay;
        }

        public void TestTimeEvents()
        {
            // You should parameterize these times, or set them from another script
            if (timeOfDayPrevious < HMSToFloat(18f, 0f, 0f) && timeOfDay >= HMSToFloat(18f, 0f, 0f))
            {
                //if (OnLightFires != null) OnLightFires(this, new OnTimeEventArgs { timeOfDay = timeOfDay });
                OnLightFires?.Invoke(this, new OnTimeEventArgs { timeOfDay = timeOfDay });
                areFiresLit = true;
            }
            if (timeOfDayPrevious < HMSToFloat(6f, 0f, 0f) && timeOfDay >= HMSToFloat(6f, 0f, 0f))
            {
                OnExtinguishFires?.Invoke(this, new OnTimeEventArgs { timeOfDay = timeOfDay });
                areFiresLit = false;
            }
        }

        public void TestTimeEventsOnSetTime()
        {
            // You should parameterize these times, or set them from another script
            if (TimeFallsBetween(timeOfDay, HMSToFloat(18f, 0f, 0f), HMSToFloat(6f, 0f, 0f)))
            {
                OnLightFires?.Invoke(this, new OnTimeEventArgs { timeOfDay = timeOfDay });
                areFiresLit = true;
            } 
            else 
            {
                OnExtinguishFires?.Invoke(this, new OnTimeEventArgs { timeOfDay = timeOfDay });
                areFiresLit = false;
            }
        }
    }
}
using UnityEngine;
using System;
using CodeMonkey.Utils;

public class DayNightController : MonoBehaviour
{
    [SerializeField] private Transform sunTransform;
    [SerializeField] private Light sun;
    [SerializeField] private float angleAtNoon;
    [SerializeField] private Vector3 hourMinuteSecond = new Vector3(6f, 0f, 0f), hmsSunSet = new Vector3(18f, 0f, 0f);
    [SerializeField] public int days = 0;
    [SerializeField] public float speed = 100;
    [SerializeField] private float intensityAtNoon = 1f, intensityAtSunSet = 0.5f;
    [SerializeField] private Color fogColorDay = Color.grey, fogColorNight = Color.black;
    [SerializeField] private Transform starsTransform;
    [SerializeField] private Vector3 hmsStarsLight = new Vector3(19f, 30f, 0f), hmsStarsExtinguish = new Vector3(03f, 30f, 0f);
    [SerializeField] private float starsFadeInTime = 7200f, starsFadeOutTime = 7200f;

    [NonSerialized] public float time;

    private float intensity, rotation, prev_rotation = -1f, sunSet, sunRise, sunDayRatio, fade, timeLight, timeExtinguish;
    private Color tintColor = new Color(0.5f, 0.5f, 0.5f, 0.5f);
    private Vector3 dir;
    private Renderer rend;

    void Start()
    {
        rend = starsTransform.GetComponent<ParticleSystem>().GetComponent<Renderer>();
        time = HMS_to_Time(hourMinuteSecond.x, hourMinuteSecond.y, hourMinuteSecond.z);
        sunSet = HMS_to_Time(hmsSunSet.x, hmsSunSet.y, hmsSunSet.z);
        sunRise = 86400f - sunSet;
        sunDayRatio = (sunSet - sunRise) / 43200f;
        dir = new Vector3(Mathf.Cos(Mathf.Deg2Rad * angleAtNoon), Mathf.Sin(Mathf.Deg2Rad * angleAtNoon), 0f);
        //dir = new Vector3(1f, 0f, 0f);
        starsFadeInTime /= speed;
        starsFadeOutTime /= speed;
        fade = 0;
        timeLight = HMS_to_Time(hmsStarsLight.x, hmsStarsLight.y, hmsStarsLight.z);
        timeExtinguish = HMS_to_Time(hmsStarsExtinguish.x, hmsStarsExtinguish.y, hmsStarsExtinguish.z);
        
       


    }
    

    void Update()
    {
        // normal below
        time += Time.deltaTime * speed;
        if (time > 86400f)
        {
            days += 1;
            time -= 86400f;
        }
        if (prev_rotation == -1f)
        {
            sunTransform.eulerAngles = Vector3.zero;
            prev_rotation = 0f;
        }
        else prev_rotation = rotation;

        rotation = (time - 21600f) / 86400f * 360f;
        sunTransform.Rotate(dir, rotation - prev_rotation);
        starsTransform.Rotate(dir, rotation - prev_rotation);

        if (time < sunRise) intensity = intensityAtSunSet * time / sunRise;
        else if (time < 43200f) intensity = intensityAtSunSet + (intensityAtNoon - intensityAtSunSet) * (time - sunRise) / (43200f - sunRise);
        else if (time < sunSet) intensity = intensityAtNoon - (intensityAtNoon - intensityAtSunSet) * (time - 43200f) / (sunSet - 43200f);
        else intensity = intensityAtSunSet - (1f - intensityAtSunSet) * (time - sunSet) / (86400f - sunSet);

        RenderSettings.fogColor = Color.Lerp(fogColorNight, fogColorDay, intensity * intensity);
        if (sun != null) sun.intensity = intensity;

        if (Time_Falls_Between(time, timeLight, timeExtinguish))
        {
            fade += Time.deltaTime / starsFadeInTime;
            if (fade > 1f) fade = 1f;
        }
        else
        {
            fade -= Time.deltaTime / starsFadeOutTime;
            if (fade < 0f) fade = 0f;
        }
        tintColor.a = fade;
        rend.material.SetColor("_TintColor", tintColor);

        //test
        
        //test
    }

    private float HMS_to_Time(float hour, float minute, float second)
    {
        return 3600 * hour + 60 * minute + second;
    }

    private bool Time_Falls_Between(float currentTime, float startTime, float endTime)
    {
        if (startTime < endTime)
        {
            if (currentTime >= startTime && currentTime <= endTime) return true;
            else return false;
        }
        else
        {
            if (currentTime < startTime && currentTime > endTime) return false;
            else return true;
        }

    }

    

}

My first idea was to just match their values so they both have the exact same values at any moment, which didn't work as the fires seem to just turn off a few seconds after game starts and never turn back on.

So the next idea is to reference TimeTickSystem's "timeofDay" inside the DayNightController script and set it to always be "time" and also call upon TimeTickSystem's "public void TestTimeEventsOnSetTime()" inside DayNightController but I don't know how to code this.

Any advice will be greatly appreciated as I have been trying for at least 10 hours and I'm at a loss on how to do it. My knowledge of coding is way too limited that despite trying to set both their values as the same, I can't get the fires to light up at night time and turn off in the morning.

  • 1
    Well your second idea is definitely the way to go but not sure what you mean by "I don't know how to code this"? Make the methods needed and call the static functions. i.e., `TimeTickSystem.TimeOfDay`. – jiveturkey Feb 08 '21 at 16:08
  • That's the thing, I wouldn't know how to do it. Setting `TimeTickSystem.TimeOfDay = time; ` produced an error about an unassigned object. I have tried reading about event handlers and referencing public classes in another script but i'm way out of my depth here. – Ilias from Ilios Feb 08 '21 at 16:53

0 Answers0