Autor Wątek: Lokalny GameObject.  (Przeczytany 4600 razy)

Offline Logos

  • Użytkownik

# Czerwiec 11, 2014, 01:26:40
Może głupie pytanie, ale zaczynam dopiero przygodę z Unity.

Dlaczego stworzenie lokalnego obiektu typu GameObject w środku w metodzie skryptu powoduje, że obiekt ten od razu jest w scenie - staje się globalny?

void GenerateRiverArea(float a_z_indent)
{
GameObject plane = new GameObject("Plane" + a_z_indent);
}

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline Veldrin

  • Użytkownik

# Czerwiec 11, 2014, 02:32:43
Zapewne dlatego, że taka została zaprojektowana architektura silnika.

Offline .:NOXY:.

  • Użytkownik
    • Profil

# Czerwiec 11, 2014, 09:49:06
Bo w Unity to dziedziczy bo globalnym obiekcie, do tego w jego konstruktorze dzieje sie takie cos:


Scene *currScene = MainSceneManager->GetCurrent();
currScene->AddObject(this);


No rocket science at all.

Offline Logos

  • Użytkownik

# Czerwiec 11, 2014, 10:05:43
Dzięki! To jest dobre rzeczy opisanie!

To spytam o coś jeszcze, bo w necie są jednak sprzeczne wytłumaczenia.

Dlaczego tak naprawdę OnGUI(), Start(), czy Update() nie markuje się przez override?

Offline .:NOXY:.

  • Użytkownik
    • Profil

# Czerwiec 11, 2014, 14:09:39
Nie znam sie dobrze na C# ale prawdopodobnie wynika to z Polimorfizmu tego jezyka jak metoda nie jest virtual to nie wymaga override.

Offline Rethil

  • Użytkownik

  • +1
# Czerwiec 11, 2014, 14:26:59
A mi wydaje się, że to znowu wynika z architektury silnika. Konkretnie rzecz biorąc bierzemy refleksję - sprawdzamy czy metoda o nazwie "Update" istnieje i jeśli tak to ją wywołujemy.

Jak się nad tym zastanowić to wywoływanie metody po nazwie stringowej ma jeszcze więcej sensu jeśli weźmie się pod uwagę, że w silniku są często gęsto rozsiane takie funkcje jak GetComponent przyjmujące nazwę typu jako string (metoda generyczna GetComponent<klasa>() tak naprawdę zamienia klasę na stringa i wywołuje metodę GetComponent("klasa")) lub metoda Invoke, SendMessage itd.

No i jeszcze jedno - w końcu i tak wszystkie klasy które piszesz są serializowane i deserializowane po C++owej stronie silnika (tak, tak Unity ma core napisany w C++, a nie jakby się mogło wydawać w C#, JS czy Boo) wiec wywoływanie po nazwie może mieć uzasadnienie w takim traktowaniu kodu.
« Ostatnia zmiana: Czerwiec 11, 2014, 14:29:08 wysłana przez Rethil »

Offline Ivian

  • Użytkownik
    • Ivian's Cave

# Czerwiec 11, 2014, 17:04:26
Tam w bebechach wszystko jest serializowane. Eventy jak OnGUI lecą przez Reflection/Invoke. Kiedyś leciało przez "SendMessage" afair. Unity w czasie kompilacji rozpoznaje jakie metody ma dana klasa i pod nie podczepia eventy.


Musisz wiedzieć, że jeśli klasa dziedzicząca po MB ma zadeklarowaną metodę Update() to ona się wywoła nawet jeśli jest pusta. Warto o tym pamiętać, bo jest to czasami całkiem spore obciążenie.

Offline koirat

  • Użytkownik

# Czerwiec 12, 2014, 04:00:39
Dlaczego tak naprawdę OnGUI(), Start(), czy Update() nie markuje się przez override?
Niestety, jak już było wspomniane dzieje się to poprzez refleksję.
Nie dzieje się to jednak w trakcie kompilacji a w run-time, zakładam jednak że tylko podczas pierwszego utworzenia obiektu wyszukiwane są te funkcje, później niewątpliwie jest to zoptymalizowane.
Pomimo tego nadal jest to do d.... rozwiązanie, w przypadku dziedziczenia robi się niezły bajzel.

Cytuj
Nie znam sie dobrze na C# ale prawdopodobnie wynika to z Polimorfizmu tego jezyka jak metoda nie jest virtual to nie wymaga override.

Metoda rzeczywiście nie wymaga overrida, problem w tym że mamy w ten czas do czynienia z zasłanianiem metody (method hiding) a nie z overriding-iem.




« Ostatnia zmiana: Czerwiec 12, 2014, 04:06:02 wysłana przez koirat »

Offline ArekBal

  • Użytkownik

# Czerwiec 12, 2014, 10:24:58
Kto ci broni w Start() włożyć wywołanie wirtualnej OnStart()?

Offline Rethil

  • Użytkownik

# Czerwiec 12, 2014, 12:03:58
Nikt:P Chodzi o to jak działa silnik, a nie o to co możesz zrobić:P Dziedzicząc po MB nie masz wirtualnej OnStart więc musisz i tak wywołać przez refleksję zwykłego Start'a. Zresztą Start może być wykorzystany jako Coroutine, co jest naprawdę fajne i czasami żal nie skorzystać z tego.

Podsumowując tworząc nową klasę MyMonoBehaviour które miałoby wywołanie wirtualnej metody OnStart() to  wołamy nową wirtualną, co jest kosztem samym w sobie, wołamy Start() przez refleksje i tracimy możliwość skorzystania z yield.

Offline ArekBal

  • Użytkownik

# Czerwiec 12, 2014, 12:47:28
Ja odpowiadam na zastrzeżenia koirata który wolałby wirtualne i dziedziczenie.

Odpowiedzią jest utworzenie kilku bazowych które będą miały Start i to co potrzebne w danej bazowej i dodanie wirtualnych metod.

Offline koirat

  • Użytkownik

# Czerwiec 12, 2014, 12:54:41
Tak też robię ale i tak jest to nieco problematyczne. Choć utworzenie kilku bazowych tylko po to żeby mieć kombinacje zarezerwowanych przez unity funkcji (Awake, Start, Update,...) uważam za przesadną komplikacje którą mogli ominąć. Niestety ten engine ma dość sporo różnych takich kwiatków.

Offline Ivian

  • Użytkownik
    • Ivian's Cave

# Czerwiec 12, 2014, 13:11:25
@koirat.

Część serializacji jest robiona podczas kompilacji. Zobacz sobie że Unity nie wywala do Inspectora property "enabled" z Behaviour, jeśli klasa nie ma zaimplementowanej metody Start() lub Update().

btw:

class A : MonoBehaviour
{
virtual void Awake() { bla bla bla }
}

class B : A
{
override void Awake() {base.Awake(); blablabla}
}

works fine.
« Ostatnia zmiana: Czerwiec 12, 2014, 13:37:00 wysłana przez Ivian »

Offline koirat

  • Użytkownik

# Czerwiec 12, 2014, 13:40:07
Seriazacja to zapisanie jakiegoś obiektu w celu późniejszego go odtworzeniu. Co ma do tego proces kompilacji ?
Zauważ że skrypty nie musisz kompilować za pomocą kompilatora unity. Możesz sobie stworzyć własną dll i ją dołączyć.


Offline Ivian

  • Użytkownik
    • Ivian's Cave

# Czerwiec 12, 2014, 14:22:00
Myślę że używamy tego samego określenia na dwie różne rzeczy :) Ty myślisz w kategorii faktycznego obiektu (Assetu), a ja w kategorii typów. Imo po kompilacji Unity wie, że na obiekcie danego typu (na danym componencie) może wykonać metodę Update etc. (i nie ma to nic wspólnego z dziedziczeniem po ScriptableObject [ahh :D dopiero w samych bebechach] czy System.Serializable). Prawdopodobnie jest na to jakieś ładniejsze/bardziej poprawne polityczne określenie. Przepraszam jeśli wprowadziłem chaos ;)