Завершение сопрограммы во время работы в unity3d

Я пытаюсь запустить и завершить сопрограмму с помощью кнопки. Я могу запустить сопрограмму, но не могу ее остановить, если я снова нажму кнопку после первого запуска сопрограммы, она просто перезапустится снова, и значение ползунка увеличится.

вот мой код

    public void LoopButton(){

    if (lb == 1){
        StopCoroutine (AutoLoop());
        tb--;
    } else {
        StartCoroutine (AutoLoop ());
        tb++;
    }
}

IEnumerator AutoLoop(){

    slider.value = slider.minValue;

    while(slider.value < slider.maxValue){
        slider.value++;
        yield return new WaitForSeconds(0.5f);
    }

    StartCoroutine (AutoLoop());
}

Вероятно, вам следует добавить логическое значение «Отменено», которое вы можете проверить при условии while. Предполагая, что в Unity нет специального способа справиться с этим. Похоже, здесь происходит неявная многозадачность.

Christopher 02.05.2018 09:14

@ Кристофер Согласен. Обратите внимание, что многозадачность с помощью сопрограмм - это просто причудливый планировщик, который работает в одном и том же основном потоке в Unity :)

MickyD 02.05.2018 09:18

@Christopher Отлично, спасибо, ребята! :)

Bosanac95 02.05.2018 09:29

@Christopher может добавить это в качестве ответа. Я буду голосовать за тебя :)

MickyD 02.05.2018 09:59

Я думаю, что есть способ справиться с этим, специфичный для Unity, поэтому я добавил ответ. @Christopher Я также включил ваше предложение в качестве альтернативного ответа в свой пост.

sonny 02.05.2018 14:06

Возможный дубликат Остановка Unity и запуск сопрограмм

AresCaelum 02.05.2018 14:12
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
6
1 066
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вы можете использовать StopCoroutine.

Больше информации здесь: https://docs.unity3d.com/ScriptReference/MonoBehaviour.StopCoroutine.html

Используйте строку для имени сопрограммы. Как это:

public void LoopButton(){

    if (lb == 1){
        StopCoroutine ("AutoLoop");
        tb--;
    } else {
        StartCoroutine ("AutoLoop");
        tb++;
    }
}

IEnumerator AutoLoop(){

    slider.value = slider.minValue;

    while(slider.value < slider.maxValue){
        slider.value++;
        yield return new WaitForSeconds(0.5f);
    }

    StartCoroutine ("AutoLoop");
}
Ответ принят как подходящий

Вам нужно вызвать StopCoroutine со ссылкой на одно и тожеCoroutine, возвращенный StartCoroutine, например:

private Coroutine loopCoroutine;

public void LoopButton()
{
    if (lb == 1)
    {
        StopCoroutine(loopCoroutine);
        tb--;
    }
    else
    {
        loopCoroutine = StartCoroutine(AutoLoop());
        tb++;
    }
}

Чтобы использовать этот подход, измените свой метод AutoLoop, чтобы использовать цикл while, а не запускать другую сопрограмму AutoLoop в конце метода. В противном случае вы не сможете остановить эту новую сопрограмму, запущенную в конце AutoLoop.

IEnumerator AutoLoop()
{
    while(true)
    {
        slider.value = slider.minValue;

        while (slider.value < slider.maxValue)
        {
            slider.value++;
            yield return new WaitForSeconds(0.5f);
        }
    }
}

В качестве альтернативного решения, как прокомментировал другой пользователь, также можно остановить сопрограмму с помощью логического флага:

private bool stopLoop;

public void LoopButton()
{
    if (lb == 1)
    {
        stopLoop = true;
        tb--;
    }
    else
    {
        stopLoop = false;
        StartCoroutine (AutoLoop ());
        tb++;
    }
}

IEnumerator AutoLoop()
{
    slider.value = slider.minValue;

    while (slider.value < slider.maxValue && !stopLoop)
    {
        slider.value++;
        yield return new WaitForSeconds(0.5f);
    }

    if (!stopLoop)
    {
        StartCoroutine(AutoLoop());
    }
}

Однако использование Unity StopCoroutine предпочтительнее использования логического флага для удобства чтения и чистоты.

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

Immersive 02.05.2018 14:27

@ Immersive: такую ​​очистку следует оставить блоку finally, так или иначе. И финалы даже должны выполняться с исключением «ThreadAborted». Это сторона саботажа, они всегда должны убегать. Вот две статьи по этому вопросу, на которые я часто ссылаюсь: blogs.msdn.com/b/ericlippert/archive/2008/09/10/… | codeproject.com/Articles/9538/…

Christopher 02.05.2018 17:09

@Christopher Я согласен в принципе, но это немного сложнее сделать в Unity, особенно для сопрограмм Unity, потому что они работают в основном потоке, а не в новом потоке (т.е. нет ThreadAbortedException). Я не знаком с этой проблемой в деталях, но думаю, что при использовании try / finally с StopCoroutine следует учесть некоторые нюансы. Например, см. это сообщение на форуме Unity: "наконец-то блокировка не выполняется в остановленной сопрограмме"

sonny 02.05.2018 17:29

@sonny: О, я только боялся, что они могли сделать что-то настолько глупое. Основная идея того, чтобы компилятор выполнял за вас совместную многозадачность, заключалась в том, что он не будет делать чего-то настолько глупого. Похоже, что метод расширения StopAndDispose () - это способ справиться с этим случаем.

Christopher 03.05.2018 06:30

Другие вопросы по теме