WaypointData getRandomWaypoint(int attempt = 0)
        {
            WaypointData waypoint = waypoints[Random.Range(0, waypoints.Count - 1)];

            // to avoid overlapping on spawn, check if current or nearest waypoints are already occupied
            if (waypoint.occupied || (waypoint.nextWaypoint != null && waypoint.nextWaypoint.occupied) || (waypoint.previousWaypoint != null && waypoint.previousWaypoint.occupied))
            {
                attempt++;

                if (attempt == maxAttempts)
                {
                    return(null);
                }

                return(getRandomWaypoint(attempt));
            }

            return(waypoint);
        }
 public void init(int direction, WaypointData startPoint)
 {
     this.direction  = direction;
     currentWaypoint = startPoint;
     SetDestination(currentWaypoint.position);
 }
        IEnumerator spawn()
        {
            int count    = 0;
            int attempts = 0;

            while (count < numberToSpawn)
            {
                WaypointData randomWaypoint = getRandomWaypoint();

                // seems like there are no available slots
                if (randomWaypoint == null)
                {
                    //Debug.Log("No available slots found for " + transform.name + " waiting a second");
                    attempts++;

                    if (attempts == maxAttempts)
                    {
                        //Debug.Log("No available slots found for " + transform.name + ", stopping spawner.");
                        break;
                    }

                    yield return(new WaitForSeconds(1));

                    continue;
                }
                // make sure this waypoint isn't reused for spawning more entities
                randomWaypoint.occupied = true;

                GameObject obj = Instantiate(prefabs[Random.Range(0, prefabs.Length)]);

                Vector3 spawnPosition = randomWaypoint.centerPosition;
                spawnPosition.y += 0.5f;

                obj.transform.position = spawnPosition;

                // Point spawned entities looking at their next waypoint
                Vector3 lookPos = spawnPosition;
                if (randomWaypoint.nextWaypoint != null)
                {
                    lookPos = randomWaypoint.nextWaypoint.centerPosition;
                }
                else if (randomWaypoint.previousWaypoint != null)
                {
                    lookPos = randomWaypoint.previousWaypoint.centerPosition;
                }

                lookPos.y = obj.transform.position.y;
                obj.transform.LookAt(lookPos);


                int direction;

                if (allowedDirection == Direction.Both)
                {
                    direction = Mathf.RoundToInt(Random.Range(0f, 1f));
                }
                else
                {
                    direction = (int)allowedDirection;
                }

                obj.GetComponent <WaypointNavigator>().init(direction, randomWaypoint);

                yield return(new WaitForEndOfFrame());

                count++;
            }

            if (optimizeOnRuntime && (!Application.isEditor || (Application.isEditor && optimizeOnEditorToo)))
            {
                removeWaypointsGameobjects();
            }
        }
        public void getNextWaypoint()
        {
            bool shouldBranch = false;

            // dont give a new waypoint if current one has a stopper and it's not an exit point (100% ratio)
            if (currentWaypoint.branchRatio < 1f && currentWaypoint.relatedSemaphore != null && currentWaypoint.relatedSemaphore.getStatus(currentWaypoint) == Semaphore.Status.Red)
            {
                return;
            }

            currentWaypoint.occupied = false;

            if (currentWaypoint.branches != null && currentWaypoint.branches.Count > 0)
            {
                // handle situations when developer left a path with a branch and no direct continuity
                if ((direction == 0 && currentWaypoint.nextWaypoint == null) || (direction == 1 && currentWaypoint.previousWaypoint == null))
                {
                    shouldBranch = true;
                }
                else
                {
                    shouldBranch = Random.Range(0f, 1f) <= currentWaypoint.branchRatio ? true : false;
                }
            }

            if (shouldBranch)
            {
                currentWaypoint = currentWaypoint.branches[Random.Range(0, currentWaypoint.branches.Count - 1)];
            }
            else
            {
                if (direction == 0)
                {
                    if (currentWaypoint.nextWaypoint != null)
                    {
                        currentWaypoint = currentWaypoint.nextWaypoint;
                    }
                    else
                    {
                        currentWaypoint = currentWaypoint.previousWaypoint;
                        direction       = 1;
                    }
                }
                else
                {
                    if (currentWaypoint.previousWaypoint != null)
                    {
                        currentWaypoint = currentWaypoint.previousWaypoint;
                    }
                    else
                    {
                        currentWaypoint = currentWaypoint.nextWaypoint;
                        direction       = 0;
                    }
                }
            }

            currentWaypoint.occupied = true;

            SetDestination(currentWaypoint.singleDirection ? currentWaypoint.centerPosition : currentWaypoint.position);
        }