Форум программистов, компьютерный форум, киберфорум
Unity, Unity3D
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.80/15: Рейтинг темы: голосов - 15, средняя оценка - 4.80
35 / 26 / 11
Регистрация: 30.01.2018
Сообщений: 169

Что то не так с системой корутин

16.03.2021, 15:43. Показов 3256. Ответов 6

Студворк — интернет-сервис помощи студентам
Приветствую всех.

Написал микро менеджер последовательных действий, через корутины. Хотя это даже менеджером нельзя назвать, но суть не в этом.
Ситуация такая -
Нпс при старте заполняет лист ienumerator'ов действиями которые он хочет последовательно производить(это как бы его цикл действий по уровню) и вызывает StartCoroutine (Это обертка на обычный запуск корутин, но перед этим он делает кое-что)

C#
1
2
3
4
5
6
7
8
9
10
countOfPoints = targets.Length;
 
        for (int i = 0; i < countOfPoints; i++)
        {
            nativeQueueEnumerators.Add(goToPoint(aipath, setter, targets[i]));
            nativeQueueEnumerators.Add(rotateToTarget(setter, targets[i]));
            nativeQueueEnumerators.Add(waitAFewMoment(setter, _waitingTime));
        }
 
        StartCoroutine(setter); // вызов функции



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

C#
1
2
3
  
 protected List<IEnumerator> nativeQueueEnumerators = new List<IEnumerator>();
 protected Queue<IEnumerator> queueEnumerators = new Queue<IEnumerator>();
queueEnumerators является очередью, с которым взаимодействую все действия. nativeQueueEnumerators это лист, который хранит все действия на которые подписался нпс изначально(при старте). Нужен он затем, что вызов происходит следующим образом:

C#
1
StartCoroutine(queueEnumerators.Dequeue());

То есть вызывается корутина, но при этом удаляется это действие из очереди, и в итоге при проходе одного цикла, то есть когда нпс пройдет все точки сделает все повороты и т.д, ему нужно вернуться в первую точку и начать все с начало, и для этого и нужен nativeQueueEnumerators, в очередь queueEnumerators, опять можно засунуть все те действия и опять начать цикл без нашего вмешательства. Надеюсь понятно объяснил, теперь к проблеме, а она заключается в следующем ->
Проблема в том, что первый цикл работает нормально, нпс проходит все точки и т.д, и когда приходит время возвращаться в начало, то есть происходит добавление всех начальных действий в queueEnumerators из nativeQueueEnumerators .


C#
1
2
3
4
5
6
7
8
9
10
11
12
13
 protected void MoveNext(AIDestinationSetter setter)
    {
        if (queueEnumerators.Count == 0) // произошел глобальный цикл
        {
            SetStartsValues();
        }
 
        Coroutine cor = setter.StartCoroutine(queueEnumerators.Dequeue());
 
        if (cor == null)
            Debug.Log("2 цикл не начинается по причине, что не запускается корутина ");
        
    }


Эта функция и запускает следующую корутину из очереди . Setter нужен, так как класс не наследует monobehavior, Условие cor == null, я вставил, что отследить, что происходит, и это условие активируется как после того, как queueEnumerators.Count станет равным нулю(условие выше), после чего произойдет SetStartsValues(),
Код

C#
1
2
3
4
5
6
7
8
private void SetStartsValues()
    {
        for (int i = 0; i < nativeQueueEnumerators.Count; i++)
        {
            queueEnumerators.Enqueue(nativeQueueEnumerators[i]);
           
        }
    }


Дальше корутина не вызовется, не понятно почему, то есть cor будет равен null, в консоль выдаст это сообщение и выйдет из функции и нпс просто остановится и все. Фуу, надеюсь вам понятно. Так вот в чем вопрос, почему корутина не вызывается, он просто проходит по ней и выдает null и все.
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
16.03.2021, 15:43
Ответы с готовыми решениями:

Что-то с системой не так((
не знаю почему то в последние месяцы ужасно зависает, любая программа очень долго грузится, начиная с ворда((( стоит ХР лицензионный,...

Что я делаю не так с файловой системой при установке?
Здравствуйте. Пытаюсь установить ubuntu рядом с Windows 7. Цель - не потерять данные в Windows. В Windows у меня 6 разделов: раздел 1 Мб...

Судя по s.m.a.r.t диск исправен, но с файловой системой что-то не так
Здравствуйте! Отчёт от HARD DRIVE INSPECTOR (немного конфигурации системы в общем и конфига и состояние HDD, в частности). В конце...

6
 Аватар для 1max1
3362 / 1775 / 1028
Регистрация: 26.10.2018
Сообщений: 5,204
16.03.2021, 16:09
C#
1
if (cor == null)
Условие не сработает никогда, так как там выкинет ошибку, либо Dequeue, если в очереди нет элементов, либо StartCoroutine, в который передается null. В остальных случаях всегда будет значение.
0
35 / 26 / 11
Регистрация: 30.01.2018
Сообщений: 169
16.03.2021, 17:17  [ТС]
Вы будете удивлены, но это условие срабатывает. И эта ситуация происходит: когда в очереди элементов становится 0, вызывается функция SetStartsValues(), где в очередь, опять добавляются элементы, после чего вызывается корутина , и этот вызов я присваиваю к cor, и когда это происходит, вызов корутины "доджится" и в cor записывается null. В этом и вопрос, - почему?
0
Эксперт .NETАвтор FAQ
 Аватар для Storm23
10425 / 5155 / 1825
Регистрация: 11.01.2015
Сообщений: 6,226
Записей в блоге: 34
16.03.2021, 18:43
Цитата Сообщение от Srgey1232 Посмотреть сообщение
Дальше корутина не вызовется, не понятно почему, то есть cor будет равен null
Вот смотрите, вы создаете объекты типа IEnumerator и сохраняете в списке.
Объект IEnumerator имеет состояние. Он моожет находится в сосотянии начала итераций, в процессе итераций и в состоянии конца итераций.
После прохода первого цикла, у вас последовательно вызваются все IEnumerator, и они все отрабатывают. То есть все IEnumerator переходят в состояние конца итераций.
А затем, вы пытаетесь снова запустить все те же самые объекты IEnumerator сначала. Но они не могут запуститься сначала, потому что они в состоянии конца итераций. Оттого ваша корутина второй раз и не запускается.

Решение - либо создавать на каждом цикле новый объект IEnumerator, либо же вызывать метод Reset() у каждого экземпляра IEnumerator на каждом новом цикле (если ваша реализация IEnumerator поддерживает метод Reset).
Обратите внимание, если вы используете упрощенный синтаксис IEnumerator, то есть у вас просто метод типа IEnumerator, с yield внутри, то Reset не поддерживается для такого энумератора.
1
35 / 26 / 11
Регистрация: 30.01.2018
Сообщений: 169
16.03.2021, 19:10  [ТС]
Спасибо за объяснения, это многое проясняет. Reset() и вправду не поддерживается, костыль с присваиванием - ничего не вышло, он видимо и само состояние копирует. Свойство current только для чтения, его тоже не изменить. Насколько мне известно интерфейс Ienumerator создан для перебирания коллекций. Каким образом я могу переопределить Reset()?
0
 Аватар для 1max1
3362 / 1775 / 1028
Регистрация: 26.10.2018
Сообщений: 5,204
16.03.2021, 20:19
Лучший ответ Сообщение было отмечено Srgey1232 как решение

Решение

Ты можешь пихать в очередь не енумы, а лямбды, которые их каждый раз возвращают новыми.
Здесь в лог попадет два сообщения:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    void Start()
    {
        StartCoroutine(start());
    }
 
    IEnumerator start()
    {
        System.Func<IEnumerator> e = () => asd();
        StartCoroutine(e());
        yield return new WaitForSeconds(1.0f);
        StartCoroutine(e());
    }
 
    IEnumerator asd()
    {
        print(1);
        yield return null;
    }
Здесь только одно:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    void Start()
    {
        StartCoroutine(start());
    }
 
    IEnumerator start()
    {
        IEnumerator e = asd();
        StartCoroutine(e);
        yield return new WaitForSeconds(1.0f);
        StartCoroutine(e);
    }
 
    IEnumerator asd()
    {
        print(1);
        yield return null;
    }
1
35 / 26 / 11
Регистрация: 30.01.2018
Сообщений: 169
17.03.2021, 11:21  [ТС]
Благодарю за помощь. Это и вправду работает. Кому интересно, как я изменил скрипты, то вот код:

Сами коллекции:
C#
1
2
List<Func<AIPath, AIDestinationSetter, Transform, float, IEnumerator>> nativeQueueEnumerators = new  List<Func<AIPath, AIDestinationSetter, Transform, float, IEnumerator>>();
Queue<Func<AIPath, AIDestinationSetter, Transform, float,IEnumerator>> queueEnumerators        = new Queue<Func<AIPath, AIDestinationSetter, Transform, float,IEnumerator>>();
Добавление в очередь действий нпс при старте:
C#
1
2
3
4
5
6
7
8
Func< AIPath,AIDestinationSetter,Transform,float , IEnumerator> moveIe = (aipathh, setterr, target, time) => goToPoint(aipathh, setterr, target);
nativeQueueEnumerators.Add(moveIe);
 
Func<AIPath, AIDestinationSetter, Transform, float, IEnumerator> rotateIe = (aipathh, setterr, target, time) => rotateToTarget(setterr, target);
nativeQueueEnumerators.Add(rotateIe);  
            
Func<AIPath, AIDestinationSetter, Transform, float, IEnumerator> waitIe = (aipathh, setterr, target, time) => waitAFewMoment(setterr,time);
nativeQueueEnumerators.Add(waitIe);
Вызов действий:

C#
1
2
 
setter.StartCoroutine(queueEnumerators.Dequeue()(_aiPath, setter, _targets[_localCircle], _waitingTime));
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
17.03.2021, 11:21
Помогаю со студенческими работами здесь

Сделать так, чтобы программа работала с шестнадцатиричной системой
#include &lt;stdio.h&gt; #include &lt;stdlib.h&gt; #include &lt;conio.h&gt; #include &lt;time.h&gt; #include&lt;Windows.h&gt; #include&lt;assert.h&gt; ...

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

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

Рекурсия корутин
что будет если запускать из корутины снова туже самую корутину? запустившая по окончании исчезнет? точнее вопрос что с ней будет

Рекурсивный вызов корутин
Доброго времени суток! Подскажите, пожалуйста, как в корутине async_rec_dir_iter вызвать ее саму же? // Вызывает async_next до тех...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
7
Ответ Создать тему
Новые блоги и статьи
Загрузка PNG с альфа-каналом на SDL3 для Android: с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 28.01.2026
Содержание блога SDL3 имеет собственные средства для загрузки и отображения PNG-файлов с альфа-каналом и базовой работы с ними. В этой инструкции используется функция SDL_LoadPNG(), которая. . .
Загрузка PNG с альфа-каналом на SDL3 для Android: с помощью SDL3_image
8Observer8 27.01.2026
Содержание блога SDL3_image - это библиотека для загрузки и работы с изображениями. Эта пошаговая инструкция покажет, как загрузить и вывести на экран смартфона картинку с альфа-каналом, то есть с. . .
влияние грибов на сукцессию
anaschu 26.01.2026
Бифуркационные изменения массы гриба происходят тогда, когда мы уменьшаем массу компоста в 10 раз, а скорость прироста биомассы уменьшаем в три раза. Скорость прироста биомассы может уменьшаться за. . .
Воспроизведение звукового файла с помощью SDL3_mixer при касании экрана Android
8Observer8 26.01.2026
Содержание блога SDL3_mixer - это библиотека я для воспроизведения аудио. В отличие от инструкции по добавлению текста код по проигрыванию звука уже содержится в шаблоне примера. Нужно только. . .
Установка Android SDK, NDK, JDK, CMake и т.д.
8Observer8 25.01.2026
Содержание блога Перейдите по ссылке: https:/ / developer. android. com/ studio и в самом низу страницы кликните по архиву "commandlinetools-win-xxxxxx_latest. zip" Извлеките архив и вы увидите. . .
Вывод текста со шрифтом TTF на Android с помощью библиотеки SDL3_ttf
8Observer8 25.01.2026
Содержание блога Если у вас не установлены Android SDK, NDK, JDK, и т. д. то сделайте это по следующей инструкции: Установка Android SDK, NDK, JDK, CMake и т. д. Сборка примера Скачайте. . .
Использование SDL3-callbacks вместо функции main() на Android, Desktop и WebAssembly
8Observer8 24.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
моя боль
iceja 24.01.2026
Выложила интерполяцию кубическими сплайнами www. iceja. net REST сервисы временно не работают, только через Web. Написала за 56 рабочих часов этот сайт с нуля. При помощи perplexity. ai PRO , при. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru