Я пытаюсь запустить и завершить сопрограмму с помощью кнопки. Я могу запустить сопрограмму, но не могу ее остановить, если я снова нажму кнопку после первого запуска сопрограммы, она просто перезапустится снова, и значение ползунка увеличится.
вот мой код
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());
}
@ Кристофер Согласен. Обратите внимание, что многозадачность с помощью сопрограмм - это просто причудливый планировщик, который работает в одном и том же основном потоке в Unity :)
@Christopher Отлично, спасибо, ребята! :)
@Christopher может добавить это в качестве ответа. Я буду голосовать за тебя :)
Я думаю, что есть способ справиться с этим, специфичный для Unity, поэтому я добавил ответ. @Christopher Я также включил ваше предложение в качестве альтернативного ответа в свой пост.
Возможный дубликат Остановка Unity и запуск сопрограмм
Вы можете использовать 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: такую очистку следует оставить блоку finally, так или иначе. И финалы даже должны выполняться с исключением «ThreadAborted». Это сторона саботажа, они всегда должны убегать. Вот две статьи по этому вопросу, на которые я часто ссылаюсь: blogs.msdn.com/b/ericlippert/archive/2008/09/10/… | codeproject.com/Articles/9538/…
@Christopher Я согласен в принципе, но это немного сложнее сделать в Unity, особенно для сопрограмм Unity, потому что они работают в основном потоке, а не в новом потоке (т.е. нет ThreadAbortedException
). Я не знаком с этой проблемой в деталях, но думаю, что при использовании try / finally с StopCoroutine
следует учесть некоторые нюансы. Например, см. это сообщение на форуме Unity: "наконец-то блокировка не выполняется в остановленной сопрограмме"
@sonny: О, я только боялся, что они могли сделать что-то настолько глупое. Основная идея того, чтобы компилятор выполнял за вас совместную многозадачность, заключалась в том, что он не будет делать чего-то настолько глупого. Похоже, что метод расширения StopAndDispose () - это способ справиться с этим случаем.
Вероятно, вам следует добавить логическое значение «Отменено», которое вы можете проверить при условии while. Предполагая, что в Unity нет специального способа справиться с этим. Похоже, здесь происходит неявная многозадачность.