Kuzyn Opublikowano 19 Czerwca 2023 Udostępnij Opublikowano 19 Czerwca 2023 Cześć, przychodzę z nieco bardziej skomplikowanym problemem, ale już nie mam w głowie żadnych innych pomysłów jak go rozwiązać. Postaram się jak najdokładniej opisać co jest nie tak. Co jest nie tak? Moje obiekty objCitizen nie przechodzą ścieżki od punktu A do punktu B w drugiej fazie swojej pracy, co powoduje, że kod z warunkiem (path_position == 1) wykonuje się natychmiastowo. A jak powinno być? Obiekt objBuilding na początku szuka wolnego objCitizen, który mógłby dla niego pracować. Jeśli go znajdzie, przydziela go do siebie. Następnie tenże objBuilding sprawdza czy ma wolne miejsce na składzie, jeśli tak to z puli przypisanych pracowników (na ten moment maks. 1) wybiera sobie pierwszego wolnego, wynajduje mu pracę i wytycza mu ścieżkę do tej pracy. objCitizen w tym momencie rusza do miejsca pracy i wykonuje swoją pracę, po czym zgłasza, że ją wykonał. Wtedy objBuilding woła go z powrotem do siebie, żeby wrócił z tym wynikiem pracy. (to nie działa) objCitizen wraca, oddaje na skład wynik swojej pracy i jest gotowy na podjęcie nowej, wyznaczonej przez objBuilding. Czy wcześniej to działało? Tak i nawet dzieliłem się tym na discordzie GMClanu https://streamable.com/qx78pz Natomiast w momencie gdy dodałem drugi rodzaj budynku i nieco pozmieniałem kod, całość się wysypała. Opierając się na przykładzie z wideo, objCitizen zamiast odnosić drewno do składu, zbiera po prostu jedno po drugim, oddając je na odległość do składu i staje w miejscu. Co do tej pory sprawdziłem i co mogę jeszcze zrobić? Opcją ostateczną zostaje dla mnie cofnięcie się do poprzedniej wersji projektu z githuba, chciałbym rozwiązać ten problem, a nie cofać wszystko. Sprawdzałem czy objCitizen ma poprawnie wyznaczony cel, próbowałem podmieniać różne warunki, sprawdzałem czy parametry ścieżki w postaci celu są poprawne i tak, wszystko się zgadzało. Zanim wkleję kod, pokrótce rozpiszę zmienne, które mają kontrolować zachowanie objCitizen i objBuilding i jak po kolei powinny się zmieniać. objBuilding w Step Evencie ma switcha, który zmienia mu stany. Stan odpowiedzialny za wyznaczanie pracy ma taki kod: function buildingStateWork(){ if (building.buildingTaskAssigned == false) { switch (building.buildingType) { case "Utility": #region UTILITY switch (building.buildingUtilityType) { #region WAREHOUSE // Check if building is Warehouse. case "Warehouse": //Check if the building got any space left. if (building.buildingStorageFull == false) { //If building is full, do not perform this code for performance. for (var i = 0; i + 1 < array_length(building.buildingStorage); i += 2) { if (building.buildingStorage[@ i][1] < building.buildingStorage[@ i + 1][1]) { //There is space for something. For this example, simplify it to wood only. //Look for somebody to bring items. for (var i = 0; i < array_length(building.buildingWorkerList); i++) { //Check if the workers are already occupied doing something or not. if (building.buildingWorkerList[i].citizen.citizenOccupied == false and building.buildingWorkerList[i].citizen.citizenBackFromTask == false) { //Check for items to be picked up in range. var AvailableItems = ds_list_create(); //Store there items that will be found in range. var CurrentWorker = building.buildingWorkerList[i]; //Store id of the worker. collision_circle_list(x, y, building.buildingWorkRange, objectItem, false, true, AvailableItems, true); //Find items. for (var i = 0; i < ds_list_size(AvailableItems); i++) { if (AvailableItems[| i].item.itemName == "Wood log") { CurrentWorker.citizen.citizenOccupied = true ; CurrentWorker.citizen.citizenGoToTask = true ; CurrentWorker.citizen.citizenTarget = AvailableItems[| i].id; CurrentWorker.citizen.citizenTargetX = AvailableItems[| i].x ; CurrentWorker.citizen.citizenTargetY = AvailableItems[| i].y ; CurrentWorker.pathStarted = false ; with (CurrentWorker) { citizenPath = path_add(); } CurrentWorker.citizen.citizenState = CITIZEN_STATES.MOVE ; building.buildingTaskAssigned = true ; break; } else { break; } } } } } else { //There is no space, so there is no need to look out for resources to be picked up/send worker. building.buildingStorageFull = true; //This needs to be set to false once somebody picks up something from there. break; } } } break; //WAREHOUSE #endregion } #endregion break; case "Production": #region PRODUCTION //Check if the building got any space left. if (building.buildingOutputAmount < building.buildingOutputAmountMax) { //Look for somebody to cut the tree. for (var i = 0; i < array_length(building.buildingWorkerList); i++) { //Check if the workers are already occupied doing something or not. if (building.buildingWorkerList[i].citizen.citizenOccupied == false and building.buildingWorkerList[i].citizen.citizenBackFromTask == false) { //Check for trees to be cut down. var AvailableResources = ds_list_create(); //Store there trees that will be found in range. var CurrentWorker = building.buildingWorkerList[i]; //Store id of the worker. collision_circle_list(x, y, building.buildingWorkRange, building.buildingProductionTarget, false, true, AvailableResources, true); //Find trees. for (var i = 0; i < ds_list_size(AvailableResources); i++) { if (AvailableResources[| i].tree.treeGrowthStage == 2) { CurrentWorker.citizen.citizenVocation = "Woodcutter" ; CurrentWorker.citizen.citizenOccupied = true ; CurrentWorker.citizen.citizenGoToTask = true ; CurrentWorker.citizen.citizenTarget = AvailableResources[| i].id ; CurrentWorker.citizen.citizenTargetX = AvailableResources[| i].x ; CurrentWorker.citizen.citizenTargetY = AvailableResources[| i].y + AvailableResources[| i].tree.treeYOffset ; CurrentWorker.pathStarted = false ; with (CurrentWorker) { citizenPath = path_add(); } CurrentWorker.citizen.citizenState = CITIZEN_STATES.MOVE ; building.buildingTaskAssigned = true ; break; } } } } } else { //There is no space, so there is no need to look out for resources to be picked up/send worker. building.buildingState = BUILDING_STATES.HOLD; //This needs to be set to false once somebody picks up something from there. } #endregion break; } } else { switch (building.buildingType) { case "Utility": #region UTILITY switch (building.buildingUtilityType) { #region WAREHOUSE // Check if building is Warehouse. case "Warehouse": for (var i = 0; i < array_length(building.buildingWorkerList); i++) { var CurrentWorker = building.buildingWorkerList[i]; if (CurrentWorker.citizen.citizenOccupied == false and CurrentWorker.citizen.citizenBackFromTask == true) { CurrentWorker.citizen.citizenOccupied = true ; CurrentWorker.citizen.citizenTarget = id ; CurrentWorker.citizen.citizenTargetX = x ; CurrentWorker.citizen.citizenTargetY = y+building.buildingYOffset ; CurrentWorker.pathStarted = false ; with (CurrentWorker) { citizenPath = path_add(); } CurrentWorker.citizen.citizenState = CITIZEN_STATES.MOVE ; break; } } break; #endregion } #endregion break; case "Production": #region PRODUCTION for (var i = 0; i < array_length(building.buildingWorkerList); i++) { var CurrentWorker = building.buildingWorkerList[i]; if (CurrentWorker.citizen.citizenOccupied == false and CurrentWorker.citizen.citizenBackFromTask == true) { CurrentWorker.citizen.citizenOccupied = true ; CurrentWorker.citizen.citizenTarget = id ; CurrentWorker.citizen.citizenTargetX = x ; CurrentWorker.citizen.citizenTargetY = y+building.buildingYOffset ; CurrentWorker.pathStarted = false ; with (CurrentWorker) { citizenPath = path_add(); } CurrentWorker.citizen.citizenState = CITIZEN_STATES.MOVE ; break; } } #endregion break; } //Switch } //Else } //Function objCitizen działa na podobnej zasadzie, w Step Evencie jest switch. Kod odpowiedzialny za pracę poniżej: function citizenStateWork(){ switch (citizen.citizenVocation) { case "Mover": //Citizen is moving to the resource. if (citizen.citizenGoToTask == true) { if collision_circle(x, y, citizen.citizenPickupRange, citizen.citizenTarget, false, true) { citizen.citizenGoToTask = false ; citizen.citizenBackFromTask = true ; citizen.citizenOccupied = false ; citizen.citizenCarrying = true ; citizen.citizenCargo = citizen.citizenTarget.item; instance_destroy(citizen.citizenTarget); } //Add else if someone picks resource before Citizen, reset back to go to the building. } if (citizen.citizenCarrying == true and citizen.citizenBackFromTask == false) { citizen.citizenOccupied = false; citizen.citizenCarrying = false; var CarriedItem = citizen.citizenCargo.itemName; citizen.citizenCargo = 0; //Find carried item in a storage and add to the pool. for (var i = 0; i < array_length(citizen.citizenAssigned.building.buildingStorage); i++) { if (CarriedItem == citizen.citizenAssigned.building.buildingStorage[i][0]) { citizen.citizenAssigned.building.buildingStorage[i][1] += 1; } } //Let building find another task. citizen.citizenAssigned.building.buildingTaskAssigned = false; } break; case "Woodcutter": //Citizen is moving to the building back with the resource. if (citizen.citizenGoToTask == true) { if collision_circle(x, y, citizen.citizenPickupRange, citizen.citizenTarget, false, true) { //Cut the tree here.f if (workTimerOn == false and citizen.citizenTarget.tree.treeHealth > 0) { workTimerOn = true; citizen.citizenTarget.tree.treeHealth = citizen.citizenTarget.tree.treeHealth - 1; time_source_start(workTimer); } //Remove the tree and add resource to worker. if (citizen.citizenTarget.tree.treeHealth <= 0) { citizen.citizenOccupied = false ; citizen.citizenGoToTask = false ; citizen.citizenBackFromTask = true ; citizen.citizenCarrying = true ; var outputToPick = instance_create_layer(citizen.citizenTargetX, citizen.citizenTargetY, "instanceSystem", objectItem); with (outputToPick) { item = new WoodLog() ; image_speed = 0 ; sprite_index = item.itemSprite ; image_index = item.itemSpriteI ; } instance_destroy(citizen.citizenTarget); citizen.citizenCargo = outputToPick.item; instance_destroy(outputToPick); } } //Add else if someone picks tree before Citizen, reset back to go to the building. } if (citizen.citizenCarrying == true and citizen.citizenBackFromTask == false) { citizen.citizenOccupied = false; citizen.citizenCarrying = false; var CarriedItem = citizen.citizenCargo.itemName; citizen.citizenCargo = 0; //Add carried item to the pool, check before if right item is coming in. if (CarriedItem == citizen.citizenAssigned.building.buildingOutput) { citizen.citizenAssigned.building.buildingOutputAmount += 1; } //Let building find another task. citizen.citizenAssigned.building.buildingTaskAssigned = false; } break; } } A na końcu kod odpowiedzialny za przemieszczenia objCitizen: function citizenStateMove(){ if (pathStarted == false) { if mp_grid_path( systemPathfinding.pathfindingCitizenGrid, citizenPath, x, y, citizen.citizenTargetX, citizen.citizenTargetY, 1) { path_start(citizenPath, citizen.citizenSpeed, path_action_stop, true); pathStarted = true; } } if (path_position == 1) { if (citizen.citizenOccupied == true and citizen.citizenBackFromTask == true) { citizen.citizenBackFromTask = false; } path_delete(citizenPath); pathStarted = false ; citizen.citizenState = CITIZEN_STATES.WORK ; } } Uzjel 1 Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
Administratorzy Rozwiązanie gnysek Opublikowano 20 Czerwca 2023 Administratorzy Rozwiązanie Udostępnij Opublikowano 20 Czerwca 2023 Po sprawdzeniu tego prywatnie, dopiszę w razie czego, dla potomności: Ze względu na to co znajduje się w mp_grid, ścieżka może się czasem nie wygenerować, w związku z tym, w poniższym kodzie function citizenStateMove(){ if (pathStarted == false) { if mp_grid_path(... może zostać zwrócony false w ostatnim ifie, a wtedy path_position nadal będzie wynosić 1, bo obiekt nadal widzi ostatni path, na końcu którego stoi, dlatego warunek był od razu spełnianiany i gra zachowywała się tak, jakbyśmy wrócili do budynku gdzie zostawia się zasoby (tak naprawdę robiąc 0 pikseli), następnie szukając ścieżki do następnego zasobu. Nawet jeśli wydaje się to mało prawdopodobne, czasem warto dodać else i obsłużyć teoretycznie nieistniejący wyjątek. Potem łatwiej go znaleźć Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
Kuzyn Opublikowano 20 Czerwca 2023 Autor Udostępnij Opublikowano 20 Czerwca 2023 28 minut temu, gnysek napisał(a): Po sprawdzeniu tego prywatnie, dopiszę w razie czego, dla potomności: Ze względu na to co znajduje się w mp_grid, ścieżka może się czasem nie wygenerować, w związku z tym, w poniższym kodzie function citizenStateMove(){ if (pathStarted == false) { if mp_grid_path(... może zostać zwrócony false w ostatnim ifie, a wtedy path_position nadal będzie wynosić 1, bo obiekt nadal widzi ostatni path, na końcu którego stoi, dlatego warunek był od razu spełnianiany i gra zachowywała się tak, jakbyśmy wrócili do budynku gdzie zostawia się zasoby (tak naprawdę robiąc 0 pikseli), następnie szukając ścieżki do następnego zasobu. Nawet jeśli wydaje się to mało prawdopodobne, czasem warto dodać else i obsłużyć teoretycznie nieistniejący wyjątek. Potem łatwiej go znaleźć Uprzedziłeś mnie z odpowiedzią Dzięki za pomoc i dodam jeszcze, czemu objCitizen nie mógł znaleźć ścieżki. Ano dlatego, że źle ustawione maski budynków zajmowały zbyt dużo komórek w gridzie i cel wskazany dla objCitizen był w niedostępnej komórce. Także uczulam na sprawdzanie tego również! Uzjel 1 Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
Uzjel Opublikowano 20 Czerwca 2023 Udostępnij Opublikowano 20 Czerwca 2023 Dodatkowo polecam rysować ścieżki chociażby dla debugowania + rysować mp_grid_draw, żeby zobaczyć czy siatka odpowiednio się wygenerowała. I na koniec jeszcze taki tip, jak nie chcemy żeby ścieżka była taka "kwadratowa" można użyć np tego: https://marketplace.yoyogames.com/assets/1687/optimized-path Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
Administratorzy gnysek Opublikowano 21 Czerwca 2023 Administratorzy Udostępnij Opublikowano 21 Czerwca 2023 12 godzin temu, Uzjel napisał(a): polecam rysować ścieżki chociażby dla debugowania to akurat robiliśmy - ale o mp_grid_draw zapomniałem, dzięki za tip! Jakby ktoś chciał zobaczyć moją wersję powyższego, zrobioną w 40-60 minut, to jest tutaj: https://gmclan.org/uploader/plik/21277,worker_placement Uzjel i Adriann 1 1 Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
Rekomendowane odpowiedzi
Jeśli chcesz dodać odpowiedź, zaloguj się lub zarejestruj nowe konto
Jedynie zarejestrowani użytkownicy mogą komentować zawartość tej strony.
Zarejestruj nowe konto
Załóż nowe konto. To bardzo proste!
Zarejestruj sięZaloguj się
Posiadasz już konto? Zaloguj się poniżej.
Zaloguj się