21 / 16 / 7
Регистрация: 30.01.2018
Сообщений: 117
1

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

16.03.2021, 15:43. Показов 2123. Ответов 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)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
16.03.2021, 15:43
Ответы с готовыми решениями:

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

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

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

Сделать так, чтобы программа работала с шестнадцатиричной системой
#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;...

6
3002 / 1551 / 898
Регистрация: 26.10.2018
Сообщений: 4,437
16.03.2021, 16:09 2
C#
1
if (cor == null)
Условие не сработает никогда, так как там выкинет ошибку, либо Dequeue, если в очереди нет элементов, либо StartCoroutine, в который передается null. В остальных случаях всегда будет значение.
0
21 / 16 / 7
Регистрация: 30.01.2018
Сообщений: 117
16.03.2021, 17:17  [ТС] 3
Вы будете удивлены, но это условие срабатывает. И эта ситуация происходит: когда в очереди элементов становится 0, вызывается функция SetStartsValues(), где в очередь, опять добавляются элементы, после чего вызывается корутина , и этот вызов я присваиваю к cor, и когда это происходит, вызов корутины "доджится" и в cor записывается null. В этом и вопрос, - почему?
0
Эксперт .NETАвтор FAQ
10328 / 5059 / 1824
Регистрация: 11.01.2015
Сообщений: 6,226
Записей в блоге: 34
16.03.2021, 18:43 4
Цитата Сообщение от Srgey1232 Посмотреть сообщение
Дальше корутина не вызовется, не понятно почему, то есть cor будет равен null
Вот смотрите, вы создаете объекты типа IEnumerator и сохраняете в списке.
Объект IEnumerator имеет состояние. Он моожет находится в сосотянии начала итераций, в процессе итераций и в состоянии конца итераций.
После прохода первого цикла, у вас последовательно вызваются все IEnumerator, и они все отрабатывают. То есть все IEnumerator переходят в состояние конца итераций.
А затем, вы пытаетесь снова запустить все те же самые объекты IEnumerator сначала. Но они не могут запуститься сначала, потому что они в состоянии конца итераций. Оттого ваша корутина второй раз и не запускается.

Решение - либо создавать на каждом цикле новый объект IEnumerator, либо же вызывать метод Reset() у каждого экземпляра IEnumerator на каждом новом цикле (если ваша реализация IEnumerator поддерживает метод Reset).
Обратите внимание, если вы используете упрощенный синтаксис IEnumerator, то есть у вас просто метод типа IEnumerator, с yield внутри, то Reset не поддерживается для такого энумератора.
1
21 / 16 / 7
Регистрация: 30.01.2018
Сообщений: 117
16.03.2021, 19:10  [ТС] 5
Спасибо за объяснения, это многое проясняет. Reset() и вправду не поддерживается, костыль с присваиванием - ничего не вышло, он видимо и само состояние копирует. Свойство current только для чтения, его тоже не изменить. Насколько мне известно интерфейс Ienumerator создан для перебирания коллекций. Каким образом я могу переопределить Reset()?
0
3002 / 1551 / 898
Регистрация: 26.10.2018
Сообщений: 4,437
16.03.2021, 20:19 6
Лучший ответ Сообщение было отмечено 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
21 / 16 / 7
Регистрация: 30.01.2018
Сообщений: 117
17.03.2021, 11:21  [ТС] 7
Благодарю за помощь. Это и вправду работает. Кому интересно, как я изменил скрипты, то вот код:

Сами коллекции:
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
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
17.03.2021, 11:21
Помогаю со студенческими работами здесь

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

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

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

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

Разница запуска корутин
Чем отличаются эти 2 типа запуска? 1) StartCoroutine(&quot;cor&quot;); 2) StartCoroutine(cor());

Цепочка корутин из xml
Добрый день. Нужна помощь опытных программистов, так как сам работаю с C# недавно. Мне нужно из...


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

Или воспользуйтесь поиском по форуму:
7
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2022, CyberForum.ru