Jump to content
Unity Insider Forum

Script to Script Werte Übergabe Noobfrage


Rasmusen

Recommended Posts

Leider verstehe ich es nicht . Ich habe so viele Tutorials durch und weis eigentlich auch wie ich Werte aus anderen Scripten benutze und Werte weitergebe. Public und dann das Script anbinden. Aber genau das geht ja nicht bei Instanzierten Objecten. Dann werden nämlich Anbindungen von anderen Componenten nicht übernommen.

 

Ich komme also nicht weiter . Folgendes :

 

Ich habe einen Enemy . Der Enemy hat den Wert Leben = 10 . Der Enemy wird durch Attacken destroyed. Dann wird ein neuer Enemy Instanziert . Aber folgendes soll passieren. Vor dem Zerstören soll +1 an das GamePlay Script gesendet werden . EnemyCount +1 so zusagen. Dieser Wert soll dann bei einem neu Erzeugten Enemy folgendes machen : Leben * EnemyCount. Der EnemyCount sitz ja aber in einem anderen Script. Ich habe das Problem das ich nicht weis wie ich das machen soll weil ich das GamePlay Script ja nicht per Drag and Drop an das Enemy Game Object im UnityPanel einbinden kann. Das ist nach dem Initiate ja wieder leer. Klar , das ist eine Noobfrage , aber ich weis auch nicht wie ich das bei Google vernünftig eingeben soll das ich eine Antwort erhalte. Da kommen immer Mega Umfangreiche und komplizierte Seiten. Kann mir das irgendjemand erklären so das ich das für immer verstehe. Weil ich beiss mir hier seit Stunden die Zähne dran aus.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Es gibt... sagen wir... drei Möglichkeiten, wie existierende Objekte sich kennen lernen können.

 

Die erste ist für Fälle, in denen der Wert zum Start der Szene bereits bekannt ist und vermutlich ewig erhalten bleibt. Sowas geht über Zuweisungen im Editor oder über Code in Awake. In vielen Situationen will man statt public lieber [serializeField] benutzen:

[serializeField]
private Light someLight;

Damit ist das Feld private und andere Scripts können nicht daran herumfummeln. Durch die Annotation [serializeField] kann man aber wie bei public einen Wert im Editor zuweisen. Alternativ wird über Code in Awake etwas gefunden:

private Light someLight;

void Awake()
{
 someLight = GetComponentInChildren<Light>();
}

Nur ein Besipiel.

 

Die zweite Möglichkeit sind Events. Wenn z.B. zwei Objekte kollidieren, löst das ein Event aus, und Referenzen der beiden Teilnehmer werden an den jeweils anderen gesendet. So lernen sie sich kennen und können miteinander arbeiten.

void OnTriggerEnter(Collider other)
{
 Debug.Log("Hallo, " + other.gameObject.name);
}

Mit ein bisschen simplem Code kann sich ein Objekt diese anderen Objekte auch merken, nachdem es sie in einem Event kennengelernt hat.

 

Variante 3 wäre eine Zuweisung durch ein anderes Skript. Hierbei ist public eher sinnvoll als in Variante 1.

Hierbei baut man entweder eine öffentliche Variable/Property oder eine Methode, die Werte entgegen nimmt. In einem einfachen Fall reicht eine Variable:

public Transform target;

void LateUpdate()
{
 if(target)
 {
Follow(target);
 }
}

Wenn ein anderes Skript bereits eine Referenz auf eine Komponente des obigen Skripts hat, geht die Zuweisung ganz einfach:

follower.target = irgendeinTransform.

Die Referenzen in "follower" und "irgendeinTransform" können jetzt wieder auf eine der drei Arten gewonnen werden.

Beispiel:

[searializeField]
private Follower follower;

void OnTriggerEnter(Collider other)
{
 follower.target = other.transform;
}

Dieses Script könnte auf einem Trigger-Collider liegen, und sorgt dafür dass der Follower (Skript weiter oben) immer anfängt, dem Objekt zu folgen, das in den Trigger fliegt.

 

Wenn deine Objekte jetzt mit Instantiate erzeugt werden, muss man nur eine einzige Sache beachten: Instantiate gibt die Referenz auf das erzeugte Objekt zurück:

[serializeField]
private GameObject prefab;
[serializeField]
private Follower follower;

public void Spawn()
{
 var spawnee = (GameObject)Instantiate(prefab);
 follower = spawnee.transform;
}

Die zurück gegebene Referenz auf das gespawnte Objekt wird in "spawnee" gespeichert. Die Transform-Komponente wird in der nächsten Zeile rausgesucht und wie weiter oben bereits gezeigt weitergegeben.

 

Ich hoffe, das hilft ein bisschen :)

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ui... das war aber jetzt Nice erklärt. Sogar so das ich es endlich mal begriffen habe. Und natürlich funzt jetzt auch das was ich wollte. Echt 1000 Dank dafür.

Freut mich!

 

Ach doch eins hab ich noch nicht verstanden in dem Zusammenhang. Was bedeutet Static ? Also Public Static. Weil statisch ist der Wert ja nicht , ich kann Ihn ja andauernd ändern. Deshalb versteh ich die Logik dahinter nicht.

"Statisch" bezieht sich auf die Variable selbst, nicht dessen Wert. Alle Werte, die ein Programm speichert, sind ja im Arbeitsspeicher in Form von Bits. Eine Variable beschreibt einen Bereich des Speichers und die Bits in diesem Bereich sind der Wert der Variablen.

static macht, dass die Variable einen statischen Bereich im Speicher bekommt. Solange das Programm läuft, bleibt dieser Speicherbereich für diese eine Variable reserviert und die Variable wird damit unsterblich.

Zum Vergleich eine nicht-statische Variable: Du hast eine Gegner-Klasse, die eine Variable "Health" hat. Ein neuer Gegner spawnt und entsprechend muss neuer Platz für seine Health-Variable gemacht werden. Da nicht von vorneherein klar war, dass es diesen Gegner geben würde, gab es auch nicht von Anfang an Speicherplatz für dessen Health-Variable. Wird der Gegner zerstört, wird der Speicherbereich wieder frei gemacht und irgendwann wieder von etwas anderem benutzt.

 

Eine statische Variable hat natürlich den Nebeneffekt, dass es nicht mehrere davon geben kann. Es gibt einen Speicherbereich dafür und das war's. Entsprechend sind statische Variablen nicht in den Objektkontext gebunden. Würdest du Enemy.health static machen, würde nicht jeder Gegner seine eigene Health-Variable kriegen, sondern alle teilen sich denselben Speicherbereich. Das ergibt natürlich gar keinen Sinn.

static ist also für objektübergreifende Sachen da. Eine mögliche Anwendung gibt es, wenn du entscheidest, dass es nur einen Spieler gibt. Dann kannst du eine statische Variable machen:

public class Player : MonoBehaviour
{
 public static Player singleton { private set; get; }

 void Awake()
 {
singleton = this;
 }
}

"singleton" ist keine Variable, sondern eine "Property". In diesem Fall ist das fast dasselbe, aber man kann nur private einen Wert setzen, während andere Klassen den Wert nur lesen können.

In Awake wird die Referenz auf "mich" in singleton gespeichert. Da statische Variablen nicht an bestimmte Objekte gebunden sind, sondern global existieren, erleichtern sie den Zugriff. Eine andere Klasse kann den Spieler jetzt so finden:

Player.singleton

und dann z.B:

Player.singleton.Kill();

Andere Anwendung:

public class Enemy : MonoBehaviour
{
 private static int enemyCount = 0;

 void Awake()
 {
enemyCount++;
 }

 void OnDestroy()
 {
if(--enemyCount == 0)
{
  Debug.Log("All enemies are dead.");
  LevelManager.singleton.LevelComplete();
}
 }
}

Ich denke, es ist klar, was hier passiert :)

 

//edit: Habe eben noch ein paar Schreibfehler nachträglich korrigiert...

Link zu diesem Kommentar
Auf anderen Seiten teilen

Archiviert

Dieses Thema ist jetzt archiviert und für weitere Antworten gesperrt.

×
×
  • Neu erstellen...