Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Rotate object without coroutine?

Discussion in 'Scripting' started by TobiasDoerrich, May 17, 2014.

  1. TobiasDoerrich

    TobiasDoerrich

    Joined:
    Mar 20, 2014
    Posts:
    14
    I'm currently working on a Time of Day system, and in that system I want to be able to control at which hour SUNRISE starts, DAY start, SUNSET starts and NIGHT starts. At the moment this is possible in the system and when the "clock" hits the next start hour I start a Coroutine to start the rotating of the sun and moon. I asked this as a question but got no answer. I've tried to solve this myself without any luck at all. I'm hoping that maybe someone here could give help me how to do this?

    My coroutine looks like this:

    Code (csharp):
    1. IEnumerator RotateSun(Vector3 fDegrees, float SecondsDuringTimeSet)
    2.     {
    3.         Quaternion quaFromPosition = _lSunLight.transform.rotation;
    4.         Quaternion quaToPostion = Quaternion.Euler(fDegrees);
    5.  
    6.         for (float t = 0.0f; t < 1; t += Time.deltaTime / SecondsDuringTimeSet)
    7.         {
    8.             _lSunLight.transform.rotation = Quaternion.Lerp(quaFromPosition, quaToPostion, t);
    9.             yield return null;
    10.         }
    11.     }
    And as you see I pass values into that for each time I run it. This is done like this:

    Code (csharp):
    1.  if (_fCurrGameHour == _fTimeStartSunrise  _bMoveSunAndMoonOnlyOnce == true)
    2.         {
    3.             // Which TIMESET should it be:
    4.             _en_CurrTimeSet = TimeSet.SUNRISE;
    5.  
    6.             // How long should the SUN move and how many which degree should it reach before that time ends
    7.             vec3MoveSun = new Vector3(10.0f, 0, 0);
    8.             StartCoroutine(RotateSun(vec3MoveSun, _fConvertSunriseToGTSeconds));
    9.  
    10.             // How long should the MOON move and how many which degree should it reach before that time ends
    11.             vec3MoveMoon = new Vector3(180.0f, 0, 0);
    12.             StartCoroutine(RotateMoon(vec3MoveMoon, _fConvertSunriseToGTSeconds));
    13.  
    14.             // Tell bool that we don't need to move the sun and moon more then once
    15.             _bMoveSunAndMoonOnlyOnce = false;
    16.         }
    And as I wrote this system works at the moment. However it is kind of a static system. So at the moment I need to make sure that the starting hour of the game is the sunrise hour. Otherwise my coroutine would break since it would not rotate to the correct position before the day start hour. And I can definitly not start the game close to sunset then the sun rotates the complete wrong way since it's closer to rotate the wrong way then (I assume).

    So my first question is: Could I somehow make the system more dynamic? I want to be able to still set at which hours SUNRISE, DAY, SUNSET and NIGHT should start so during different season for example I could have different lengths on my day. I want to be able to change these hours in the game and then if the SUNSET would be set later the sun would start to rotate a little slower since it is supposed to take longer to reach it's SUNSET position.

    Onto my second question: Would it also be possible to rewrite my coroutine so I could start the game at any hour I want and the sun would still start at the right degree rotation?

    The sun will always set at the same rotation (170 degrees) and rise at the same rotation (350 degree). I just want to control the time it takes before it reaches to those rotations. Maybe I could somehow move this to my update phase instead of using a Coroutine for this? I have no clue how to change this in my system so if anyone have any ideas. Please help.
     
  2. TobiasDoerrich

    TobiasDoerrich

    Joined:
    Mar 20, 2014
    Posts:
    14
    Anyone? Please, I'm really really stuck on this problem. :(
     
  3. Rutenis

    Rutenis

    Joined:
    Aug 7, 2013
    Posts:
    297
  4. TobiasDoerrich

    TobiasDoerrich

    Joined:
    Mar 20, 2014
    Posts:
    14
    Hmm, yeah. But that does not seem to do what I want. I do not want the SUN to stop rotating and wait for it to start. I want it to rotate certain degrees under a set amount of seconds. And I want to change that so it will move slower if I make the day longer, and faster if I would make the day faster.
     
  5. renman3000

    renman3000

    Joined:
    Nov 7, 2011
    Posts:
    6,680
    And what is wrong with a coroutine? Update, of course is another object.
     
  6. TobiasDoerrich

    TobiasDoerrich

    Joined:
    Mar 20, 2014
    Posts:
    14
    The problem I have is that I cannot start the day at any other hour then SUNRISE, so if I would want to start the game at noon this is not possible since then the sun wont move as I wrote.

    And also my second problem is that I cannot change the SUNRISE Start hour at runtime, if I would, that would break the whole rotation. And I would love to be able to change season and with the at which hour sunset is and so on, and that the SUN then rotates faster or slower depending on if SUNRISE should come later or not. I want know the degrees at which the sun should rise and set, and between that I want to control the speed of how fast the sun reaches them. This way I can have longer DAYS then NIGHTS:
     
  7. NomadKing

    NomadKing

    Joined:
    Feb 11, 2010
    Posts:
    1,461
    I think I understand the problem with your system - you treat the movement of the Sun / Moon as events that you simply fire off without having definitive control over. Instead, you want to swap to a more simulation / state based system, where your game time directly effects what your Sun / Moon /Lighting are doing and can respond to change (we used a similar system in our game City Living).

    If you want, I can probably write a quick example of how you could achieve this, but it'll be tomorrow before I have time. One question though, in your design do you have different requirements during Sunrise and Sunset? Or are they merely the start / end markers for the Day and Night cycles?
     
  8. renman3000

    renman3000

    Joined:
    Nov 7, 2011
    Posts:
    6,680
    Why can't you start the day when ever you want??
    You should just have variables that allow for a flexable system.

    Runday()
    Time
    SunPostion
     
  9. TobiasDoerrich

    TobiasDoerrich

    Joined:
    Mar 20, 2014
    Posts:
    14
    I have four different TimeSets, Sunrise, Day, Sunset and Night. I set starting hours for each set. That's why in my system I can have longer days and the sun stays longer than the moon will during the day.

    So I could say that SUNRISE starts at 06:00, and then I move the sun certain degrees. And at 10:00 DAY starts and so on. And between day and sunset the run rotates a certain amount of degree, and between sunset and night the sun rotates a certain amount of degrees. This as I said is so I can tell how long I want the sun to be shown during a day and so on. :)

    And yes, if you can give me an example that would be perfect. :)

    The only stuff I found is that I rotate the sun 360 degree and that is during a full day. That would always make the day be 50% and night be 50% I would like to control that more in my system.
     
  10. TobiasDoerrich

    TobiasDoerrich

    Joined:
    Mar 20, 2014
    Posts:
    14
    Hmm, yeah, that's kind of what I want I guess. I just do not know how to set that up. I have manged to build this system so it changes colors, and lights intensity and all that during these different hours. However as I said this is the problem I'm stuck with, I have no idea how to solve that.
     
  11. NomadKing

    NomadKing

    Joined:
    Feb 11, 2010
    Posts:
    1,461
    Hi Tobias

    Here's a short example of the type of system I was talking about:

    UnityScript
    Code (csharp):
    1. #pragma strict
    2.  
    3. enum TimeSet {SUNRISE, DAY, SUNSET, NIGHT};
    4.  
    5. var CurrentSimTime : float = 0.0;
    6. private var SimSpeed : float = 10.0;
    7. var MaxSimTime : float = 300.0;
    8.  
    9. var CurrentTimeSet : TimeSet = TimeSet.SUNRISE;
    10. var NextTimeSet : TimeSet = TimeSet.DAY;
    11.  
    12. private var TimeSetStart : float[] = [0.0, 50.0, 200.0, 250.0];
    13.  
    14. function Update () {
    15.  
    16.     //Increase Sim Time
    17.     CurrentSimTime += Time.deltaTime * SimSpeed;
    18.  
    19.     //Check for Wrap around
    20.     if (CurrentSimTime >= MaxSimTime)
    21.         {
    22.         CurrentSimTime = 0.0;
    23.         CurrentTimeSet = TimeSet.SUNRISE;
    24.         NextTimeSet = TimeSet.DAY;
    25.         }
    26.  
    27.     //Check for TIMESET Changing
    28.     if (CurrentSimTime > TimeSetStart[NextTimeSet])
    29.         {
    30.         CurrentTimeSet += 1;
    31.         NextTimeSet += 1;
    32.  
    33.         //Catch Wrap
    34.         if (NextTimeSet > TimeSetStart.length-1)
    35.             NextTimeSet = 0;
    36.         }
    37.  
    38.     //Do TIMESET Specific Stuff
    39.     switch (CurrentTimeSet)
    40.         {
    41.         case TimeSet.SUNRISE:
    42.  
    43.         return;
    44.  
    45.         case TimeSet.DAY:
    46.  
    47.         return;
    48.  
    49.         case TimeSet.SUNSET:
    50.  
    51.         return;
    52.  
    53.         case TimeSet.NIGHT:
    54.  
    55.         return;
    56.         }
    57.  
    58. }
    59.  
    60. // Test GUI
    61. function OnGUI () {
    62.     GUI.Label(Rect(10.0, 10.0, 1000.0, 200.0), "Current Time: " + CurrentSimTime);
    63.  
    64.     GUI.Label(Rect(10.0, 40.0, 1000.0, 200.0), "Current TimeSet: " + CurrentTimeSet);
    65.     GUI.Label(Rect(10.0, 60.0, 1000.0, 200.0), "Next TimeSet: " + NextTimeSet);
    66.  
    67.     if (GUI.Button(Rect(10.0, 90.0, 100.0, 20.0), "Pause"))
    68.         {
    69.         if (SimSpeed != 0.0)
    70.             SimSpeed = 0.0;
    71.         else
    72.             SimSpeed = 10.0;
    73.         }
    74. }
    Basically, your incrementing your GameTime (I used low numbers to keep it fast and simple), making sure your in the correct TimeSet and then doing something specific to the TimeSet. So for the Sun, since you know the Start and End rotations for your TimeSets, and the CurrentTime of the simulation, you can work out a definitive rotation for any given time in your simulation. The best test of this is that if you pause your simulation, anything that relies on the SimTime for position etc. should also pause.

    As for extending the length of any TimeSet, you'd simple want to write a function that made sure the added time was carried over to all the following TimeSets (e.g. If I added 50 to Sunset, I'd have to add 50 to Night and the MaxSimTime to make sure they stayed at their current lengths.) You may then have to adjust the position of you Sun / Moon / etc. to remain relative to your new TimeSet length to avoid odd moments (e.g If the Sun is 50% of the way through the Day TimeSet when you extend it, make sure it's still 50% of the way through the new one).

    It's not the best example, but maybe you can see a better direction to head in now :)
     
    Last edited: May 19, 2014
  12. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,221
    erm... kind of the blind leading the blind here.

    Generically, all you need is the current time and the time of the sunrise and sunset. You can figure out angles and whatever by just those 3 numbers.

    Code (csharp):
    1.  
    2.     public float timeOfDay = 0;
    3.     public float sunrise = 420;
    4.     public float sunset = 1140;
    5.  
    6.     void aVeryGenericDay(){
    7.         float timeOfDay = Time.time % 1440;
    8.  
    9.         float sunAngle = Mathf.Clamp ((timeOfDay - sunrise) / (sunset - sunrise) * 180, 0, 180);
    10.  
    11.         float nightDuration = 1440 - sunset + sunrise;
    12.         float nightPos = timeOfDay > sunrise ? timeOfDay - sunset : 1440 - sunset + timeOfDay;
    13.  
    14.         float moonAngle = Mathf.Clamp (nightPos / nightDuration * 180, 0, 180);
    15.  
    16.         float hour = Mathf.Floor(timeOfDay / 60);
    17.         float minute = Mathf.Floor (timeOfDay - hour * 60);
    18.  
    19.         print ("Time: "+hour+":"+minute+", SunAngle: " + sunAngle + ", MoonAngle: " + moonAngle);
    20.     }
    21.  
    take the sunAngle for instance. (timeOfDay - sunrise) / (sunset - sunrise) is just a number that gives you back the percentage across the day. At night, that value is actually greater than 1 or less than 0. Since you have a defined number that you know is between 0 and 1, you can simply lerp colors across that range. Say your morning is purple and your evening is green. You can just do Color.lerp(purple, green, timeOfDay).

    That is a very generic version of it though, you would want to use a mixer that will do what you want.

    So consider this (added after the print):
    Code (csharp):
    1.  
    2.         float overallTime = (timeOfDay - sunrise) / (sunset - sunrise);
    3.         if (overallTime < 0 || overallTime > 1) overallTime = nightPos / nightDuration + 1;
    4.         overallTime *= 0.5f;
    5.  
    This will give a basic 0-1 time across the day from dawn to dusk. now that you have a specific amount across the day, you can do some Color lerps for them.

    Lets build some infrastructure to this first:
    Code (csharp):
    1.  
    2.     int HexToInt(char hexChar){
    3.         return ("0123456789ABCDEF").IndexOf (hexChar);
    4.     }
    5.  
    6.     Color HexToRGB (string color) {
    7.         color = color.ToUpper ();
    8.         float red = (HexToInt(color[1]) + HexToInt(color[0]) * 16.0f) / 255.0f;
    9.         float green = (HexToInt(color[3]) + HexToInt(color[2]) * 16.0f) / 255.0f;
    10.         float blue = (HexToInt(color[5]) + HexToInt(color[4]) * 16.0f) / 255.0f;
    11.         return new Color(red, green, blue, 1);
    12.     }
    13.  
    14.     public struct ColorTime{
    15.         public Color color;
    16.         public float time;
    17.         public ColorTime(Color color, float time){
    18.             this.color = color;
    19.             this.time = time;
    20.         }
    21.     };
    22.  
    Basically this gives us some tools to work with.

    Now, lets build a ColorTime array (yeah, color + time, that is it)
    Code (csharp):
    1.  
    2.         ColorTime[] colors = new ColorTime[4];
    3.         colors [0] = new ColorTime (HexToRGB("6dcff6"), 0.00f); // sunrise
    4.         colors [1] = new ColorTime (HexToRGB("1c78c6"), 0.25f); // mid day
    5.         colors [2] = new ColorTime (HexToRGB("0c5594"), 0.50f); // sunset
    6.         colors [3] = new ColorTime (HexToRGB("062a49"), 0.75f); // mid night
    7.  
    Basically, it is derived from morning to midnight. You shouldn't have to redo morning on the end.

    Now, all we have to do is figure out what position whatever the overall time is in that sense.
    Code (csharp):
    1.  
    2.         int p = colors.Length-1;
    3.         while (time < colors[p].time) p--;
    4.  
    Now, every time it runs past this code, it will find the pointer for the ColorTime that is below where we are.

    Next, all we have to do is get the start and end times and colors for this, and do a Color.Lerp to get our result.
    Code (csharp):
    1.  
    2.         float startTime = colors [p].time;
    3.         float endTime = p == colors.Length - 1 ? 1 : colors [p + 1].time;
    4.         Color startColor = colors [p].color;
    5.         Color endColor = p == colors.Length - 1 ? colors [0].color : colors [p + 1].color;
    6.  
    7.         return Color.Lerp (startColor, endColor, (time - startTime) / (endTime - startTime))
    8.  
    Do note that every bit of this is built on the back of this simple mathematical statement.
    Code (csharp):
    1.  
    2. (current - start) / (end - start)
    3.  
    This basically gives you a percentage (0-1) accross the span from start to end wherever the current pointer is.

    It doesn't quite look the same in the night time, because night goes over zero time, thus must loop around.


    P.S. the whole code.
    Code (csharp):
    1.  
    2. public float timeOfDay = 0;
    3.     public float sunrise = 420;
    4.     public float sunset = 1140;
    5.  
    6.     void VeryGeneric(){
    7.         float timeOfDay = Time.time % 1440;
    8.  
    9.         float sunAngle = Mathf.Clamp ((timeOfDay - sunrise) / (sunset - sunrise) * 180, 0, 180);
    10.  
    11.         float nightDuration = 1440 - sunset + sunrise;
    12.         float nightPos = timeOfDay > sunrise ? timeOfDay - sunset : 1440 - sunset + timeOfDay;
    13.  
    14.         float moonAngle = Mathf.Clamp (nightPos / nightDuration * 180, 0, 180);
    15.  
    16.         float hour = Mathf.Floor(timeOfDay / 60);
    17.         float minute = Mathf.Floor (timeOfDay - hour * 60);
    18.  
    19.         float overallTime = (timeOfDay - sunrise) / (sunset - sunrise);
    20.         if (overallTime < 0 || overallTime > 1) overallTime = nightPos / nightDuration + 1;
    21.         overallTime *= 0.5f;
    22.  
    23.  
    24.  
    25.         print ("Time: "+hour+":"+minute+", SunAngle: " + sunAngle + ", MoonAngle: " + moonAngle + ", SkyColor: " + GetSkyColor(overallTime));
    26.     }
    27.  
    28.     Color GetSkyColor(float time){
    29.         // colors has to be in order of time.
    30.         ColorTime[] colors = new ColorTime[4];
    31.         colors [0] = new ColorTime (HexToRGB("6dcff6"), 0.00f); // sunrise
    32.         colors [1] = new ColorTime (HexToRGB("1c78c6"), 0.25f); // mid day
    33.         colors [2] = new ColorTime (HexToRGB("0c5594"), 0.50f); // sunset
    34.         colors [3] = new ColorTime (HexToRGB("062a49"), 0.75f); // mid night
    35.  
    36.         int p = colors.Length-1;
    37.         while (time < colors[p].time) p--;
    38.  
    39.         float startTime = colors [p].time;
    40.         float endTime = p == colors.Length - 1 ? 1 : colors [p + 1].time;
    41.         Color startColor = colors [p].color;
    42.         Color endColor = p == colors.Length - 1 ? colors [0].color : colors [p + 1].color;
    43.  
    44.         return Color.Lerp (startColor, endColor, (time - startTime) / (endTime - startTime));
    45.     }
    46.  
    47.     int HexToInt(char hexChar){
    48.         return ("0123456789ABCDEF").IndexOf (hexChar);
    49.     }
    50.  
    51.     Color HexToRGB (string color) {
    52.         color = color.ToUpper ();
    53.         float red = (HexToInt(color[1]) + HexToInt(color[0]) * 16.0f) / 255.0f;
    54.         float green = (HexToInt(color[3]) + HexToInt(color[2]) * 16.0f) / 255.0f;
    55.         float blue = (HexToInt(color[5]) + HexToInt(color[4]) * 16.0f) / 255.0f;
    56.         return new Color(red, green, blue, 1);
    57.     }
    58.  
    59.     public struct ColorTime{
    60.         public Color color;
    61.         public float time;
    62.         public ColorTime(Color color, float time){
    63.             this.color = color;
    64.             this.time = time;
    65.         }
    66.     };
    67.