Jump to content
Unity Insider Forum
Sign in to follow this  
nordseekrabe

Objekt im Objekt finden

Recommended Posts

Moin, Unity-Freunde,

in meiner Küchenszene habe ich einen Schrank zum Kühlschrankobjekt gewählt, Collider und SpriteRenderer hinzugefügt, in Sprite wird das Bild des offenen Kühlschrankes eingefügt.

SpriteRenderer deaktiviert. Auf dem GO liegt das Script "ObjektÖffnen". Wenn ich nun auf den Kühlschrank mit "Öffne" klicke, wird der offene Kühlschrank dargestellt (siehe Script).

Jetzt soll aber im Kühlschrank ein Stück Fleisch liegen. Der SpriteRenderer des Fleischobjektes muss also auch deaktiviert sein, damit das Fleisch nicht durch den geschlossenen Kühlschrank sichtbar

wird. Also dachte ich, zunächst aktiviere ich den SpriteRender des Kühlschrankes und anschließend den des Fleischstückes. Funktioniert aber nicht. Liegt das am Collider im Collider ?

Oder was mache ich falsch ?

if (aktionsManager.aktuelleAktion == "Öffne")
        {
            GetComponent<Renderer>().enabled = true;  //das Bild des offenen Kühlschrankes erscheint
            aktionsManager.Infotext.text = "Hoppla, da liegt ja ein riesiger Brocken Fleisch im Kühlschrank.";

            Fleischbrocken.GetComponent<Renderer>().enabled = true;
            
        }

Bin wie immer für jeden Tipp dankbar.

Gruß von der sonnigen Ostseeküste       Nordseekrabbe

 

Share this post


Link to post
Share on other sites

Eine schnelle Ergänzung von mir. Bei dem Versuch, das Script des Objektes "InteraktivesElement", dass ja auch deaktiviert werden sollte, mit dem zusätzlichen Code

                                          this.myScript.gameObject.SetActive(true);

zu aktivieren, habe ich (ungewollt) den SpriteRenderer des Objektes aktiviert, womit meine ursprüngliche Frage beantwortet ist. Aber eigentlich wollte ich mit der Ergänzung das Script aktivieren, was jetzt unklar bleibt ?

private InteraktivesElement myScript            war der Versuch, das Script des Objektes zu deklarieren. Das Script auf dem Objekt(Fleischbrocken) muss aber auch zunächst deaktiviert sein, weil man ja sonst bei geschlossenem Kühlschrank beim Kontakt mit dem Collider durch die Maus einen Hinweis auf den Fleischbrocken erhält. Also bleiben jetzt die Fragen a) wieso erscheint mit dem neuen Code beim Öffnen das Objekt im Kühlschrank und b) wie aktiviere ich tatsächlich das "InteraktivesElement(Script)" des GO

Share this post


Link to post
Share on other sites

Du brauchst noch etwas Grundwissen. Ich könnte da jetzt einiges schreiben. Da ich aber vor einigen Jahren ein Video zu gemacht habe, biete ich dir das mal an. :)
Das ist das erste Video einer ganzen Reihe auf meinem Kanal. Die weiteren Folgen lohnen sich bestimmt auch.

 

Share this post


Link to post
Share on other sites

Sehr gutes Tutorial, wie auch all die anderen, die ich natürlich bereits durchgearbeitet habe, ohne behaupten zu wollen, alles verstanden zu haben, geschweige denn verinnerlicht zu haben.

Das ist das grundsätzliche Problem des Laien, der sich autodidaktisch in eine solche Materie einarbeiten will, ohne eigentlich das umfassende Grundwissen zur Programmierung zu haben.

Daher behaupte ich jetzt einfach mal, das das empfohlene Tut zu meinem Problem nicht weiterhilft. Das Problem ist (ja inzwischen), von einem Script (hier: "ObjektÖffnen") ein anderes Script (hier: "InteraktivesElement")  enabled/disabled zu steuern. Beide Scripte liegen auf dem GO "Fleischbrocken" und "InteraktivesElement" ist disabled, weil ja bei geschlossenem Kühlschrank weder das Fleisch benannt noch sonst wie bearbeitet werden soll/kann. In dem Moment, in dem der Kühlschrank geöffnet wird, wird das Fleisch sichtbar (SpriteRenderer enabled), das Script "InteraktivesElement" sollte jetzt auch enabled werden. 

if (aktionsManager.aktuelleAktion == "Öffne")
        {
            if (zimmer == Room.Kueche)
            {
                GetComponent<Renderer>().enabled = true;  //das Bild des offenen Kühlschrankes erscheint
                aktionsManager.Infotext.text = "Hoppla, da liegt ja ein riesiger Brocken Fleisch im Kühlschrank.";
                
                Fleischbrocken.gameObject.SetActive(true);
                Fleischbrocken.GetComponent<Renderer>().enabled = true;

            }
        }

Das oben beschriebene Procedere gelingt mit dem genannte Code. Es fehlt eine entsprechendes Enabled für das Script "InteraktivesElement" des Fleischbrockens, weil mir dazu eine sinnvolle Syntax nicht gelingen will. Und das ist die Frage mit der ich um ein wenig Anregung bitten wollte.

Nordseekrabbe 

Share this post


Link to post
Share on other sites

Zwischen die < > kannst du (prinzipiell erst einmal) jeden Klassennamen schreiben, den es im Projekt gibt. Dazu zählen lauter Klassennamen, die Unity dir gibt (wie Renderer), aber auch alle, die du so gebaut hast, z.B. "InteraktivesElement". Bei GetComponent kommt dazu, dass nur Komponenten erlaubt sind, aber das hast du ja gegeben. Also einfach

Fleischbrocken.GetComponent<InteraktivesElement>().enabled = true;

Schick ist auf lange Sicht was anderes, aber so hält's erstmal.

Was ich mich halt frage ist, warum du überhaupt die Komponenten ein- und ausschaltest, wenn du doch sowieso das ganze GameObject schon aktivierst und deaktivierst. Ein Renderer auf einem deaktivierten GameObject ist automatisch ebenfalls deaktiviert, da muss man nicht noch mit enabled arbeiten.

Share this post


Link to post
Share on other sites

Es ist ja schon etwas besser geworden, wie ich am Script sehe. :)
Ich frage mich warum du dein Fleischbrockenobjekt überhaupt deaktiviert hast und es jetzt akrivieren willst.
Genauso, warum ist das Script denn vorher aus?
Das der Renderer erst dann an ist, wenn der Kühlschrank offen ist, ist für mich nachvollziehbar, aber der Rest eigentlich nicht.

Wenn man mit dem Objekt erst dann interagieren soll, wenn der Kühlschrank auf ist, dann schalte einfach den Collider bzw. Trigger an oder aus. Je nach Situation.
Natürlich kannst du auch das Fleisch mit dem Renderer ein und ausschalten, wenn deine Szene so aufgebaut ist, dass es keine Kühlschranktür gibt, die einfach vor dem Fleich liegen würde.
Das Ganze GO (GameObject) zu aktivieren, ist aber etwas zu viel des Guten.

Also: Du hast ein Fleisch-Gameobjekt, welsches Ativiert ist und auch ein enabled Script hat. Renderer und evtl Collider (wenn du per Klick aufs Objekt interagierst) sind zu Beginn disabled.
Sobald der Kühlschrank auf ist, muss dein Fleischobjekt den Renderer und den Collider anschalten. Ob das Script des Fleischobjektes das selber tut, weil es von irgendwo eine Info bekommen hat, oder aber ein Script eines anderen Objektes das mit dem Fleischobjekt tut, ist eine Frage der Vorlieben. Es ist aber egal, wer es tut, derjenige muss wissen wann er es tun soll.
Renderer, Collider und Script sind Behaviours die man mit Component.eabled=true aktiviert. Das Component vor dem Punkt ist explizit das Behaviour. Hast du also einen SpriteRenderer, einen BoxCollider2D und ein Script mit Namen InteraktivesElement, muss du sie auch genauso einbinden und ansprechen.

Beispiel wo du alle nötigen Komponenten einschaltest:

private InteraktivesElement dasScript;
private BoxCollider2D derCollider;
private SpriteRenderer derRenderer;
public GameObject Fleisch; // hier wird das Gameobject im Inspector einfach rein getan.

void Start(){ 
  // hier werden die Komponenten des Fleisches kennengelert und den Variablen übergeben
  dasScript = Fleisch.GetComponent<InteraktivesElement>();
  derCollider = Fleisch.GetComponent<BoxCollider2D>();
  derRenderer = Fleisch.GetComponent<SpriteRenderer>();
void Update(){
  if(kühlschrankAuf){
    // hier werden die Komponenten angeschaltet
    dasScript.enabled=true;
    derCollider.enabled=true;
    derRenderer.enabled=true;
  }
    

 

Beispiel wenn du das Komplette GameObjekt einfach aktivieren willst und alle Komponenten nicht extra aktiviert werden müssen.
 

public GameObject Fleisch; // hier wird das Gameobject im Inspector einfach rein getan.

void Start(){
  
void Update(){
  if(kühlschrankAuf){
    Fleisch.SetActive(true);
  }
 

Du kannst natürlich auch von einem anderen GO das Fleisch beim Spielstart auch suchen und dann einer Variable zuwesen, aber das geht nur, wenn es aktiv ist. Inaktive Objekte findest du nicht. Und wie es immer so ist, wenn das GO selber inaktiv ist, dann sind alle seine Komponenten auch inaktiv. Selbst seine KinderObjekte wären inaktiv. DIe KindObjekte wären zwar für sich gesehen aktiv, aber wenn der Chef inaktiv ist, dann überstimmt er die Kinder einfach und somit sind sie im Ganzen gesehen auch inaktiv.

Jetzt hat der Sascha geantwortet.... Egal ich poste das jetzt. ;)



 

Share this post


Link to post
Share on other sites

Tausend Dank, habe sicher beim Coden einige Fehler gemacht, denn im Prinzip hatte ich oben beschriebene Aktivierungen und Deaktivierungen versucht. Habe jetzt aber für mich die einfachste Lösung gefunden: FleischObjekt ist Child von Kühlschrank und ist als Objekt zunächst deaktiviert (und damit auch alle Componenten obwohl mit Häkchen versehen). Mit dem Öffnen des Kühlschrankes wird gleichzeitig auch das Fleischobjekt aktiviert (SetActice(true). So habt Ihr beide es auch beschrieben. Super, wieder eine offene Frage weniger.

Einen schönen Abend und ein sonniges Wochenende           Nordseekrabbe

Share this post


Link to post
Share on other sites

Eine Frage hätte ich noch zum besseren Verständnis: malzbie gibt die Objekte immer mit public in den Inspektor, was aber doch unglaublich aufwendig ist. Wenn ich im gesamten Spiel

sagen wir mal 100 Objekte habe, die ich in irgendeiner Szene dann mal brauche, muss ich aber in jeder Szene unter den entsprechenden Scripts das Objekt eintragen, oder ? "Public" dient doch aber an sich für den Zugriff auf ein fremdes Script. Dann sollte doch [HideInInspector] public Object auch funktionieren, oder habe ich da etwas nicht verstanden ? 

Share this post


Link to post
Share on other sites

Ich mache die public, damit man die Werte beim Tutorial im Inspector sehen kann und auch mal schnell verändern kann.
Natürlich sollte am Schluß nur das public sein, was auch von außen angesprochen oder abgefragt wird.

HideInInspector versteckt die Variablen selbts wenn sie Public sind. Das ist wieder was ganz Anderes.

Share this post


Link to post
Share on other sites

Bin gestern gar nicht auf die Objekte eingegangen, mit denen du ja kommunizieren willst.
Du hast bei Unity viele Möglichkeiten irgendwelche Referenzen zu anderen Objeken/Komponenten zu holen.
Der einfachste Weg ist der mit der Public Variable, wo du das andere Objekt einfach im Inspector in den Slot fallen lässt. Schon hast du deine Referenz.
Natürlich ist das Handarbeit und wenn du wirklich 100 Objekte hast, die alle Referenzen zu anderen Objekten haben müssen, ist das natürlich sehr aufwendig.
Da willst du das eigentlich anders machen. Genauso ist das System problematisch, wenn diese Objekte zum Szenenstart noch gar nicht in der Szene sind. Dann kannst du diese händische Vorarbeit natürlich nicht machen.
Es muss dann über den Code nach Objekten gesucht werden. Das ist nicht unbedingt besser, weil du beim Erstellen des Codes schon wissen musst, nach was du suchst. Das kann ein Name ein Tag oder aber eine Eigenschaft sein. Wenn aber jetzt mehrere Objekte in der Szene sind, die dieses gesuchte Auswahlkriterium haben, wird es problematisch.
Ich denke da z.B. an eine GUI mit mehreren Buttons.
Außerdem kannst du nicht ständig nach neuen Objekten suchen, die vielleicht irgendwann einmal in der Szene erscheinen können. Das würde viel zu viel Performance kosten, denn Suchen ist teuer!
Da sollte sich dann das neu entstandene Objekt besser in eine Liste eintragen, wenn es denn nötig ist, dass man jedes Objekt in der Szene kennen muss.
Es gibt natürlich auch das Referenzieren, welches bei einer Aktion passiert. z.B. wenn ein Objekt mit einem Ray auf ein anderes Objekt schießt oder 2 Objekte kollidieren. Da kann man alle Infos zum Objekt abfragen und auch jetzt noch ne Referenz bilden.

Du musst also für dich entscheiden wie du die Referenzen bildest und das ist natürlich abhängig von der Situation.
Eine öffentliche Variable für Objekte zu bilden und die händisch im Inspector zu bestücken (wenn die Szene es zulässt) ist meiner Meinung nach aber beste Weg, denn es spart Code und reduziert Fehler.
 

Share this post


Link to post
Share on other sites

eine prima verständliche Erläuterung zu meinem Problem mit den "Public Objekten, danke. Was mir besonders missfällt ist folgendes: z.B. im Script ObjektOeffnen werden 3 Objekte public deklariert und müssen dann in der Szene im Inspektor zugewiesen werden. Wenn ich nun aber die Szene wechsele und dort einem ganz anderen Objekt das ObjektOeffnen-Script zuweise, muss ich auch hier im Inspektor nicht nur das neue Objekt zuweisen , sondern auch die 3 anderen Objekte aus der vorherigen Szene, oder etwa nicht ? Zumindest erscheinen die 3 Slots auch im Inspektor in der neuen Szene. Oder können die dann einfach leer bleiben, wenn diese Objekte in der neuen Szene nicht benötigt werden ? Sonst wird das doch ein riesiger "Schwanz", wenn in meinetwegen 30 Szenen irgendwelche Objekte mit dem ObjektOeffnen-Script arbeiten. Ich hoffe, das mein Unbehagen ein Stück weit nachvollziehbar ist. 

Share this post


Link to post
Share on other sites

Wenn das ObjektOeffnen Script z.B. auf einer Schachtel oder einen Schrank zugewiesen ist und die 3 Objekte, die im Script zugewiesen sein könnten, quasi der Inhalt des Schrankes darstellen soll, dann wüsste ich nicht warum in dem Script die Objekte eines ganz anderen Schrankes aus einer anderen Szene drin sein sollten.

Genauso kann das Script auch ohne die 3 zugewiesenen Objekte auskommen. Wenn z.B. nur 1 Objekt zugewiesen wäre und somit 2 Slots leer sind, ist das ja kein Problem. Du musst aber im Script überprüfen, ob da ein eine Referenz vorhanden ist oder eben nicht.
Ein einfaches Beispiel:

public GameObject platz1;

void Irgendwas(){
  if(platzhalter != null){
    print(platz1.name);
  }
}

Kleines Praxisbeispiel:
Ich baue virtuelle Flipper. Und wie du das ja bei Flippern kennst, gibt es Ziele die man treffen muss. Diese Ziele spielen einen Sound ab, der aber abhängig davon ist, welchen Zustand die Ziele haben.
Jetzt könnte ich für jedes Ziel ein eigenes Script erzeugen und immer die selben Dinge einbauen. Das habe ich aber so nicht gemacht. Ich habe Soundobjekte gebaut, die irgendwo in der Szene liegen. Jedes Sound Objekt hat ein Script, welches ich von den Ziel-Objekten aus anspreche. Dieses Script heißt SFX_Script und da drin gibt es 3 public Funktionen. PlaySound, PlayBadSound und PlayThridSound habe ich die Funktionen genannt.
Wenn ich den Flipper baue, weiß ich noch gar nicht wieviele Soundobjekte ich brauchen werde und genauso weiß ich auch nicht wieviele Ziele oder Wege es geben wird, die einen Sound abspielen sollen. Da alle Soundobjekte das gleiche Script haben, kann ich schlecht per Code danach suchen. Deswegen hat ein Ziel oder ein Wegetrigger eine public Variable vom Typ SFX_Script, bei der ich dann das das entsprechende Soundobjekt rein fallen lasse, wenn ich es dann irgendwann erstellt habe, also die Sound erzeugt wurden.
Auch wenn es noch gar keine Sounds gibt ist mein Ziel_Script trotzdem funktionsbereit, weil ich eben da, wo das Script auf das SFX_Script zugreifen würde, vorher abfrage ob es denn nicht null ist.
 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×