[Unity][UI] Okienko obiektu


#1

Witam,
zastanawiam się jak obsłużyć wyświetlanie panelu informacyjnego danego obiektu. Przejdę od razu do rzeczy mam scenę, na niej są obiekty (drzewa, krzaki itd.). Nie znam jeszcze możliwej ilości różnych obiektów dlatego myślę nad skalowalnym rozwiązaniem. Po kliknięciu na obiekt chcę wyświetlić jego “tabliczkę” informacyjną z indywidualnymi opcjami co można z nim zrobić (dla drzewa np. zetnij, dla krzaków zbieraj). Czasem dwie akcje do jednego obiektu. Obiekty będą miały cechę wspólną czyli pozyskujemy z nich surowce, różnice to, że jedne znikają ze sceny drugie pozostają na scenie oraz różna ikonka akcji w okienku.
Aktualnie realizuję to tak:
raycast -> trafiony obiekt -> skrypt na obiekcie odpalający prefab okna
problem jest przypisanie odpowiednich akcji OnClick.AddListener na danym przycisku, który powinien wykonać metodę w głównym skrypcie obiektu. W sensie, jak zdefiniować które metody obiekt ma przesłać do przycisków. Czy da się je zdefiniować jakimiś stringami?
Mógłbym również niby ustawić wszystkie okienka na scenie i włączać odpowiednie ale jeśli nagle tych przykładowych drzew by nie było to jednak to okno gdzieś w pamięci na scenie by wisiało.
Robienie indywidualnych skryptów dla indywidualnego okna wydaje mi się mało efektywne.
Może potrzebuje dnia wolnego, żeby to przemyśleć, może sam niepotrzebnie komplikuje problem.
Za wszelkie porady będę wdzięczny.


#2

Hmm nie wiem czy dobrze zrozumiałem, Chcesz wykonać jakąś akcje na zaznaczony obiekcje, w panelu który się wyświetli np. zetnij drzewo ? Można w skrypcie napisać ogólna funkcje zetnij drzewo. W tym skrypcie statyczna zmienna z obiektem drzewo której będzie dotyczyła funkcja. Po kliknięcie na dane drzewo odpala się panel a dane drzewo przypisuje do statycznej zmienne w skrypcie od ui.


#3

Ui canvas w world space.
Do tego delegate, Action i lambda expresions/funkcje anonimowe. Do przesylania i przypisywania “funkcji”.
Dodatkowo modular ui window. -> robisz jedno okno ale jest inicjowane przez rozne obiekty w rozny sposob i roznymi wlasciwosciami.

Najlepiej trzymaj okienko jako prefab w np. resources (mam nadzieje ze wiesz o co biega z resources) -> ladujesz kiedy jest potrzebne i niszczysz kiedy nie potrzebujesz. Inicjujesz z nowymi danymi potrzebnymi do aktualnego obiektu, np. pozycja okienka, rodzic (moze sie orzydac jak obiekt sie porusza to i okienko by sie poruszalo), funkcja ktora ma byc odpalona po nacisnieciu guzika i inne potrzebne rzeczy.

Modularne okienko zawsze mozesz trzymac w pamieci -> bo uzywasz go w wielu innych przypadkach. No i nie potrzujesz osobnych okienek do roznych rodzajow obiektow :]

Mam nadzieje ze zrozumiales moje chaotyczny styl przekazywania informacji :smiley: jak nie to daj znac postaram sie pomoc jakims przykladowym kodem :]

P.S.
Nigdy nie przekazuj wartosci/zmiennych do funkcji jako stringi. Ciezko to skontrolowac.

P.S2.
Do obiektow ktore beda uzywac tych okienek dorob interfejs, bardzo to pomoze.


#4

Dzięki za podpowiedzi.
@Palanthir dobrze zrozumiałeś, faktycznie muszę przesłać referencje obiektu do skryptu UI, przez to, że obiekt “spawnuje” UI i jest jego rodzicem mam łatwiejsze powiązanie.
@RoboCat akurat ten panel zrobię overlay, world space ewentualnie jakieś progres bary, muszę opracować jakiś ogólny schemat tego modularnego okna.
Obiekt będzie miał listę z dostępnymi akcjami (jakiś pomocniczy enum) którą wyśle to tego okna, a okno utworzy odpowiednie przyciski i podepnie metody.
Z tym stringiem nie chodziło mi o przesyłanie danych, jeśli obiekt jest prefabem, ma ogólny skrypt (stosowany w innych obiektach) za pomocą którego robię spawn okna. Definiuje w inspektorze parametry dla tego (pref)obiektu, pytanie czy w inspektorze mogę zdefiniować referencje do metody?

Biorę się za kodowanie, jak coś będę miał sensownego podeślę co mi wyszło.

P.S.
W chaosie kryje się logika, wada programisty, rzuca się hasłami, kwestia optymalizacji zdania ^^


#5

Przyda ci sie jedna rzecz -> pluggable functions in scriptable objects. Bardzo fajna sprawa. Robisz scriptable objects z odnoscnikami do funkcji -> i podmieniasz je tylko w glownym skrypcie. takie plug and play w edytorze :]

Byl taki tutorial na unty officialu i plugable ai, zastosowali to w tank’ach.
https://www.youtube.com/watch?v=cHUXh5biQMg

to chyba bedzie najodpowiedniejsze jak lekko dostosujesz pod siebie.
Ogolnie polecam scriptable objects, bardzo fajna sprawa.


#6

Będę musiał kiedyś usiąść i przerobić te zagadnienia o których piszesz @RoboCat, wiedziałem, że coś takiego jest ale zbytnio nie rozkminiałem jak to do końca działa. Wstępnie prosto zrobiłem działanie na trzech skryptach, skrypt Controller robi raycasta i uruchamia metode w obiekcie ShowUI, drugi w obiekcie który wyświetla odpowiedni prefab okna, trzeci w samym oknie który pobiera i ustawia odpowiednie dane. Niby powinienem wysyłać parametry od obiektu do interfejsu jednak w ten sposób jeśli obiektem będzie ognisko to interface dla niego będzie już działał na innej zasadzie. Tak to mniej więcej to teraz wygląda.


#7

Wazne ze dziala.

Zamiast instantiate i destroy za kazdym razem, stworz jeden panel a pozniej go tylko deaktywuj i aktywuj z nowymi ustawieniami i podpinaj pod nowy obiekt, mozesz dopisac funkcje Init(wartosci), narazie to nie duza roznica pozniej wazne zasoby. instantiate i destroy do obciazenie.

W ObjInteraction -> zmienilbym UiPrefab na scriptable object. Pomysl jak teraz zmienisz ten panel na inny obiekt to bedziesz musial we wszystkich obiektach ze skryptem ObjInteraction zmienic ten link do prefabu. A jak bedzie scriptable object -> to tylko w nim zmienisz a reszta sie juz podlinkuje. Chyba ze poszukasz obiektu po tagach.

Teraz co masz to wywoluje funkcje na krzaku tylko-> a co z postacia? Przelaczenie animacji itp.
Jezeli tylko akcje na np kamyku to Ja to bym widzial tak ze obiekty w grze nazwijmy je np “clickable” implementowaly interface np IClickableWithMenu. (nazwy umowne :smiley: ) dzieki temu nie bedziesz probowal wyswietlac okienka przy obiektach ktore nie powinny ich miec. Mozna tez inherit’owac (ale tworze slowa… dziedziczyc) po rodzicu glownej klasie obiektow ktora ma abstract klase MainAction() itp. ale wolalbym dodac interfejsy.

W interface musialbys dac funkcje np. MainAction(), SecondAction(), i inne potrzebne rzeczy ktore dana klasa musiala by implementowac. Po kliknieciu na obiekt (raycast itp) sprawdzasz czy jest IClickableWithMenu -> jak tak to instantiate okienko z ustawieniami -> przekazujesz akcje. mozesz to zrobic prosto poprzez lambda( ()=> { MainAction(); }) albo przez delegate.

Dzieki temu masz to wszystko modularne.
Robisz nowy obiekt np: MagicznyKamyczek ktory implementuje IClickableWIthMenu… i teraz MUSISZ (inaczej unity ci nie pozwoli, czyli juz masz zabezpieczenie ze sie nie sypnie) te funkcje sobie dopisac np piszesz funkcje SuperStoneBallCast() i przekazujesz ja do okienka jako MainAction(). Nie musisz nic zmieniac, nie musisz dodawac nowych enumow. Poprostu sobie piszesz co ma ten dany obiekt robic jezeli zostala wywolana funkcja MainAction()… :smiley:
Do tego mozesz zrobic sobie te funkcje jako scriptable objects. dzieki temu mozesz je uzywac w wielu miejscach, i wybierac/dodawac z listy jak enum, ale wieksza kontrola i bedziesz musial zmienic funkcje tylko w jednym miejscu.
Rozwijajac mozesz zrobic nawet w obiekcie liste funkcji (tych scriptable objects) i laczyc wszystko jak combosy… np Magiczny kamyk bedzie puszczal StonBalla i do tego robil sie mokry.

Chyba ze postac tez ma jakas akcje robic to bedziesz musial to ladnie polaczyc :]

Chaotycznie bo pisze swoj projekt i w przerwach dopisuje tego posta.
Pokombinuj i bedzie ok -> wazne ze dziala, chociaz lepiej zeby kod i architektura tez byly ladne :smiley:

To tak w skrocie… chyba najdluzszy moj post w zyciu.

Edytowalem zeby zlikwidowac literowki i bledy bo nie dalo sie tego czytac…


#8

Dzięki wielkie za wsparcie i poświęcony czas ^^
Wczoraj już nie chciałem Ci głowy zawracać, zamiast pisać przerobiłem sobie działanie interfejsów. Dziś może uda mi się zobaczyć i przeanalizować działanie pluggable function w scriptobject.

…instantiate i destroy to obciążenie.

Wiem, ale stwierdziłem, że nikt nie będzie w stanie w ciągu jakiegoś czasu tyle razy kliknąć, żeby stało się to uciążliwe. Mam trochę większy porządek na scenie. Ale masz rację w sumie czy zrobię referencję obiektu już na scenie to działanie będzie identyczne (delikatna modyfikacja skryptów). Gorzej jak scena się zmieni, tu może być problem.

jak teraz zmienisz ten panel na inny obiekt to bedziesz musial we wszystkich obiektach ze skryptem ObjInteraction zmienic ten link do prefabu

Edycja prefabu (UI) nie niszczy powiązania w obiektach. Wiec przy pierwszym stworzeniu prefabu obiektu ustawiam w nim skrypt ObjInteraction i jaki prefab UI ma być podpięty.

Teraz co masz to wywoluje funkcje na krzaku tylko-> a co z postacia?

No właśnie teraz jest tak, że klikasz -> raycast -> jeśli trafienie w obiekt z skryptem ObjInteraction -> wyświetl podpięte UI. Identycznie sprawdzenie jak zrobił bym to na interfejsie.
Postać teraz nic nie ma więc nie reaguje, jeśli podepnę skrypt ObjInteraction to mogę ustawić inny prefab UI (np wyświetlenie ekwipunku z całkowicie innym rozłożeniem przycisków, ikonek itd.).
Interfejs faktycznie zabezpieczy mi projekt, tylko muszę to przemyśleć i coś zaprojektować.
Jeszcze się zastanawiam, bo przesłanie metody to powiedzmy nie problem, ale co zrobić z ikonką przycisku? Enum używam pomocniczo do ustawienia dostępnych akcji i wyświetlenia dobrej ikonki dla danej akcji (cut -> siekiera).
Muszę jednak najpierw ogarnąć scriptable object.

Oj jest przy tym wszystkim rozkminy, a miały być proste UI :smiley: Tylko jak teraz nie pomyślę to później mogę mieć problem z rozbudową.


#9

Prosze bardzo :]

Chodzilo mi o calkowita zmiane prefabu, a nie jego modyfikacje :]

Jeszcze się zastanawiam, bo przesłanie metody to powiedzmy nie problem, ale co zrobić z ikonką przycisku?

Dajmy na to masz funkcje:
W okienku UI daj konstruktor albo jakas funkcje Init() co bieze parametry. np: (nie wiem co dokladnie potrzebujesz w ui)
Najlepiej zrobi sobie taka klase albo jako struct:

    public class DataToSendToUIWindow 
    {
        public Sprite icon;
    public Text buttonText;
    public Theme myTheme;  // tutja mozesz zrobic swoj wlasny scriptableobject z danymi jak kolory ksztalty image buttonow, dzieki temu np crafting okienko bedzie inne a np okienko do zbierania inne , wieksze pole do rozbudowania pozniej bo mozesz wiecej rzeczy przesylac.
    i co tam jeszcze potrzbujesz do utrworzenia okienka;
    }

A jak masz malo rzeczy do przeslania to poprostu przeslij bezposrednio 1 by 1 w funkcji.

W elemencie ui cos na ksztalt    
    public void Init(funcja MainActivity, DataToSendToUIWindow myModalData)
    {
this.MainActivity = MainActivity;
    tutaj wszystko podpinasz pod zmienne okienka
    i aktywujesz
    }

A poznej po kliknieciu na IClickabelWIthUI
uiPrefab.Init(i przekazujesz wszystko z danego obiektu)

Tak w skrocie :] Mam nadzieje ze ten chaos ci pomoze.