Правильный способ управлять временем в единстве - PullRequest
0 голосов
/ 22 января 2019

Мне нужно выполнить какое-то временное задание (симуляцию), например, как началась игра:

  • Через 2 минуты запустите TrainA.
  • Через 6 минут звездный поезд B
  • через 12 минут запустите поезд C и т. Д.

Но помните: если я хочу быстро просмотреть симуляцию, таймер долженбыть в состоянии скорости.

Теперь я рассматриваю два подхода (приветствуются и другие подходы, в этом и причина вопроса)

Каждый скрипт объекта (поезда) управляет своим временем:

void Start()
{
    StartCoroutine("MyEvent");
}

private IEnumerator MyEvent()
{

    yield return new WaitForSeconds(120f); // wait two minutes
    //Launch Train

}

Как и этот вид сценария прикрепить к каждому объекту, требующему действия по истечении определенного времени:

Проблема:

  1. Как мнеускорить время?
  2. Может быть, производительность интенсивна.Поскольку каждый сценарий управляет своей собственной подпрограммой (возможно, я ошибаюсь)

Один таймер Глобальный сценарий:

    function Update ()
    {
    Timer += Time.deltaTime; //Time.deltaTime will increase the value with 1 every second.
    if (timer>= 120){
    //launch train, an so one conditions
   //Or get timer variable in other script and compare time on update 
    }

} 

Теперь, используя приведенный выше сценарий, я могуполучить переменную Timer в другом скрипте и может выполнять мою задачу на основе времени в методе обновления.

Теперь вопрос в том, как мне управлять этим?Первый или второй путь или третий путь (вами)?Потому что я также хочу ускорить время, которое кажется невозможным в совместной программе, когда оно регистрируется.Нужна ваша помощь, ребята !!

1 Ответ

0 голосов
/ 22 января 2019

Вы используете любой из двух способов и просто меняете Time.timescale , если хотите просмотреть его быстрее / медленнее и т. Д. В примере, нажав Пробел :

public class Example : MonoBehaviour
{
    // Toggles the time scale between 1 (normal) and 0.5 (twice as fast)
    // whenever the user hits the Space key.

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            if (Time.timeScale == 1.0f)
            {
                Time.timeScale = 0.5f;
            }
            else
            {
                Time.timeScale = 1.0f;
            }

            // Also adjust fixed delta time according to timescale
            // The fixed delta time will now be 0.02 frames per real-time second
            Time.fixedDeltaTime = 0.02f * Time.timeScale;
        }
    }
}

Для сопрограмм это работает без необходимости что-либо менять, потому что WaitForSeconds зависит от Time.timescale:

Фактическое время приостановки равноданное время, умноженное на Time.timeScale.


Time.deltaTime afaik not , на которое воздействует Time.timescale, поэтому для более быстрого воспроизведения вам потребуетсяdo

private void Update ()
{
    Timer += Time.deltaTime * (1 / Time.timescale); 

    if (timer >= 120)
    {
        //launch train, an so one conditions
        //Or get timer variable in other script and compare time on update 
    }
}

Будет ли один Update или несколько сопрограмм более производительным, во многом зависит от конкретного варианта использования.На самом деле, на самом деле это не заметно, пока у вас не будет примерно 10.000 сопрограмм (не указывайте здесь числа;)).

В вашем случае для поднятия только одного или нескольких событий лучше придерживатьсявместо этого с одним методом Update() и вызовите событие или что-то в этом роде.

Но - почему бы просто не иметь один единственный сопрограмм вместо Update вообще:

public class GlobalTimer : MonoBehaviour
{
    public float Delay = 2.0f;
    public UnityEvent onTimerDone;

    // Unity allows to use Start as IEnumerator instead of a void
    private IEnumerator Start()
    {
        yield return new WaitforSeconds(delay);

        onTimerDone.Invoke();
    }
}

, чем у вас есть только один вызванный метод и вы можете добавить обратные вызовы к этому таймеру, например

globalTimerReference.onTimerDone.AddListener(() => {
    Debug.LogFormat("Timer of {0} seconds is done now.", globalTimerReference.Delay);
});

или через инспектор (как в UI.Button.onClick).

ДляНесколько событий Я только что предложил быстрое и грязное решение, чтобы вы могли просто определить несколько событий через инспектор и добавить различные обратные вызовы и прочее:

public class GlobalTimer : MonoBehaviour
{
    public List<UnityEvent> events;
    public List<float> delays;

    private void Start()
    {
        var validPairs = Mathf.Min(events.Count, delays.Count);

        for (int i = 0; i < validPairs; i++)
        {
            StartCoroutine(InvokeDelayed(events[i], delays[i]));
        }
    }

    private IEnumerator InvokeDelayed(UnityEvent unityEvent, float delay)
    {
        yield return new WaitForSeconds(delay);

        unityEvent.Invoke();
    }
}

Просто убедитесь, что для каждого события есть задержка всписок.В будущем вы, возможно, захотите написать правильный CustomEditor, чтобы редактировать этот более красивый в инспекторе.

Обновление

или вы можете взять мой: D

public class ExampleScript : MonoBehaviour
{
    [SerializeField] private List<EventDelayPair> EventDelayPairs;

    private void Start()
    {
        foreach (var eventDelayPair in EventDelayPairs)
        {
            StartCoroutine(InvokeDelayed(eventDelayPair.unityEvent, eventDelayPair.Delay));
        }
    }

    private IEnumerator InvokeDelayed(UnityEvent unityEvent, float delay)
    {
        yield return new WaitForSeconds(delay);

        unityEvent.Invoke();
    }

    [Serializable]
    private class EventDelayPair
    {
        public UnityEvent unityEvent;
        public float Delay;
    }
}

[CustomEditor(typeof(ExampleScript))]
public class ExampleInspector : Editor
{
    private SerializedProperty EventDelayPairs;
    private ReorderableList list;

    private ExampleScript _exampleScript;

    private void OnEnable()
    {
        _exampleScript = (ExampleScript)target;

        EventDelayPairs = serializedObject.FindProperty("EventDelayPairs");

        list = new ReorderableList(serializedObject, EventDelayPairs)
        {
            draggable = true,
            displayAdd = true,
            displayRemove = true,
            drawHeaderCallback = rect =>
            {
                EditorGUI.LabelField(rect, "DelayedEvents");
            },
            drawElementCallback = (rect, index, sel, act) =>
            {
                var element = EventDelayPairs.GetArrayElementAtIndex(index);

                var unityEvent = element.FindPropertyRelative("unityEvent");
                var delay = element.FindPropertyRelative("Delay");


                EditorGUI.PropertyField(new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight), delay);

                rect.y += EditorGUIUtility.singleLineHeight;

                EditorGUI.PropertyField(new Rect(rect.x, rect.y, rect.width, EditorGUI.GetPropertyHeight(unityEvent)), unityEvent);


            },
            elementHeightCallback = index =>
            {
                var element = EventDelayPairs.GetArrayElementAtIndex(index);

                var unityEvent = element.FindPropertyRelative("unityEvent");

                var height = EditorGUI.GetPropertyHeight(unityEvent) + EditorGUIUtility.singleLineHeight;

                return height;
            }
        };
    }

    public override void OnInspectorGUI()
    {
        DrawScriptField();

        serializedObject.Update();

        list.DoLayoutList();

        serializedObject.ApplyModifiedProperties();
    }

    private void DrawScriptField()
    {
        // Disable editing
        EditorGUI.BeginDisabledGroup(true);
        EditorGUILayout.ObjectField("Script", MonoScript.FromMonoBehaviour(_exampleScript), typeof(ExampleScript), false);
        EditorGUI.EndDisabledGroup();

        EditorGUILayout.Space();
    }
}

Пример

enter image description here

или с предварительным просмотром задержек для отладки

public class ExampleScript : MonoBehaviour
{
    public List<EventDelayPair> EventDelayPairs;

    private void Start()
    {
        foreach (var eventDelayPair in EventDelayPairs)
        {
            StartCoroutine(InvokeDelayed(eventDelayPair));
        }
    }

    private IEnumerator InvokeDelayed(EventDelayPair pair)
    {
        var timer = pair.Delay;

        do
        {
            timer -= Time.deltaTime * (1 / Time.timeScale);
            pair.Delay = timer;
            yield return null;
        } while (timer > 0);

        pair.Delay = 0;

        pair.unityEvent.Invoke();
    }

    [Serializable]
    public class EventDelayPair
    {
        public UnityEvent unityEvent;
        public float Delay;
    }
}

enter image description here


Кстати, ваш комментарий

// Time.deltaTime будет увеличивать значение на 1 каждую секунду.

не сформулировано правильно.Вместо этого должно быть:

Time.deltaTime будет увеличивать значение каждого кадра примерно на время, прошедшее в секундах с момента рендеринга последнего кадра.


РЕДАКТИРОВАТЬ - Уменьшить задержки впоследствии

Я понял из вопроса, что вы хотели speed up всего воспроизведения.

Из комментариев, которые я узнал сейчас, вместо этого вы хотели скорее уменьшитьзадержка потом.Таким образом, вы не можете использовать Time.timescale.

. Для этого вы можете использовать второй пример, слегка измененный:

[Serializable]
public class EventDelayPair
{
    public UnityEvent unityEvent;
    public float Delay;
    // add a time multiplicator for each delay with default 1
    public float TimeMultiplicator = 1.0f;
}

Примечание : вам придетсятакже добавьте его в EditorScript, если вы его используете - я оставляю это как домашнее задание;)

private IEnumerator InvokeDelayed(EventDelayPair pair)
{
    var timer = pair.Delay;

    do
    {
        timer -= Time.deltaTime * pair.TimeMultiplicator;
        pair.Delay = timer;
        yield return null;
    } while (timer > 0);

    pair.Delay = 0;

    pair.unityEvent.Invoke();
}

, чтобы вы могли в Инспекторе или также по сценарию

exampleScriptReference.EventDelayPairs[0].TimeMultiplicator = 2;

уменьшить задержкубыстрее.

Вы также можете добавить общий мультипликатор, например

// Again you have to add it to the inspector if you use it
public float overallMultiplicator = 1.0f;

//...
    timer -= Time.deltaTime * pair.TimeMultiplicator * overallMultiplicator;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...