Not All Code Paths Returns a Vaalue

Форум для самых маленьких, а так же тех, кому недосуг читать справку самостоятельно.

Not All Code Paths Returns a Vaalue

Сообщение DimaJoke 23 фев 2019, 17:54

Здравствуйте, форумчане!
Реализовываю вот алгоритм поиска пути для ИИ с использованием узлов.
У каждого узла есть свой ID.
Юнит должен получить массив int[], где будут ID узлов, которые он должен пройти.
Вот код, с которым у меня проблема
Синтаксис:
Используется csharp
public int[] Way(int Start, int End)
        {
       
                //Все объекты узлов
                GameObject[] AllNodesObjects = GameObject.FindGameObjectsWithTag("Node");

               

                // неотсортированный список узлов
                Node[] AllNodes = new Node[AllNodesObjects.Length];

               

                // заполняем список!
                for(int i = 0; i < AllNodesObjects.Length; i++)
                {
                        AllNodes[i] = AllNodesObjects[i].GetComponent<Node>();
                }

                //отсортированный список
                Node[] Nodes = new Node[AllNodes.Length];

                //Сортировка
                for(int i = 0; i < AllNodes.Length; i++)
                {
                        Nodes[AllNodes[i].ID] = AllNodes[i];
                }
                //Мы получили отсортированный массив узлов. начинаем поиск пути.

                if(Nodes[End].gameObject.GetComponent<EndNode>() == null)
                {
                        Nodes[Start].IsChecked = true;
                        Nodes[Start].CheckNearest();
                        EndNode EN = Nodes[End].gameObject.AddComponent<EndNode>();

                        if(!Stop)
                        {
                                if(EN.EndFind)
                                {
                                        return EN.Way;
                                }
                        }

                        else
                        {
                                return nullArr;
                        }
                }

                else
                {
                        return nullArr;
                }

        }

        IEnumerator WaitForStopFind()
        {
                yield return new WaitForSeconds(10f);
                Stop = true;
        }
 

Проблема в том, что поиск пути будет идти несколько кадров, а этот метод должен вернуть всё за один кадр.
Я понимаю, что нужно использовать корутины, но понятия не имею, как...
Что бы повзрослеть, человек должен преодолеть ошибки юности.

Поэтому я снова здесь..
Аватара пользователя
DimaJoke
UNITрон
 
Сообщения: 293
Зарегистрирован: 12 авг 2018, 18:59
Откуда: Ульяновск
  • Сайт

Re: Not All Code Paths Returns a Vaalue

Сообщение Xtir 23 фев 2019, 19:02

в самом конце нужно return добавить
Xtir
UNIверсал
 
Сообщения: 498
Зарегистрирован: 21 окт 2016, 00:37

Re: Not All Code Paths Returns a Vaalue

Сообщение DimaJoke 23 фев 2019, 19:15

а что возвращать?
Что бы повзрослеть, человек должен преодолеть ошибки юности.

Поэтому я снова здесь..
Аватара пользователя
DimaJoke
UNITрон
 
Сообщения: 293
Зарегистрирован: 12 авг 2018, 18:59
Откуда: Ульяновск
  • Сайт

Re: Not All Code Paths Returns a Vaalue

Сообщение Cr0c 23 фев 2019, 19:30

DimaJoke писал(а):а что возвращать?

null или пустой массив )) но это фигня. Поиск пути чем делается? Почему поиск пути не отдаёт готовый путь? Я вчера А* изучал и написал свой для генерации дорог в сетке, так у меня 25х25 поле 10 дорог считаются и спавнятся за 3-5 секунд, с учётом генерации домов и земли на всей площади.
Аватара пользователя
Cr0c
Адепт
 
Сообщения: 3035
Зарегистрирован: 19 июн 2015, 13:50
Skype: cr0c81

Re: Not All Code Paths Returns a Vaalue

Сообщение DimaJoke 23 фев 2019, 20:09

Cr0c писал(а):
DimaJoke писал(а):а что возвращать?

null или пустой массив )) но это фигня. Поиск пути чем делается? Почему поиск пути не отдаёт готовый путь? Я вчера А* изучал и написал свой для генерации дорог в сетке, так у меня 25х25 поле 10 дорог считаются и спавнятся за 3-5 секунд, с учётом генерации домов и земли на всей площади.

У меня немного по другому ИИ работает. Ну во первых это 2Д платформер, ИИ тут ходят по узлам, которые установлены возле дверей, лестниц и пр. Стратегически важных объектах.

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

Поэтому я снова здесь..
Аватара пользователя
DimaJoke
UNITрон
 
Сообщения: 293
Зарегистрирован: 12 авг 2018, 18:59
Откуда: Ульяновск
  • Сайт

Re: Not All Code Paths Returns a Vaalue

Сообщение Cr0c 23 фев 2019, 21:57

Зачем такой ужас - вагон GetComponent, FindObjectsOfType? Почему при старте сцены не спихнуть всё в кеш контроллера и уже в нём искать? Почему нодам самим не регистрироваться (для исключения поиска и гет компонентов)? А при регистрации собирать структуры в ноды со всеми данными (трансформы, компоненты, etc)...
Аватара пользователя
Cr0c
Адепт
 
Сообщения: 3035
Зарегистрирован: 19 июн 2015, 13:50
Skype: cr0c81

Re: Not All Code Paths Returns a Vaalue

Сообщение DimaJoke 24 фев 2019, 11:14

в итоге нифига не работает.

Если я возвращаю null или nullArray то он возвращается и всё. Я получаю на объекте нулевой массив.
Сам массив уже есть на компоненте EndNode, но я не могу его получить.
Что бы повзрослеть, человек должен преодолеть ошибки юности.

Поэтому я снова здесь..
Аватара пользователя
DimaJoke
UNITрон
 
Сообщения: 293
Зарегистрирован: 12 авг 2018, 18:59
Откуда: Ульяновск
  • Сайт

Re: Not All Code Paths Returns a Vaalue

Сообщение Ziza 24 фев 2019, 11:51

Ну так зачит условие:
Синтаксис:
Используется csharp
                if(Nodes[End].gameObject.GetComponent<EndNode>() == null)
                {
                        Nodes[Start].IsChecked = true;
                        Nodes[Start].CheckNearest();
                        EndNode EN = Nodes[End].gameObject.AddComponent<EndNode>();
                        if(!Stop)
                        {
                                if(EN.EndFind)
                                {
                                        return EN.Way;
 

Не срабатывает, а почему - кто ж его знает) Поставьте точки и посмотрите в дебаге.

А как у вас, кстати так получается, что вы только добавили новый компонент:
Синтаксис:
Используется csharp
EndNode EN = Nodes[End].gameObject.AddComponent<EndNode>();

и прямо тут же проверяете Stop и новый компонент на if(EN.EndFind) и возвращаете EN.Way. Что-то мне подсказывает, что он всегда будет пуст.
Эти внутренние условия на проверку Stop, EN.EndFind и возврат его EN.Way точно должны быть в той ветке где вы его добавляете, а не наоборот?
Аватара пользователя
Ziza
UNIт
 
Сообщения: 81
Зарегистрирован: 02 ноя 2018, 23:07

Re: Not All Code Paths Returns a Vaalue

Сообщение DimaJoke 24 фев 2019, 12:19

Ziza писал(а):Ну так зачит условие:
Синтаксис:
Используется csharp
                if(Nodes[End].gameObject.GetComponent<EndNode>() == null)
                {
                        Nodes[Start].IsChecked = true;
                        Nodes[Start].CheckNearest();
                        EndNode EN = Nodes[End].gameObject.AddComponent<EndNode>();
                        if(!Stop)
                        {
                                if(EN.EndFind)
                                {
                                        return EN.Way;
 

Не срабатывает, а почему - кто ж его знает) Поставьте точки и посмотрите в дебаге.

А как у вас, кстати так получается, что вы только добавили новый компонент:
Синтаксис:
Используется csharp
EndNode EN = Nodes[End].gameObject.AddComponent<EndNode>();

и прямо тут же проверяете Stop и новый компонент на if(EN.EndFind) и возвращаете EN.Way. Что-то мне подсказывает, что он всегда будет пуст.
Эти внутренние условия на проверку Stop, EN.EndFind и возврат его EN.Way точно должны быть в той ветке где вы его добавляете, а не наоборот?

Мне и нужно что бы массив Way возвращался только после того, когда булево EN.EndFind будет равен true, но это не успевает происходить. Метод возвращает значение в тот же кадр, а EN.EndFind становится true лишь после 5-30 кадров.
Что бы повзрослеть, человек должен преодолеть ошибки юности.

Поэтому я снова здесь..
Аватара пользователя
DimaJoke
UNITрон
 
Сообщения: 293
Зарегистрирован: 12 авг 2018, 18:59
Откуда: Ульяновск
  • Сайт

Re: Not All Code Paths Returns a Vaalue

Сообщение Ziza 24 фев 2019, 12:35

Ну так я и говорю, поэтому и не успевает)
По всей видимости вы хотели написать что то типа:
Синтаксис:
Используется csharp
        public int[] Way(int start, int end)
        {
            var nodes = GameObject.FindObjectsOfType<Node>();
            Array.Sort(nodes, (x, y) => x.ID.CompareTo(y.ID));
            var endNode = nodes[end].GetComponent<EndNode>();
            if (endNode == null)
            {
                nodes[start].IsChecked = true;
                nodes[start].CheckNearest();
                nodes[end].gameObject.AddComponent<EndNode>();
            }
            else
            {
                if (endNode.EndFind)
                    return endNode.Way;
            }

            return null;
        }
 

Т.е. метод будет возвращать null до тех пор пока путь не будет найден. Не проверялось, но теоретически должно работать)
P.S. А вообще это как-то опасно выглядит - считать, что ID нодов всегда будут совпадать с индексами отсортированного массива, мало ли что пойдет не так...
Аватара пользователя
Ziza
UNIт
 
Сообщения: 81
Зарегистрирован: 02 ноя 2018, 23:07

Re: Not All Code Paths Returns a Vaalue

Сообщение DimaJoke 24 фев 2019, 13:25

Дело в том, что к этому методу могут обращаться несколько объектов. значение start будет разное, а end одинаковое, тогда всем выдадут одинаковые маршруты и произойдёт вакханалия..
Я решил немного переделать. Из Метода я сделал Функцию, в которую в качестве аргумента отправляется копия класса, в котором есть массив Way. Отправлять после нескольких секунд. с помощью корутины. Получилось как-то так:
Синтаксис:
Используется csharp
public void Way(int Start, int End, AIWayMananger AI)
        {
       
                //Все объекты узлов
                GameObject[] AllNodesObjects = GameObject.FindGameObjectsWithTag("Node");

               

                // неотсортированный список узлов
                Node[] AllNodes = new Node[AllNodesObjects.Length];

               

                // заполняем список!
                for(int i = 0; i < AllNodesObjects.Length; i++)
                {
                        AllNodes[i] = AllNodesObjects[i].GetComponent<Node>();
                }

               

                //Сортировка
                for(int i = 0; i < AllNodes.Length; i++)
                {
                        Nodes.Add(AllNodes[i].ID, AllNodes[i]);
                }
                //Мы получили отсортированный словарь узлов. начинаем поиск пути.

                if(Nodes[End].gameObject.GetComponent<EndNode>() == null)
                {

                        Nodes[Start].IsChecked = true;
                        Nodes[Start].CheckNearest();
                        Nodes[Start].gameObject.AddComponent<StarterNode>();
                        EndNode EN = Nodes[End].gameObject.AddComponent<EndNode>();
                        StartCoroutine(ReturnWay(AI, EN));     
               
                }
        }

        IEnumerator ReturnWay(AIWayMananger AI, EndNode EN)
        {
                yield return new WaitForSeconds(1f);
                AI.Way = EN.Way;
                Destroy(EN);
        }
 



Основной скрипт AI, висящий на юните будет вызывать метод FindWay(), который находится в скрипте AIWayMananger, который выглядит примерно так:

Синтаксис:
Используется csharp
public class AIWayMananger : MonoBehaviour
{
   public int[] Way;
   public int StartN;
   public int End;

   public void FindWay()
   {
                GameObject.FindObjectsOfType<FindWay>[0].GetComponent<FindWay>().Way(StartN, End, this);

   }

   void Start()
   {
        FindWay();
   }

}
 


и.. всё работает...
Что бы повзрослеть, человек должен преодолеть ошибки юности.

Поэтому я снова здесь..
Аватара пользователя
DimaJoke
UNITрон
 
Сообщения: 293
Зарегистрирован: 12 авг 2018, 18:59
Откуда: Ульяновск
  • Сайт

Re: Not All Code Paths Returns a Vaalue

Сообщение Ziza 24 фев 2019, 13:47

Но ведь сейчас у вас если два юнита запросят путь с одним значением End одновременно, то путь создастся только для первого запросившего.
Надо получается убирать условие
Синтаксис:
Используется csharp
if(Nodes[End].gameObject.GetComponent<EndNode>() == null)

и вешать для каждого запросившего по компоненту.
И видимо имеет смысл вынести поиск нодов и сортировку словаря отдельно и вызывать только один раз в начале и при добавлении новых нодов. А то сейчас расточительно получается.

P.S. Вы кстати можете свою инструкцию для корутины написать, там три строчки кода и ждать действительно когда путь найдется, а не надеяться на магическую секунду :)
Синтаксис:
Используется csharp
public class WaitForFindPath : CustomYieldInstruction
{
    private EndNode _endNode;
   
    public WaitForFindPath(EndNode node)
    {
        _endNode = node;
    }

    public override bool keepWaiting
    {
        get { return !_endNode.EndFind;  }
    }
}
Аватара пользователя
Ziza
UNIт
 
Сообщения: 81
Зарегистрирован: 02 ноя 2018, 23:07

Re: Not All Code Paths Returns a Vaalue

Сообщение Cr0c 25 фев 2019, 10:38

DimaJoke писал(а):в итоге нифига не работает.

Если я возвращаю null или nullArray то он возвращается и всё. Я получаю на объекте нулевой массив.
Сам массив уже есть на компоненте EndNode, но я не могу его получить.

Убери все геткомпонент, сделай класс поиска, регистрируй в нём все ноды с координатами и ребрами. Тогда поиск пути будут очень быстрым и без лишних телодвижений. Введение в алгоритм A* - разобраться просто.
Аватара пользователя
Cr0c
Адепт
 
Сообщения: 3035
Зарегистрирован: 19 июн 2015, 13:50
Skype: cr0c81


Вернуться в Почемучка

Кто сейчас на конференции

Сейчас этот форум просматривают: Google [Bot] и гости: 25