Jump to content
Unity Insider Forum

Variable anhand einer anderen Variable definieren?


PM_Daniel

Recommended Posts

Hallo Leute,

ich bin eben auf ein kleines Problem gestoßen.

 

Hier erstmal die Situation.

Ich habe ein GameObject das einen gewissen Namen trägt, z.B.: Level1.

 

Nun habe ich zwei Skripte, das erste beinhaltet für jede Level einen Bool,

der je nach Status ob die Level geschafft ist oder nicht wahr oder falsch ist.

 

Im Zweiten frage ich diesen Bool ab.

 

Nun das Problem:

Ich möchte nicht für jede Level ein eigenes Script schreiben und möchte

deshalb anhand des Namens des Jeweiligen GameObjects eine gewisse

Variable abfragen.

 

    if (Level.this.gameObject.name == true) { }

 

So in etwa sollte es aussehen, nur klappt das natürlich nicht.

Gibt es also eine Möglichkeit hinter dem "Level." eine Variable aus dem aktuellen Script zu nehmen?

 

Ziel ist dann das Level.level1 beispielsweise abgefragt wird.

Oder eben auch Level.level2 anhand des GameObject Namen.

 

Vielen Dank schonmal. :)

Link zu diesem Kommentar
Auf anderen Seiten teilen

Poste mal mehr code.

Level sieht, weil es groß geschrieben ist erstmal nach einer Klasse aus. Da versuchst du auf this zuzugreifen? this ist ein reservierter Term. Bin nicht sicher, was du damit an der Stelle eigentlich machen willst.

 

Dann vergleichst du gameObject.name (wohl einen string? Zumindest wenn du von Monobehaviour erbst) mit einem bool. Das kann so gar nicht klappen =p

 

Ich würde dir empfehlen erstmal mit einfachen Coding Tutorials zu beginnen.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ich erkläre es mal einfacher.^^

 

Ich möchte aus der Klasse "Level" den "bool" abfragen.

 

Meine Frage allerdings ist nicht wie das funktioniert sondern:

 

Gibt es die Möglichkeit statt:

 

if (Level.level1 == true)

 

das "level1" durch eine Variable zu erstetzen?

 

Beispielsweise:

    levelName = this.gameObject.name;
    if (Level.levelName  == true) { }

 

Diese Version so funktioniert natürlich nicht, weil er die "levelName" Variable in der Klasse "Level" sucht.

 

Ich möchte ihm also sagen das er in der Klasse "Level" nach der Variable suchen soll die den gleichen Namen hat wie mein GameObject.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Sicher. Du musst nur in deiner Klasse Level eine public-Variable anlegen:

 

public class Level : MonoBehaviour {
public bool myBool = false;
}

 

Dann kannst du so drauf zugreifen:

public Level level; // hier muss natürlich eine Instanz des Objekts rein
level.myBool = true;
bool status = level.myBool;

Link zu diesem Kommentar
Auf anderen Seiten teilen

Wenn ich den ersten Post richtig verstaqnden habe möchtest du folgendes:

 

Dictionary<string, bool> levelNameToCompletion = new Dictionary<string, bool>();
...
levelNameToCompletion["Level1"] = false;
levelNameToCompletion["Level2"] = false;
levelNameToCompletion["Level3"] = false;
..

Debug.Log(this.gameObject.name + " abgeschlossen: " + levelNameToCompletion[this.gameObject.name]);
// Gibt zB aus:
// Level1 abgeschlossen: true

 

Du könntest aber auch dem GameObjekt ein simples Script geben was angibt für welches Level dieses GO sein soll:

 

public class LevelIdentificator : MonoBehaviour
{
 public int LevelIndex = 0;
}

 

Und dann kannst du einfach diese Komponente benutzen um auf ein Array von Level Stati zuzugreifen:

 

bool[] levelStatus = new bool[5]; // 5x ein bool
...
var levelIndex = GetComponent<LevelIdentificator>().LevelIndex;

Debug.Log(this.gameObject.name + " abgeschlossen: " + levelStatus[levelIndex]);
// Gibt zB aus:
// Level1 abgeschlossen: true

levelStatus[levelIndex] = true; // Level abgeschlossen

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ahh Mark hat mich verstanden. :D

Dank deiner Antwort hab ich einen Weg gefunden. :)

Allerdings hab ich es nun (meiner Meinung nach) etwas einfacher gestaltet:

public class Level : MonoBehaviour {
public static bool[] levelStatus = new bool[11];

void Start () {
	levelStatus[0] = true;
	levelStatus[1] = true;
	levelStatus[2] = false;
	levelStatus[3] = false;
	levelStatus[4] = false;
	levelStatus[5] = false;
	levelStatus[6] = false;
	levelStatus[7] = false;
	levelStatus[8] = false;
	levelStatus[9] = false;
	levelStatus[10] = false;
}

 

public class ErsteLevel : MonoBehaviour {
int levelint;

void Start()
{
	int.TryParse(this.gameObject.name, out levelint);
}
void Update () {

	if (Level.levelStatus[levelint] == true)
	{
	   //Ausgabe
	}
}
}

 

Ist der Name des GameObjects jetzt Beispielsweise "1", fragt er in dem Array nach "[1]" und weis dann

ob die Level freigeschaltet ist oder nicht. :)

 

Danke nochmal an alle beteiligten!

 

MfG. Daniel

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ist der Name des GameObjects jetzt Beispielsweise "1", fragt er in dem Array nach "[1]" und weis dann

ob die Level freigeschaltet ist oder nicht. :)

Ich würde Marks Variante aber trotzdem bevorzugen, weil du dein Level dann auch besser benamen kannst ^^

Ein Level das "Prolog" heißt gibt auf jeden Fall mehr Aufschluss als "1" ^^

Sowas könntest du eventuell auch dem User anzeigen lassen, falls du das möchtest.. Selbst wenn du es jetzt noch nicht brauchst, könntest du es trotzdem für andere Projekte wiederverwenden ^^

 

public class ErsteLevel : MonoBehaviour {

Erstellst du da für jedes Level eine eigene Klasse, die einfach nur schaut, ob ihr Level geladen ist? :o

Schreib das doch mit in die Level Klasse oder bau dir einen LevelManager oder sowas.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Erstellst du da für jedes Level eine eigene Klasse, die einfach nur schaut, ob ihr Level geladen ist? :o

Schreib das doch mit in die Level Klasse oder bau dir einen LevelManager oder sowas.

 

Nein, der Name der Klasse wurde noch nicht geändert. ;)

Ich wollte es vorher anders machen.

 

Ich würde Marks Variante aber trotzdem bevorzugen, weil du dein Level dann auch besser benamen kannst ^^

Ein Level das "Prolog" heißt gibt auf jeden Fall mehr Aufschluss als "1" ^^

Sowas könntest du eventuell auch dem User anzeigen lassen, falls du das möchtest.. Selbst wenn du es jetzt noch nicht brauchst, könntest du es trotzdem für andere Projekte wiederverwenden ^^

 

Ich muss ehrlich gestehen das ich es mit Marks Variante nicht zum laufen gebracht habe.

 

Der "LevelName" ist in diesem Fall nicht so Wichtig, da es sich hier nur um den Button der jeweiligen Level im Level-Auswahlmenü handelt.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Die Klasse ErsterLevel, nenne sie anders und mach die private variable public, so kannst du sie im Inspektor setzen und kannst auch die Start Methode entfernen. Viel simpler.

So simpel und doch so richtig...

Manchmal sieht man den Wald vor lauter Bäumen nicht...

Link zu diesem Kommentar
Auf anderen Seiten teilen

Public variables sind böse.

 

Zu behaupten dass public variables "böse" sind, ist einfach nur humbug.

Sowas sollte man nicht zu jemanden sagen der noch im Lernprozess ist, da dies eher den Lernprozess stört.

 

Es spricht also nichts dagegen marks lösungsvorschlag zu verwenden ;)

Link zu diesem Kommentar
Auf anderen Seiten teilen

Zu behaupten dass public variables "böse" sind, ist einfach nur humbug.

 

Das würde ich so nicht sagen. In der OOP-Denkweise die C# und Unity nunmal nutzen ist es best practice, den Zugang zu Daten möglichst weit zu beschränken. Heißt: Wenn du eine Variable hast, die nur das aktuelle Objekt verwendet sollte sie private sein. Wenn sie von allen gelesen UND gesetzt werden können soll ohne eine vorherige Überprüfung, dann public. Wenn sie nur von der eigenen Klasse und vom Editor verändert werden soll: private mit [serializeField].

 

Generell kommen public Variablen in wirklichem Code selten vor. Wenn dann als readonly property:

 

public int MyInt {get; private set;}

 

Ansonsten sollte der Zugriff auf Variablen (vor allem das Setzen) durch öffentliche Funktionen der Klasse erfolgen.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ich bin da auch mehr auf Silveryards Seite. Public Variablen sollten so sparsam eingesetzt werden wie möglich. Eine Property mit Get und Set hat noch den Vorteil, dass beim Set eine Validierung der Daten erfolgen kann.

 

Generell als Böse würde ich public aber auch nicht bezeichnen. Nur vorsichtig sollte man sein und sich die Probleme bewußt machen, die public eben mit sich bringt.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Meint ihr nicht, dass ihr es ein wenig übertreibt???

Public ist böse???

Jungejungejunge...

 

Da kommen neue User und wollen Infos aus Script A haben oder sogar Werte im Script A von außen verändern und nutzen dann static, weils auf den ersten Blick so schön einfach ist.

Das ist natürlich nicht der gute Weg. Böse ist static deswegen noch lange nicht.

Aber auf jeden Fall sollte man da helfen und argumentieren, warum static nicht der beste Weg ist.

 

Soweit alles gut, aber jetzt setzt ihr noch einen drauf und redet von Properties und Get und Set?

Sagt sogar Public sei böse!

Geht's noch?

Wenn hier einer anfängt zu programmieren, wird er die ganzen dollen Dinge und ihre Möglichkeiten noch nicht kennen.

Und natürlich nutzt er Public Variablen wenn dort unterschiedliche Scripte miteinander kommunizieren.

Er wird vielleicht sogar die Werte im Inspector zur Laufzeit ändern wollen, nur um zu sehen, wie sein System funktioniert.

Der jenige, der hier programmiert, tut das sowieso in der Regel alleine und nicht im Team. Was soll also passieren, wenn eine Variable Public ist?

Wenn er sie abfragen oder ändern will kann er es tun. Wenn nicht, dann lässt er es. Die Public Variable macht sich nicht sebstständig und die anderen Scripte ändern die Variable auch nicht, wenn es nicht extra so programmiert wurde.

 

Ihr seid echt Eisenhart!

Überdenkt mal eure Intention. Wir sind hier nicht im C# Profi Forum!

Link zu diesem Kommentar
Auf anderen Seiten teilen

Tja, da hast du natürlich völlig Recht. An meinem Arbeitsplatz ist neben Visual Studio auch Resharper und Stylecop im Einsatz. Jede Zeile Code wird von mindestens einem anderen Kollegen begutachtet, bevor was produktiv geht. Die Coding Conventions sind ziemlich restriktiv. Im täglichen Einsatz sehe ich dann aber, dass genau diese Praxis dafür sorgt, dass der Code übersichtlich und gut strukturiert bleibt, dass keine überflüssigen Abhängigkeiten bestehen und dass jeder den Code versteht, auch nach Jahren noch.

 

Wenn ich dann hier sehe, wie Einsteiger mit immer den gleichen Problemen auf immer die gleichen, weil simplen Lösungen zurückfallen, geht's manchmal mit mir durch. Aus professioneller Sicht kann ich Silveryard nur zustimmen. Allerdings muss man diese Aussagen in diesem Umfeld hier relativieren.

 

Also nochmal:

  • public static-Variablen würde ich auch bei kleinsten Spielen nur benutzen, wenn es absolut keinen anderen Weg gibt. Und den gibt's eigentlich immer.
  • public-Variablen sollten nicht inflationär benutzt werden. Wenn ein Script mehr als drei oder vier public-Variablen beinhaltet, ist es eventuell besser, ein neues Script zu erstellen, das einen Teil der Aufgaben übernimmt.

Der Grund für beide Behauptungen: jede public Variable in einem Script kann von jedem anderen Script aus mit jedem beliebigen Wert geändert werden. Ein Beispiel:

 

Ich habe im Player-Script eine Variable

public int Life;

Wenn der Gegner auf den Player schießt, fügt er direkt aus dem Gegnerscript heraus Schaden zu:

playerScript.Life -= 10;

Wenn ich eine Health-Box finde, setzt das Healthbox-Script das Playerleben hoch:

playerScript.Life += 10;

Der Spieler soll allerdings nicht über 100 Leben bekommen können, und wenn er Null Leben "erreicht", ist er tot.

 

Daher wäre es hier sinnvoller, das Ganze so zu implementieren:

// SpielerScript:
private int life;

public void ChangeLife(int amount)
{
life += amount;
if (life < 0)
{
 life = 0;
 ProcessPlayerDeath();
}

if (life > 100)
{
 life = 100;
}
}

Jetzt können andere Scripts nur auf die Methode zugreifen und die Plausibilitätsprüfung erfolgt dort, wo sie hingehört, im Spielerscript.

 

Wenn jetzt ein Einsteiger das doch auf die erste Art regelt? Tja, dann ist das halt so. Solange es funktioniert, spielt es keine Rolle. Wenn das Spiel immer weiter wächst und neue Funktionalitäten dazukommen, fliegt ihm diese Praxis um die Ohren, weil er nicht mehr durchblickt, wann was von wem geändert wird. Dann muss er halt das Ganze verwerfen und Teile neu schreiben.

 

Sollen wir ihm das von Anfang an gleich sagen? Wenn du es so machst, ist es auf lange Sicht Kacke? Wohl eher nicht. Man lernt praktisch nur aus Fehlern, die man selber macht. Allerdings kann ich auch nicht aus meiner Haut. Bei bestimmten Programmierpraktiken geht mir der Hut hoch, weil sie so viel Fehlerpotenzial enthalten. Darauf werde ich auch in Zukunft hinweisen. Ich kann nicht anders.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Macht doch einfach einen Extra Thread dafür auf, es wurde erwöhnt und es wurden Begründungen genannt, wenn der OP sich dafür interessiert kann er alles nun lesen. Als Anfänger ist die Chance dazu eher gering, aber es wurde von euch erwähnt. Der Rest hier geht einfach am Thread selbst vorbei.

 

Wieso hab ich eine public Variable genommen? Weils verdammt nochmal im Sinne eines Beispiels komplett ausreichend für den Fragesteller im Thread war. Attribute und sonstige Details gehen vermutlich momentan sehr am OP vorbei. Sowas kommt später aber nicht in diesem Status.

 

Ausserdem war mir die Nebenwirkung von SerializeField nicht bewusst (es taucht im Inspector auf).

Link zu diesem Kommentar
Auf anderen Seiten teilen

Schon witzig, wie energisch ihr alle werdet. Ich hab nur vorgeschlagen an der Stelle public durch [serializeField] zu ersetzen. Schließlich ging es darum, dass man den Wert der Variable im Inspector setzen kann. Das verstehen doch auch Anfänger.

 

Aber ja, geht auch mit public.

 

Im Informatikstudium sind Access Modifiers so mit das erste was man gelehrt bekommt. Deswegen schaffe ich gerne Bewusstsein dafür. Es wurde ja niemand beleidigt hier. Wenn jemand was dazu gelernt hat ist es doch auch schön.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Archiviert

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

×
×
  • Neu erstellen...