Я делаю цикл день-ночь для своей игры. То, как я это делаю, заключается в том, что у меня есть DateTime, к которому я добавляю секунды каждую секунду. У меня также есть целые минуты, которые в основном (DateTime.hours * 60 + DateTime.minutes).
Я хочу повернуть солнце на основе переменной минут. Окончательное уравнение - Quaternion.Euler (минуты / 4, 0, 0). Все это работает до тех пор, пока DateTime не достигнет полудня в этот момент, солнце не начнет глючить, уходя в отрицательную сторону, а затем возвращается к правильному вращению до полуночи.
В какой-то момент инспектор не показывает те же значения, что показывает Debug.Log солнечной гнили.
Вот видео, показывающее, что происходит. Извините за плохое качество https://thewikihow.com/video__Gtb1h8feGs
Я где-то видел, что это может быть связано с замком карданного подвеса. Я не лучший, когда дело доходит до кватернионов, поэтому я могу говорить чепуху. В любом случае, вот мой код
public enum DayTime
{
Morning,
Noon,
AfterNoon,
Evening,
Night
}
public class MoonTime : MonoBehaviour
{
public DateTime date = new DateTime(2023, 1, 1, 0, 0, 0);
[HideInInspector]
public float minutes = 0;
public float dayLength = 4;
public float smoothness = 4.5f;
[HideInInspector]
public DayTime dayTime;
public delegate void TimeChange(DateTime date);
public event TimeChange onTimeChange;
public delegate void DayTimeChange(DayTime dayTime);
public event DayTimeChange onDayTimeChange;
public Material daySkyBox;
public Material nightSkyBox;
public Light Sun;
public Light Moon;
private void Awake()
{
StartCoroutine(TimeClock());
onTimeChange += (d) =>
{
var sunCurrentRot = Sun.transform.rotation.eulerAngles;
Debug.Log("What rot is should be " + Quaternion.Euler(minutes / 4, sunCurrentRot.y, sunCurrentRot.z).eulerAngles);
Sun.transform.rotation = Quaternion.Euler(minutes / 4, sunCurrentRot.y, sunCurrentRot.z);
Debug.Log("What is it " + Sun.transform.rotation.eulerAngles);
//var moonCurrentRot = Moon.transform.rotation.eulerAngles;
//Moon.transform.rotation = Quaternion.Euler((minutes * 0.25f) + 180, moonCurrentRot.y, moonCurrentRot.z);
};
}
private void Update()
{
}
public IEnumerator TimeClock()
{
while (true)
{
yield return new WaitForSecondsRealtime(1 / smoothness);
float finalValue = 1440 / (dayLength * 60) / smoothness;
date = date.AddSeconds(finalValue);
minutes = (date.Hour * 60) + date.Minute;
if (date.Hour >= 0 && date.Hour < 12)
{
if (dayTime != DayTime.Morning)
{
dayTime = DayTime.Morning;
Debug.Log("Morning");
onDayTimeChange?.Invoke(DayTime.Morning);
}
}
else if (date.Hour == 12)
{
if (dayTime != DayTime.Noon)
{
dayTime = DayTime.Noon;
Debug.Log("Noon");
onDayTimeChange?.Invoke(DayTime.Noon);
}
}
else if (date.Hour > 12 && date.Hour <= 15)
{
if (dayTime != DayTime.AfterNoon)
{
dayTime = DayTime.AfterNoon;
Debug.Log("After Noon");
onDayTimeChange?.Invoke(DayTime.AfterNoon);
}
}
else if (date.Hour > 15 && date.Hour <= 17)
{
if (dayTime != DayTime.Evening)
{
dayTime = DayTime.Evening;
Debug.Log("Evening");
onDayTimeChange?.Invoke(DayTime.Evening);
}
}
else
{
if (dayTime != DayTime.Night)
{
dayTime = DayTime.Night;
Debug.Log("Night");
onDayTimeChange?.Invoke(DayTime.Night);
}
}
onTimeChange?.Invoke(date);
Debug.Log(date);
}
}
}
Любая помощь приветствуется
Единственное, что здесь выглядит иначе, это то, что вы выборочно вызываете функцию, которой не поделились с нами — onDayTimeChange. Что это такое, и что происходит, когда вы его проходите DayTime.Night? Этого нет в фрагменте, который вы разместили.
Изменение onDayTimeChange вызывается в IEnumerator TimeClock() ближе к концу.
Я вижу, что это называется. Я не вижу, что он делает.
Это совпадение, что солнце начинает вести себя странно в полдень, а в вашем методе TimeClock() блок if (date.Hour == 12) — единственный, у которого нет логики помимо dayTime = [...] и Deblug.Log?
@Chuck Всякий раз, когда меняется состояние дня (утро, полдень, вечер, ...), я называю это. Я не использовал его ни в этом фрагменте, ни где-либо еще. В своем предыдущем комментарии вы сказали, что вызываете функцию, но onDayTimeChange — это событие.
@Snapper «Всякий раз, когда меняется состояние дня (утро, полдень, вечер, ...), я называю это». это не совсем правильно; как я уже сказал, вы не вызываете его внутри блока else if (date.Hour == 12), как с любым другим значением DayTime.
Я только сейчас это заметил. Спасибо что подметил это. Это просто ошибка на моей стороне. После исправления солнце кажется таким, что начинает глючить в 6 утра.
@Snapper также обратите внимание, что в ваших чеках у вас есть if (date.Hour >= 0 && date.Hour <= 12), а затем else if (date.Hour == 12)... но вы уже проверяете date.Hour <= 12, поэтому он никогда не достигнет date.Hour == 12, и вы никогда не установите dayTime = DayTime.Noon.
Должно быть, я закодировал это поздно ночью. После исправления всего этого солнце все еще глючит.
In your previous comment you said calling a function but onDayTimeChange is an event -.- Я пытаюсь помочь тебе, приятель. Есть ли у него подписчики? Эти подписчики что-нибудь делают?
Я знаю об этом, извините, если это показалось немного резким, но это вовсе не было намерением. Отвечая на ваш вопрос, нет, у него нет подписчиков. Просто там для меня, чтобы использовать в будущем





Единственное другое исправление, о котором я могу думать, заключается в том, что иногда Unity будет изменять преобразование кватерниона-Эйлера, так что две оси смещаются, чтобы удерживать другую ось в некоторых пределах. Я думаю, что эти пределы могут быть -90...90, но здесь я не уверен.
Я подозреваю, что проблема, с которой вы столкнулись, заключается в том, что вы пытаетесь установить код, опрашивая текущий поворот и обновляя один угол. Если единица преобразовала, например, <91, 0, 0> в <1, 90, 90> или что-то подобное, и вы берете это вращение и устанавливаете следующий угол x равным 92, тогда вы устанавливаете <92, 90, 90> вместо предполагаемых <92, 0, 0>. Это будет не то, что вы имеете в виду, и вы закончите тем, что Unity повторно изменит координаты, чтобы снова быть в пределах границ.
Два возможных решения здесь:
Я настоятельно рекомендую вариант (2), потому что, если вы когда-либо применяете только дельты, вы обнаружите, что ограничения с плавающей запятой и другие ошибки округления приведут вас к тому, что ваше солнце находится в неправильном положении во время день.
Вот предлагаемое исправление для вашего скрипта:
private float sunY;
private float sunZ;
private void Awake()
{
StartCoroutine(TimeClock());
sunY = Sun.transform.rotation.eulerAngles.y;
sunZ = Sun.transform.rotation.eulerAngles.z;
onTimeChange += (d) =>
{
Debug.Log("What rot is should be " + Quaternion.Euler(minutes / 4, sunY, sunZ).eulerAngles);
Sun.transform.rotation = Quaternion.Euler(minutes / 4, sunY, sunZ);
Debug.Log("What is it " + Sun.transform.rotation.eulerAngles);
//var moonCurrentRot = Moon.transform.rotation.eulerAngles;
//Moon.transform.rotation = Quaternion.Euler((minutes * 0.25f) + 180, moonCurrentRot.y, moonCurrentRot.z);
};
}
Это должно гарантировать, что ваши повороты останутся такими, как вы ожидаете, даже если внутреннее преобразование Unity из кватерниона в Эйлера перевернет оси на вас (потому что вы не начинаете с этих значений).
Обратите внимание, что поворот на 345,25 градуса аналогичен повороту на -14,75 градуса...