Почему не получается прервать корутину?

245
01 февраля 2018, 15:13

Привет. Есть такой код -

    if (Input.GetButtonDown("Reload") && !InRealod && Ammo < MaxAmmo)
    {
        StartCoroutine(ReloadCountdown());
    }
    if (InRealod && Input.GetButtonDown("Fire") && Ammo != 0)
    {
        StopCoroutine(ReloadCountdown());
    }
    IEnumerator ReloadCountdown()
    {
        while (Ammo < MaxAmmo)
        {
            InRealod = true;
            yield return new WaitForSeconds(ReloadTime);
            Ammo++;
            InRealod = false;
        }
    }

Но корутина не прерывается. Все условия соблюдаются. Но она сама прерывается когда Ammo == MaxAmmo. Даже если сделать так -

IEnumerator ReloadCountdown()
{
    while (Ammo < MaxAmmo && !Input.GetButtonDown("Fire"))
    {
        InRealod = true;
        yield return new WaitForSeconds(ReloadTime);
        Ammo++;
        InRealod = false;
    }
}

ничего не получается. Идея такая - зарядка патронов в оружие должна идти пока игрок не нажмёт на кнопку огня(если Ammo != 0). Почему не получается прервать корутину?

Answer 1

В строчке StopCoroutine(ReloadCountdown()) - вы по факту сначала запускаете новую корутину перезарядки, а затем её же и останавливаете. Вам нужно кешировать корутину, которую возвращает StartCoroutine(), а в метод StopCoroutine передавать ссылку на неё. К тому же проверку ссылки на корутину перезарядки можно использовать вместо флага InRealod. Внизу код реализации.

А во втором случае ваша проблема связана с тем, что проверка на ввод осуществляется не каждый кадр. Когда вы вызываете yield return new WaitForSeconds(ReloadTime) - корутина приостанавливается на длительность этого таймера и только потом продолжает выполнение. Т.е. она не будет знать нажали вы кнопку или нет, пока она ждала.

    Coroutine _reloadRoutine;
    void Update()
    {
        if (Input.GetButtonDown("Reload") && _reloadRoutine == null && Ammo < MaxAmmo)
        {
            _reloadRoutine = StartCoroutine(ReloadCountdown());
        }
        if (_reloadRoutine != null && Input.GetButtonDown("Fire") && Ammo != 0)
        {
            StopCoroutine(_reloadRoutine);
            _reloadRoutine = null;
        }
    }
    IEnumerator ReloadCountdown()
    {
        while (Ammo < MaxAmmo)
        {
            InRealod = true;
            yield return new WaitForSeconds(ReloadTime);
            Ammo++;
            InRealod = false;
        }
        _reloadRoutine = null;
    }
READ ALSO
async/await за кулисами

async/await за кулисами

Рихтер приводит вот такой код:

243
Events в консоле c#

Events в консоле c#

Вопрос: как реализовать обработчик событий (именно FormClosed, или любой аналог который сработает на закрытии) в консоле или там где нет формы?

195
Оптимизация сортировки списка

Оптимизация сортировки списка

Существует глобальный список новостей

177
Как можно реализовать вывод ObservableCollection в ходе работы программы WPF C#?

Как можно реализовать вывод ObservableCollection в ходе работы программы WPF C#?

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

199