示例#1
0
    /**
     * Déclenche (via une coroutine) le mouvement du transporteur vers la maison la
     * plus proche (sur le réseau routier), où il sera détruit (utile pour se
     * débarrasser des transporteurs dont le bâtiment principal est détruit).
     * Le stock sera alors perdu. Si aucune maison n'est disponible, le
     * transporteur ne bouge pas, et la coroutine va continuer d'attendre une
     * maison vers laquelle se rendre.
     **/
    private IEnumerator GoHome()
    {
        RoadRouteManager roadRouteManager = GetComponent <RoadRouteManager>();

        while (true)
        {
            //TODO utiliser un findNearestObjectWithPath (Utils) pour être plus générique.
            GameObject[] homesArray = GameObject.FindGameObjectsWithTag("Home");

            float         minDistance   = 0.0f;
            FreightAreaIn nearestHomeIn = null;
            foreach (GameObject home in homesArray)
            {
                FreightAreaIn homeIn = home.GetComponent <BuildingStock>().freightAreaData.freightAreaIn;

                float distance = RoadsPathfinding.RealDistanceBetween(homeIn.road, roadRouteManager.occupiedRoad);
                if (distance > 0.0f && (nearestHomeIn == null || minDistance > distance))
                {
                    minDistance   = distance;
                    nearestHomeIn = homeIn;
                }
                yield return(null);
            }

            if (nearestHomeIn != null)//Sinon, c'est qu'il n'y a AUCUNE maison satisfaisante, et la boucle principale se charge de relancer la recherche
            {
                destination = nearestHomeIn.GetComponentInParent <BuildingStock>();
                roadRouteManager.MoveTo(destination.freightAreaData.freightAreaIn.road, Random.Range(0.5f, 3.0f), null);
                yield break;
            }

            yield return(null);
        }
    }
示例#2
0
    private IEnumerator SortAvailableKeepAsideOrderManagersByDistance(Cell <PriorityQueue <float, KeepAsideOrderManager> > rslt)
    {
        StockManager stockManager = GameManager.instance.cityBuilderData.stockManager;

        PriorityQueue <float, KeepAsideOrderManager> rsltQueue           = new PriorityQueue <float, KeepAsideOrderManager>();
        IEnumerator <KeepAsideOrderManager>          keepAsideEnumerator = stockManager.AllKeepAsideOrderManagers();

        while (keepAsideEnumerator.MoveNext())
        {
            KeepAsideOrderManager keepAsideManager = keepAsideEnumerator.Current;

            if (keepAsideManager != null)//On vérifie s'il n'a pas été détruit
            {
                float distance = Vector2.Distance(transform.position, keepAsideManager.transform.position);

                if (distance <= keepAsideManager.availabilityRange)//Pour éviter les calculs inutiles ; si ce n'est pas le cas, il est de toute façon trop loin
                {
                    FreightAreaIn  inArea  = keepAsideManager.freightAreaData.freightAreaIn;
                    FreightAreaOut outHome = freightAreaData.freightAreaOut;

                    float roadDistance = RoadsPathfinding.RealDistanceBetween(inArea.road, outHome.road);

                    if (roadDistance > 0.0f && roadDistance <= keepAsideManager.availabilityRange)
                    {
                        rsltQueue.Push(roadDistance, keepAsideManager);
                    }
                }
            }

            yield return(null);
        }

        rslt.value = rsltQueue;
    }
示例#3
0
    /**
     * Coroutine à lancer pour trier selon leur distance (sur le réseau
     * routier) à cette route les bâtiments capable de recevoir des commandes.
     **/
    public IEnumerator SortOrderManagersByDistance(Cell <PriorityQueue <float, OrderManager> > rslt)
    {
        PriorityQueue <float, OrderManager> rsltQueue = new PriorityQueue <float, OrderManager>();
        StockManager stockManager = GameManager.instance.cityBuilderData.stockManager;
        IEnumerator <OrderManager> allOrderManagers = stockManager.AllOrderManagers();

        while (allOrderManagers.MoveNext())
        {
            OrderManager orderManager = allOrderManagers.Current;

            if (orderManager != null)
            {
                float realDistanceToOrderManager = RoadsPathfinding.RealDistanceBetween(this, orderManager.freightAreaData.freightAreaOut.road);
                if (realDistanceToOrderManager > 0.0f)
                {
                    rsltQueue.Push(realDistanceToOrderManager, orderManager);
                }
            }

            yield return(null);
        }

        rslt.value = rsltQueue;

        yield return(null);
    }
    public static float RealDistanceBetween(RoadData start, RoadData goal)
    {
        SearchData       searchData = new SearchData(goal, start, 4, Orientation.SOUTH);//TODO Le 4 est ici totalement arbitraire, il n'est pas utilisé. + Orientation a définir en fonction de celle du bâtiment.
        Stack <RoadData> path       = RoadsPathfinding.AStar(searchData, -1, RouteStarNeighborhood, RouteStarCost, RouteStarRebuild, RouteStarGoal);

        return(path == null ? -1.0f : (float)path.Count);
    }
    private IEnumerator MoveToWithMultipleTries(RoadData destination, float delay, RetryData retryData)
    {
        if (delay > 0.0f)
        {
            yield return(new WaitForSeconds(delay));
        }

        string currentOrientation = _moveManager.orientation;

        Stack <RoadData> moveKeyPoints = null;
        int tries = 0;

        while (moveKeyPoints == null)
        {
            if (tries > 0)
            {
                yield return(new WaitForSeconds(UnityEngine.Random.Range(0.5f, 3.0f)));
            }
            moveKeyPoints = RoadsPathfinding.RouteStar(destination, occupiedRoad, _keyPointsModulo, currentOrientation);

            tries++;
        }

        _moveManager.Move(FollowMoveKeyPoints(moveKeyPoints, destination, retryData));
    }
示例#6
0
    private IEnumerator SendWaitingCarriers()
    {
        while (true)
        {
            if (_waitingCarriers.Count > 0 && road.roadLock.IsFree(Orientation.SOUTH))//TODO orientation
            {
                ResourceCarrier candidate      = _waitingCarriers.Dequeue();
                ResourceCarrier firstCandidate = candidate;
                bool            firstOk        = true;

                while (RoadsPathfinding.RouteStar(road, candidate.destination.freightAreaData.freightAreaIn.road, 10, Orientation.SOUTH) == null && firstCandidate != candidate)//TODO orientation (et attention avec in/out :/)
                {
                    firstOk = false;
                    _waitingCarriers.Enqueue(candidate);
                    candidate = _waitingCarriers.Dequeue();

                    yield return(new WaitForSeconds(0.1f));
                }//TODO ATTENTION: la boucle ci-dessus veut dire que si le joueur fait n'importe quoi et coupe des chemins partout, la taille de la file va augmenter alors que des transporteurs y restent coincés!!!! Du coup, au moins mettre un genre de message d'erreur pourrait être sympa.==> TODO attention aussi au cas des destruction: que deviennent les carriers qui devaient aller à un bâtiment qui n'existe plus ? Comparer avec null pour vérifier que pas détruits ??? OK sur les children ?

                if (firstOk || firstCandidate != candidate)//Donc, on a trouvé un transporteur à envoyer
                {
                    candidate.transform.position = new Vector3(road.transform.position.x, road.transform.position.y, candidate.transform.position.z);
                    MoveManager candidateMoveManager = candidate.GetComponent <MoveManager>();
                    candidateMoveManager.orientation = Orientation.SOUTH;//TODO orientation
                    candidate.GetComponent <RoadRouteManager>().occupiedRoad = road;
                    road.roadLock.LockFor(candidateMoveManager.orientation, candidate.gameObject);
                    candidate.GetComponent <Collider2D>().enabled = true;
                    candidate.GetComponent <RoadRouteManager>().MoveTo(candidate.destination.freightAreaData.freightAreaIn.road);
                }
            }

            yield return(new WaitForSeconds(0.5f));
        }
    }
示例#7
0
    public IEnumerator goOnTour(List <GameObject> toVisit)
    {
        if (prefecture != null)
        {
            List <GameObject> toReVisit = new List <GameObject>();
            toVisit.Remove(prefecture);
            _tour = TSP.GetItinary(prefecture, toVisit);
            GameObject _currentDestination;
            while (!_tour.IsEmpty())
            {
                _continueTour        = false;
                _tryAgainToVisitHome = 50;

                _currentDestination = _tour.Pop();
                goalFA = _currentDestination.GetComponentInChildren <FreightAreaIn>();
                if (goalFA != null && RoadsPathfinding.RealDistanceBetween(GetComponent <RoadRouteManager>().occupiedRoad, goalFA.road) != -1)
                //Il existe encore une route vers ce batiment
                {
                    GetComponent <RoadRouteManager>().MoveTo(goalFA.road);
                    yield return(new WaitUntil(() => _continueTour || goalFA == null || gameObject.GetComponent <RoadRouteManager>().occupiedRoad == goalFA.road));

                    if (goalFA != null && _continueTour)//On a pas pu atteindre la maison et on a choisi de la skipper
                    {
                        toReVisit.Add(goalFA.gameObject);
                    }
                    if (goalFA != null && !_continueTour)
                    {
                        Building building = _currentDestination.GetComponent <Building>();
                        if (building != null)
                        {
                            building.RestoreHealth();
                        }
                        GetComponent <SpriteRenderer>().enabled = false;//TODO il est toujours sur la FA et donc le lock est toujours activé !
                        yield return(new WaitForSeconds(Random.Range(2.0f, 5.0f)));

                        GetComponent <SpriteRenderer>().enabled = true;
                    }
                }
            }
            if (toReVisit.Count != 0 && _trytoRevisitCount-- != 0)
            {
                StartCoroutine(goOnTour(toReVisit));
            }
            else
            {
                StartCoroutine(GoBack());
            }
        }
    }
示例#8
0
    /**
     * Coroutine à lancer pour effectuer une recherche parmi les entrepôts disponibles
     * quel est le plus proche remplissant une condition donnée. Pour les calculs
     * de distance, ce sont ici les freight area d'ENTREE (in) qui sont utilisées, ATTENTION!
     **/
    public static IEnumerator FindNearestWarehouseSatisfyingCondition(RoadData startPoint, Func <Warehouse, bool> acceptanceFunction, Cell <Warehouse> rslt, HashSet <FreightAreaIn> toIgnore)
    {
        PriorityQueue <float, Warehouse> sortedWarehouses = new PriorityQueue <float, Warehouse>();
        IEnumerator <Warehouse>          allWarehouses    = GameManager.instance.cityBuilderData.stockManager.AllWarehouses();

        while (allWarehouses.MoveNext())
        {
            Warehouse warehouse = allWarehouses.Current;

            if (warehouse != null)// Car il peut avoir été détruit depuis le début de la coroutine !
            {
                FreightAreaIn warehouseIn = warehouse.orderManager.freightAreaData.freightAreaIn;
                if (!toIgnore.Contains(warehouseIn) && acceptanceFunction(warehouse))
                {
                    float distanceToWarehouse = Vector2.Distance(warehouseIn.transform.position, startPoint.transform.position);
                    sortedWarehouses.Push(distanceToWarehouse, warehouse);
                }
            }
        }

        if (!sortedWarehouses.IsEmpty())
        {
            Warehouse bestWarehouse = sortedWarehouses.Pop();
            float     pathDistance  = RoadsPathfinding.RealDistanceBetween(startPoint, bestWarehouse.orderManager.freightAreaData.freightAreaIn.road);

            yield return(null);

            while (!sortedWarehouses.IsEmpty() && (pathDistance > sortedWarehouses.LowestKey() || pathDistance < 0.0f))
            {
                Warehouse nearestAsTheCrowFlies = sortedWarehouses.Pop();
                float     newPathDistance       = RoadsPathfinding.RealDistanceBetween(startPoint, nearestAsTheCrowFlies.orderManager.freightAreaData.freightAreaIn.road);
                if (newPathDistance >= 0.0f && (newPathDistance < pathDistance || pathDistance < 0.0f))
                {
                    pathDistance  = newPathDistance;
                    bestWarehouse = nearestAsTheCrowFlies;
                }
                yield return(null);
            }

            if (pathDistance >= 0.0f)
            {
                rslt.value = bestWarehouse;
            }
        }
    }
示例#9
0
    //TODO faire une version avec une co-routine plus efficace (un pathfinding/frame)
    public static GameObject GetNearestObjectWithPath(RoadData origin, string tag, HashSet <GameObject> exclude)
    {
        GameObject[] objectsWithTag = GameObject.FindGameObjectsWithTag(tag);
        float        minDistance    = Mathf.Infinity;
        GameObject   nearest        = null;

        foreach (GameObject nearObject in objectsWithTag)
        {
            RoadData destinationRoadData = nearObject.GetComponentInChildren <FreightAreaIn>() == null ? null : nearObject.GetComponentInChildren <FreightAreaIn>().road;
            if (destinationRoadData != null && (exclude == null || (exclude != null && !exclude.Contains(nearObject))))
            {
                float distance = RoadsPathfinding.RealDistanceBetween(destinationRoadData, origin);

                if (distance != -1.0f && distance < minDistance)
                {
                    minDistance = distance;
                    nearest     = nearObject;
                }
            }
        }
        return(nearest);
    }
示例#10
0
    //TODO pour l'instant, pas de TSP, c'est un algo qui établi un itinéraire en prenant à chaque fois le gameObject le plus proche à vol d'oiseau du précédent.

    /**
     * Pré : origin doit avoir un RoadData
     * */
    public static PriorityQueue <int, GameObject> GetItinary(GameObject origin, List <GameObject> toVisit)
    {
        PriorityQueue <int, GameObject> rslt = new PriorityQueue <int, GameObject>();


        GameObject previous = origin;
        int        i        = 0;

        while (toVisit.Count > 0)
        {
            GameObject nearest = GetNearestObject(previous, toVisit);

            if (previous.GetComponentInChildren <RoadData>() != null &&
                nearest.GetComponentInChildren <RoadData>() != null &&
                RoadsPathfinding.RealDistanceBetween(previous.GetComponentInChildren <RoadData>(), nearest.GetComponentInChildren <RoadData>()) != -1)//On checke qu'il y a quand même bien un passage
            {
                rslt.Push(i, nearest);
                previous = nearest;
                i++;
            }
            toVisit.Remove(nearest);
        }
        return(rslt);
    }
示例#11
0
    public bool SendOrderIfPossible()
    {
        FreightAreaOut freightOut = freightAreaData.freightAreaOut;

        if (freightAreaData.availableCarriers > 0 && OrdersToTreat() && freightOut.road.roadLock.IsFree(Orientation.SOUTH))//TODO orientation (opposée à celle du bâtiment)
        {
            ResourceOrder toTreat = NextOrder();

            FreightAreaIn destinationIn = toTreat.deliveryPlace.freightAreaData.freightAreaIn;
            if (RoadsPathfinding.RouteStar(destinationIn.road, freightOut.road, 10, Orientation.SOUTH) != null)//TODO orientation
            {
                MarkAsTreated(toTreat);
                freightAreaData.SendCarrier(toTreat.deliveryPlace, Orientation.SOUTH, toTreat.shipment);//TODO orientation (opposée à celle du bâtiment)

                return(true);
            }
            else //Si la destination n'est pas raccordée au réseau routier, on annule sa commande et on l'en notifie
            {
                toTreat.deliveryPlace.freightAreaData.parentStock.GetComponent <ResourceConsumer>().CancelResourceOrder(toTreat.shipment);
            }
        }

        return(false);
    }
示例#12
0
    private IEnumerator <MoveDescriptor> FollowMoveKeyPoints(Stack <RoadData> moveKeyPoints, RoadData finalDestination, RetryData retryData)
    {
        RoadData lastKeyPoint = occupiedRoad;

        foreach (RoadData keyPoint in moveKeyPoints)
        {
            if (keyPoint != null && keyPoint.Neighbors().Contains(occupiedRoad))
            {
                AnticipateNextOrientation(occupiedRoad, keyPoint, _moveManager.orientation);
            }

            RoadData lastRoad = occupiedRoad;
            while (occupiedRoad != keyPoint)
            {
                string           currentOrientation = _moveManager.orientation;
                Stack <RoadData> roadPath           = RoadsPathfinding.RoadPathStar(keyPoint, occupiedRoad, _keyPointsModulo, currentOrientation, finalDestination);

                if (roadPath == null)//On annule cet énumérateur et on relance la recherche
                {
                    if (retryData == null)
                    {
                        retryData = new RetryData(lastKeyPoint, finalDestination);
                    }

                    retryData.IncrementCounter();

                    _moveManager.CancelMove();

                    if (retryData.triesCounter == MAX_MOVE_TRIES)
                    {
                        onStuckEvent.Invoke(retryData);
                    }
                    else
                    {
                        MoveTo(finalDestination, UnityEngine.Random.Range(0.25f, 1.5f), retryData); //Ce qui relance donc une coroutine qui va s'occuper de ça!
                    }
                    yield break;
                }
                else if (roadPath.Count == 0)
                {
                    break; //Si le roadPath est vide, c'est qu'on est déjà à destination, ou suffisamment proche de celle-ci pour passer au prochain keyPoint
                }

                RoadData nextRoad = roadPath.Pop();

                if (nextRoad != lastRoad || UnityEngine.Random.Range(1, 100) == 1)
                {
                    foreach (RoadData toReserve in roadPath)
                    {
                        toReserve.roadLock.reservationsNber++;
                    }

                    MoveDescriptor toApply = new MoveDescriptor(nextRoad.transform.position, occupiedRoad.transform.position, speed, 0.1f);

                    string orientationToUnlock = currentOrientation;

                    if (MovementWithoutUnshift(occupiedRoad.roadLock, currentOrientation, toApply))//Partage la case avec un autre dans une orientation contraire
                    {
                        _moveManager.UseShiftForMovement(toApply);
                    }
                    else if (occupiedRoad.roadLock.split != RoadLock.DIAGONAL_SPLIT)//!NoNeedToRelock())
                    {
                        occupiedRoad.roadLock.UnlockFor(currentOrientation, gameObject);
                        occupiedRoad.roadLock.LockFor(toApply.orientation, gameObject);
                        orientationToUnlock = toApply.orientation;
                    }

                    nextRoad.roadLock.LockFor(toApply.orientation, gameObject);
                    //+++++> C'est la ligne ci-dessus qui est chiante: avec un diag split, on risque de relocker dans la mme direction que le contenu principal...>TROUVER UNE SOLUTION
                    //>>>> cas de double split à gérer via une condition spéciale (offre spéciale, SUPER PROMO) dans le RoadLock (avec qques var globales :/)

                    yield return(toApply);

                    lastRoad = occupiedRoad;
                    occupiedRoad.roadLock.UnlockFor(orientationToUnlock, gameObject);
                    occupiedRoad = nextRoad;

                    foreach (RoadData toFree in roadPath)
                    {
                        toFree.roadLock.reservationsNber--;
                    }

                    if (roadPath.Count != 0)//Donc, s'il y a encore une case sur laquelle bouger par la suite jusqu'au prochain keypoint
                    {
                        RoadData secondNextRoad = roadPath.Pop();
                        AnticipateNextOrientation(nextRoad, secondNextRoad, toApply.orientation);
                    }
                }
                else
                {
                    yield return(null);
                }
            }

            lastKeyPoint = keyPoint;
        }

        yield return(null);
    }
示例#13
0
    /**
     * Coroutine se chargeant d'envoyer tout ce qui a été produit par le bâtiment
     * et se trouve contenu dans son stock à l'entrepôt le plus proche capable
     * de l'accueillir ou à un bâtiment l'ayant commandé. Tout cela se voit bien
     * entendu diviser entre les transporteurs
     * disponibles pour le bâtiment.
     **/
    private IEnumerator ManageProductionStorage()
    {
        FreightAreaData freightData = orderManager.freightAreaData;

        while (true)
        {
            if (!orderManager.SendOrderIfPossible() && !orderManager.OrdersToTreat() && _warehouseOrders.Count > 0)//L'appel à la méthode envoie une commande si elle retourne true, d'où l'aspect un peu étrange de la condition
            {
                ResourceOrder    warehouseOrder = _warehouseOrders.Dequeue();
                ResourceShipment orderShipment  = warehouseOrder.shipment;

                FreightAreaIn destinationIn = warehouseOrder.deliveryPlace.freightAreaData.freightAreaIn;
                if (orderManager.stock.StockFor(orderShipment.resourceName) >= orderShipment.amount && RoadsPathfinding.RouteStar(destinationIn.road, freightData.freightAreaOut.road, 10, Orientation.SOUTH) != null)//TODO orientation
                {
                    _currentStock.RemoveFromStock(orderShipment.resourceName, orderShipment.amount);
                    freightData.SendCarrier(warehouseOrder.deliveryPlace, Orientation.SOUTH, orderShipment);//TODO orientation
                }
            }

            yield return(new WaitForSeconds(0.5f));
        }
    }