Я знаю, что этот вопрос задавали по поводу других вкусов, но я не нашел своего... извините, если дублирую.
У меня есть функция, которая внутренне использует класс Time
и его свойства, как, например, deltaTime
.
Чтобы отладить свою функцию, я хотел бы использовать не класс Time
как есть, а его производный класс TimeDebug : Time
и переопределить свойство deltaTime
, превратив его во что-то предсказуемое, т.е.:
public class TimeDebug : Time
{
public static new float deltaTime { get { return 0.2f; } }
}
Моя функция будет использовать класс как полиморфный параметр:
void DoSomething(TimeDebug timer)
{
...
...
}
Моя функция может получить параметр Time
или TimeDebug
, в зависимости от «Режима выпуска» или «Режима отладки»:
DoSomething(new TimerDebug()) // debug mode
DoSomething(new Timer()) // release mode
Теперь возникает вопрос: компилятор не позволит мне скомпилировать доступ для чтения к статическому члену deltaTime
, потому что я делаю это из экземпляра класса. Например, я не могу сделать:
void DoSomething(TimeDebug timer)
{
Debug.Log(timer.deltaTime); // won't compile!!
}
Как передать параметр класса, чтобы я мог прочитать свойство deltaTime
, независимо от того, равен ли параметр класса Time
или TimeDebug
?
Это звучит как проблема XY. Какова основная цель, которая в первую очередь привела к созданию этого дизайна? Если цель состоит в том, чтобы иметь разные функциональные возможности в режиме отладки, то могут быть варианты получше.
Другие уже упомянули фундаментальный недостаток этого подхода, поэтому я не буду туда углубляться. Я также видел упоминание об использовании Time.captureDeltaTime
, хотя, возможно, вас тоже заинтересует Application.targetFrameRate
, если вашей целью является тестирование с заданной частотой кадров.
@ ipodtouch0218 Я пытался избежать ветвления кода, независимо от того, предварительно скомпилирован он или нет (@David). Наличие веток кода для каждого «исключения» показалось мне беспорядочным. Я думал, что наследование могло бы добавить больше простоты, потому что мы используем один и тот же код функции (без ветвления), работающий с обоими классами, благодаря полиморфизму. Возможно, полиморфизм нецелесообразен?
Вы не можете переопределить статическое свойство, поскольку статические свойства не могут быть virtual
. Лучшее, что вы можете сделать, это создать новый класс, который имеет собственное нестатическое свойство virtual float deltaTime
, и создать два дочерних класса, которые наследуются от него: один возвращает Time.deltaTime
, а другой возвращает 0.2f
; затем пройдите эти занятия.
@ ipodtouch0218 Я думаю, что твое решение - точное решение вопроса. Мне жаль, что я этого не понял... :-) Не могли бы вы отредактировать свой ответ ниже и добавить к нему свои недавние слова комментария? Тогда я отмечу задачу как решенную.
@oscar сделал это.
Я чувствую, что это проблема XY. На самом деле вас не волнует «получение статического свойства через экземпляр», вы пытаетесь исправить deltaTime
до определенного значения в Unity (условно).
Это можно сделать, просто установив для Time.captureDeltaTime значение 0,2f:
Если это свойство имеет ненулевое значение, то Time.time увеличивается с интервалом captureDeltaTime (масштабируемым Time.timeScale) независимо от реального времени и продолжительности кадра. Это полезно, если вы хотите снять фильм, в котором вам нужна постоянная частота кадров и вы хотите оставить достаточно времени между кадрами для сохранения изображений на экране.
Очевидно, что из-за того, что вы блокируете deltaTime
без блокировки частоты кадров, игра будет работать СЛИШКОМ быстро для большинства компьютеров. (1 секунда реального времени при 200 кадрах в секунду будет 0.2 (deltaTime) * 200 (frames)
= 40 секундам игрового времени)
Что касается того, почему это называется «captureDeltaTime
»; он предназначен в основном для «захвата» видео игрового процесса как можно быстрее, без учета того, как оно выглядит в реальном времени. Похоже на то, что видеоредакторы при рендеринге просматривают видео намного быстрее, чем в реальном времени.
Решение «Y»-части проблемы XY: вы не можете переопределить статическое свойство, поскольку статические свойства не могут быть виртуальными.
Лучшее, что вы можете сделать, это создать новый класс, который имеет собственное нестатическое свойство virtual float deltaTime
, и создать два дочерних класса, которые наследуются от него: один возвращает Time.deltaTime
, а другой возвращает 0.2f
; затем перейдите в эти классы:
public class Timer {
public virtual float deltaTime => Time.deltaTime;
}
public class DebugTimer : Timer {
public override float deltaTime => 0.2f;
}
Затем вы можете просто передать экземпляр Timer
:
void DoSomething(Timer timer)
{
Debug.Log(timer.deltaTime);
}
Действительно хороший хак, не знал об этом. Однако, поскольку я только тестирую функцию, ее вызовы происходят только внутри одного кадра. Почему? Потому что таким образом мне не придется ждать (например) 10000 кадров, чтобы протестировать 10000 вызовов функций. Выполнение 10000 вызовов функций внутри простого цикла for (все внутри одного кадра) намного эффективнее. А мой класс TimeDebug был предназначен для имитации разного времени кадра (и других параметров) при каждом вызове без выхода из кадра. Так что да, это похоже на проблему XY... но я подумал, что наследование может быть элегантным решением этой ситуации.
Обобщенным решением было бы предоставить Time(r) (какой из них?) виртуальное нестатическое свойство, которое может быть переопределено производным классом:
public class TimeDebug : Time
{
public static new float deltaTime { get { return 0.2f; } }
public override float DeltaTime => deltaTime;
}
Использование соглашений об именах для указания обоих видов доступа может вызывать опасения (может быть даже сомнительно вообще иметь статическое свойство, в зависимости от вашего использования), но это «правильный» способ запроса свойства, привязанного к конкретному экземпляр класса, который будет запрошен методами. Другие, более загадочные реализации могут включать в себя предоставление таймеру обобщенного свойства DeltaTime, которое использует отражение ссылки «this» для поиска фактического значения статического свойства «deltaTime», но я не думаю, что здесь это имеет большой смысл.
Если вы ссылаетесь на него, полное квалифицированное имя класса «Time» — это класс «UnityEngine.Time». Что касается вашего ответа, свойство «DeltaTime» будет новым и не будет существовать в базовом классе «Time», AFAIK, поэтому полиморфизм потерпит неудачу, не так ли? Если нам нужно написать две разные функции для доступа к каждому классу, мы теряем преимущества наследования.
Какой смысл передавать экземпляр класса только для того, чтобы получить от него статическое свойство? Почему бы просто не передать сам deltaTime?
release ? Time.deltaTime : 0.2f
?