Jump to content
Unity Insider Forum

Performance fragen


Strooja0108

Recommended Posts

Hi Leute,

ich bin neu hier . Ich versuche gerade ein kleines Spiel umzusetzen und haette deshalb einige Fragen an euch.Ich hoffe ihr koennt mir da weiterhelfen. es wird ein 2D Spiel welches auf Pc jedoch auch auf Andorid laufen soll.Deshalb versuche ich es so smart wie mir moeglich zu programmieren. Hier nun ein paar Fragen.

1 Frage:

Ich habe zwei Buttons . Der eine soll ein Menue oeffnen in dem man verschiedene Schwerter kaufen kann. Jedes Schwert hat unterschiedliche Attribute. Zurzeit importiere ich jedes dieser Attribute aus unterschiedlichen arrays( Preis ,staerke,Geschwindigkeit....). Ist es klueger dies in einem mehrdimensionalen Array zu speichern oder ist meine technik auch ok? Mit dem zweiten Button soll das gleiche menue geoffnet werden jedoch mit Schildern. Sollte ich hierfuer ein komplett neues script, neue buttons und alles neu erzeugen. Oder einfach das script vom ersten button nehmen und einfach ueberpruefen welcher button geklickt wurde und dementsprechend die array listen laden? Was ist performance technisch am kuegsten oder spielt das bei so geringen Daten(in jedem array sind vielleicht 20 integer) keine Rolle?

2 Frage:

Kann man irgendwo sehen wie viele Abfragen ein Handy oder Computer so pro Sekunde schafft ohne das es ruckelt. Ich habe zurzeit 2 scripte die die ganze zeit laufen und ungefaehr 30 Abfragen pro millisekunde testen.Ich denke das ist mehr als ok aber ab wann sollte ich aufpassen?

 

3 Frage:

Ist es korrekt das wenn ich ein Gameobject auf .setActive(false) setze, dass Object gehided wird und  die scripte auf diesem Object auch gestoppt werden?

 

4 Frage:

Ich habe 2 Hauptscripts(Timescript,Player)  wobei ich das eine in das jeweils andere hineinlade um so an die Daten des anderen zu gelangen. Das mache ich in dem ich schreibe

In Player:

public Timescript  DataTiemscript;

Ist das der richtige weg das zu machen? Ich hab verstanden das ich so eine instance des anderen scriptes erstelle und so zugriff auf die Daten habe.

 

Ich programmiere jetzt seit 2 Monaten immer mal wieder an dem Spiel und es geht sehr gut vorran ich wollte nur mal hoeren ob meine Art zu programmieren auch nur einigermassen richtig ist(Hab seit 7 Jahren nicht mehr programmiert und noch nie Object based). Bis jetzt funktioniert alles. Aber es soll ja auch ordentlich sein :)

 

Ich bedanke mich schonmal fuer eure Hilfe

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hi!

vor 3 Stunden schrieb Strooja0108:

Zurzeit importiere ich jedes dieser Attribute aus unterschiedlichen arrays( Preis ,staerke,Geschwindigkeit....). Ist es klueger dies in einem mehrdimensionalen Array zu speichern oder ist meine technik auch ok?

Weder, noch. Bitte benutze Objekte dafür. Also statt

int[] prices;
int[] strengths;
int[] speeds;

einfach

class Sword
{
  public int price;
  public int strength;
  public int speed;
}

und dann

Sword[] swords;

Damit sind deine Werte schön innerhalb von einem Schwert gruppiert, anstatt dass da eine unsichtbare Verbindung zwischen deinen Zahlen verschiedener Arrays besteht, die einzig durch denselben Index in den Arrays definiert ist.

Wenn du deine Schwert-Klasse jetzt noch von ScriptableObject erben lässt und ein nettes Attribut draufknallst, kannst du deine Schwerter sogar schön im Editor als Assets erstellen und anpassen.

vor 3 Stunden schrieb Strooja0108:

Kann man irgendwo sehen wie viele Abfragen ein Handy oder Computer so pro Sekunde schafft ohne das es ruckelt. Ich habe zurzeit 2 scripte die die ganze zeit laufen und ungefaehr 30 Abfragen pro millisekunde testen.Ich denke das ist mehr als ok aber ab wann sollte ich aufpassen?

Grundregel für Performance: Nicht lange fackeln, sondern ausprobieren und daran herumschrauben, wenn es sich als Problem herausstellt. Wegen güffeliger 30 Abfragen in Update braucht kein modernes Handy überhaupt den Ofen anschmeißen. Wenn du dann doch etwas feststellst, hilft dir der Profiler beim identifizieren von Problemquellen.

Aber ernsthaft, mach dir da bitte keinen Kopf. Jeder noch so krüppelige Handyprozessor knallt dir heutzutage problemlos zehn- bis zwölfstellig Operationen pro Sekunde raus.

vor 3 Stunden schrieb Strooja0108:

Ist es korrekt das wenn ich ein Gameobject auf .setActive(false) setze, dass Object gehided wird und  die scripte auf diesem Object auch gestoppt werden?

Ein deaktiviertes GameObject bedeutet, dass alle seine Komponenten inaktiv werden. Das gilt natürlich auch für den Renderer.

Im Gegensatz zu "enabled = false;" werden bei "SetActive(false)" aber auch alle laufenden Coroutinen gestoppt.

Was aber nicht darunter fällt ist, dass man mit Objekten interagieren kann. Die Komponenten kriegen keine MonoBehaviour-Events mehr (Start, Update, ...), aber wenn dein Code zu dem Objekt geht und eine Methode aufruft, dann wird die nach wie vor ausgeführt.

vor 3 Stunden schrieb Strooja0108:

4 Frage:

Ich habe 2 Hauptscripts

 

vor 3 Stunden schrieb Strooja0108:

Ich hab verstanden das ich so eine instance des anderen scriptes erstelle und so zugriff auf die Daten habe.

Nicht wirklich. Wenn du in deinem Code

Typ name

schreibst, dann deklarierst du eine Variable. Das ist ein kleines Stück Speicher, in dem ein Wert drinstehen kann. Ist "Typ" z.B. "int", dann steht in diesem Speicherbereich eine Zahl. Welche Zahl da drinsteht, kannst du mit einer Zuweisung ändern.

int zahl;
zahl = 10;

Wenn aber "Typ" ein Objekttyp ist, also der Name einer Klasse (z.B. einer Komponente), dann steht in diesem Speicherbereich die Position eines Objekts dieses Typs, die sogenannte "Adresse", oder der Wert für "null", also "kein Objekt".

Wenn du also "Timescript  DataTiemscript" schreibst, dann reservierst du einen kleinen Speicherbereich, um darin die Adresse eines "Timescript"-Objekts irgendwo anders im Speicher einzutragen. Aber es wird kein "Timescript"-Objekt erstellt, und ohne weiteres Zutun steht da nicht einmal eine Adresse drin.

In Unity hast du halt die Eigenart, dass du im Editor in ein solches Feld ein Objekt einfach mit der Maus reinziehen kannst. Ich bin mir recht sicher, dass du das auch schon gemacht hast. Du ziehst also dein GameObject mit dem "Timescript"-Script in dein Feld und speicherst die Szene. Das ist sehr vergleichbar damit,

zahl = 10;

zu schreiben, also eine Zuweisung. Bemerke, dass du aber das GameObject vorher selbst erstellt hast, und dass du auch dein Timescript da draufgezogen hast. Das ist der Moment, wo das Objekt erstellt wurde. "Timescript  DataTiemscript" erstellt halt nur die Variable.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Wow erstmal vielen vielen Dank für deine ganze Hilfe . Das ist echt super. Wenn du nichts daegen hast hätte ich noch ein paar folge Fragen zu den bisher genannten.

Zu Frage 1. Mit Object erstellen meinst du eine eigenen Klasse erstellen oder ist das wieder was anderes?ICh muss leider sagen ich verstehe es nicht ganz.Wenn ich das Object erstelle wie fülle ich es vorher. Es geht hier nicht um ein Schwert ausrüsten sondern um ein Kauf Menü.Also ich habe  ein Panel und 3 Buttons "Vorher,Kaufen,Nachher". DAs heisst ich brauche ja eine Art Datenbank wo Preis ,Stärke usw. von jedem Schwert steht.Und das habe ich bis jetzt halt in vielen arrays vorher definiert.Wie mache ich das denn in einem Object? Und wie rufe ich dann die einzelnen Variablen aus dem Object auf? Sorry vermutlich sehr einfach aber wie gesagt Object orientiert habe ich bis jetzt noch nicht gemacht.

 

Zu Frage 4: Es geht nur darum das ich von einem Script auf das andere zugreifen kann.Zurzeit mache ich das denke ich wie du beschrieben hast. ich erstelle ein Object  und ziehe darauf das Object auf dessen das zweite Script läuft und habe somit zugriff auf das script.Ich habe aber was davon gelesen das man besser eine instance von dem zweiten script erstellt,dass wäre besser. Was denkst du?

 

 

Danke nochmal vielmals für deine Hilfe du hast miche cht weiter gebracht.

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 1 Stunde schrieb Strooja0108:

Mit Object erstellen meinst du eine eigenen Klasse erstellen oder ist das wieder was anderes?

Eine Klasse ist ein Stück Code, das als Bauplan für Objekte funktioniert. Ein Objekt ist dann ein Ding im Speicher, das spezifische Werte für alle Zustandsfelder (=Variablen außerhalb von Methoden) speichert. Nehmen wir mal eine Beispielkomponente:

public class Dingsbums : MonoBehaviour
{
  public Color color;
}

Sie hat ein Zustandsfeld "color". Ich ziehe einfach mal zwei davon auf ein GameObject:

image.png

Was du hier repräsentiert siehst, sind zwei Objekte. Eines mit einer roten Farbe für "color" und eines mit einer blauen Farbe. Beides sind Instanzen derselben Klasse "Dingsbums". Und selbst, wenn sie die gleiche Farbe hätten, wären es immer noch zwei verschiedene Objekte. Wenn du also ein Script auf ein GameObject ziehst (oder auch eine beliebige andere Komponente hinzufügst), dann repräsentiert dieser Abschnitt im Inspektor ein neues Objekt, das du gerade erstellt hast. Und die Felder und Funktionen die es hat entsprechen dem, was die zugrundeliegende Klasse vorgibt.

Jetzt sind aber Komponenten nicht die einzige Art von Objekten, die es gibt. GameObjects sind auch Objekte der Klasse "GameObject". Jedes einzelne deiner Assets wird von Unity als Objekt interpretiert. So ist deine Grafik ein Texture2D-Objekt und deine Sound-Datei kommt als AudioClip-Objekt an.

vor 1 Stunde schrieb Strooja0108:

Wenn ich das Object erstelle wie fülle ich es vorher.

Kommt ganz auf die Art deines Objekts an. Ein AudioClip ist bereits automatisch von Unity mit den Sound-Daten gefüllt, weil Unity die Sound-Datei lädt. Eine Komponente ist mit den Daten gefüllt, die du im Inspektor einstellst - die lädt Unity dann beim Szenenstart (oder beim instanziieren eines Prefabs). Wenn dein Objekt kein "UnityEngine.Object" ist (wie z.B. Komponenten es sind), dann lädt Unity dir gar nichts. Dafür kannst es mit Code selber zusammenbasteln. Ich könnte da kurz drauf eingehen, wie das aussehen kann, aber ich denke, ich beschränke mich lieber auf das, was ich auch empfehlen würde... wird nämlich schon ein bisschen viel auf einmal.

Stattdessen, probiere mal ScriptableObjects aus. Packe dir dieses Script in deine Assets:

using UnityEngine;

[CreateAssetMenu]
public class Sword : ScriptableObject
{
  public int price;
  public int strength;
  public int speed;
}

Da sind jetzt zwei neue Sachen:

  1. Die Klasse erbt von "ScriptableObject" statt von "MonoBehaviour". Damit ist es keine Komponente mehr. Du wirst feststellen, dass du dieses Script nicht auf ein GameObject ziehen kannst.
  2. Das Attribut [CreateAssetMenu] fügt diese Klasse zum "Create"-Menü deiner Project View (und dem Menüpunkt "Assets" ganz oben links) hinzu.

Speichere die Datei und lass Unity kompilieren. Als nächstes kannst du mitten in deine Assets rechtsklicken, dann gehst du auf "Create" und solltest ganz oben "Sword" finden. Wenn du da draufklickst, erstellst du wieder ein neues Objekt vom Typ "Sword", aber nicht als Komponente auf einem GameObject, sondern als Asset in deinem Projekt. Das kannst du jetzt anklicken, einen Namen geben und wie eine Komponente im Inspektor bearbeiten. Und du kannst es in andere Objekte reinziehen, um es zu referenzieren. Zum Beispiel kannst du eine Shop-Komponente basteln, indem du ein Array von Schwertern anlegst, die zum Verkauf stehen:

public class Shop : MonoBehaviour
{
  public Sword[] swordsForSale;
}

Da kannst du alle Schwerter in die Liste ziehen, die der Laden im Angebot haben soll.

Deine Datenbank, die du haben willst, besteht dann aus lauter einzelnen Objekten, die du in deinen Assets einzeln anklicken und bearbeiten kannst.

vor 2 Stunden schrieb Strooja0108:

Und wie rufe ich dann die einzelnen Variablen aus dem Object auf?

Punktnotation!

Mal so als Beispiel könnte man die Schwerter des Shops alle in einer Start-Methode auflisten:

private void Start()
{
  foreach (var sword in swordsForSale)
  {
    Debug.Log(sword.name + ": " + sword.price + " gold");
  }
}

Auf "strength" und "speed" kannst du genauso zugreifen wie auf "price". Das gilt natürlich für alle weiteren Felder, die du der Sword-Klasse gibst, solange sie "public", also öffentlich sind.

vor 2 Stunden schrieb Strooja0108:

Ich habe aber was davon gelesen das man besser eine instance von dem zweiten script erstellt,dass wäre besser. Was denkst du?

Du schreibst direkt vorher:

vor 2 Stunden schrieb Strooja0108:

ich erstelle ein Object  und ziehe darauf das Object auf dessen das zweite Script läuft

In dem Moment, in dem du das zweite Script auf ein GameObject gezogen hast, hast du wie gesagt bereits eine Instanz erstellt. Durch das Ziehen in den Inspektor des ersten Scripts hinterlegst du lediglich eine Referenz, die dem einen Objekt sagt, wo es das andere im Speicher finden kann.

Allgemein gilt zum Problem "wie mache ich, dass Objekt A Objekt B kennt" zu sagen, dass viele Wege nach Rom führen, und jede Variante hat ihre Vor- und Nachteile. Da jetzt ins Detail zu gehen, würde extrem zu weit führen. Du wirst jahrelang immer neue Varianten kennenlernen, diese Frage zu beantworten. Ich benutze Unity jetzt seit zehn Jahren und habe das letzte Jahr an einem Asset-Store-Paket gearbeitet, das ich vor kurzem veröffentlicht und hier vorgestellt habe. Dabei geht's genau um diese Frage, und seit ich das zugrunde liegende Video geschaut habe (siehe Link) und das Ding implementiert habe, arbeite ich niemals mehr ohne. Damit läuft bei mir alles wesentlich besser, und trotzdem bin ich neun Jahre lang ohne ausgekommen ;)

Daher eins nach dem anderen, und für die erste Zeit gilt auf jeden Fall: Solange es funktioniert, ist es schonmal gut. Und sobald du selber Probleme bemerkst und dich fragst, ob das eventuell an der Herangehensweise liegt, sag Bescheid ;)

Link zu diesem Kommentar
Auf anderen Seiten teilen

Unfassbar nochmal vielen Dank ist ja unglaublich was für ne Hilfe man hier bekommt. Also ich hab das mit den Asset erstellen ausprobiert und es funktioniert wunderbar.

Noch einmal zum Verständniss. Das heisst in Unity ist alles ein Object, von einem bestimmten Typ.Objects  vom Typ GameObject z.B.  können  andere Objects aufnehmen.Und zwar Objects wie ein Script,Image, Renderer..... die man in dem Fall dann auch Komponenten nennt. Ausserdem bedeutet es das man eigentlich IMMER mit Instancen arbeitet. Denn sobald man z.B. ein script auf ein Object zieht ist das nur eine Instance vom original script ,richtig?

 

 

Tut mir leid  eine Frage hätte ich da aber erstmal noch und zwar die weshalb ich ursprünglich hier hingekommen bin . Das Thema mit den zwei Buttons die die selbe UI öffnen sollen.

Da du sagt das es bei der Performance kein Problem gibt, würde ich einfach im script checken welcher der beiden Buttons geklickt wurde (sword oder schild) und dementsprechend das array mit den objekten laden und anzeigen.  Stande nämlich bis jetzt vor dem Problem wenn ich das nicht so machen möchte und zwei scripte schreibe.Das ich dem "Kaufen" Button zum Beispiel nur ein onclick Event geben konnte entweder sword kaufen oder schild kaufen und der Button slebst nicht wusste in welches array er schauen muss um den Preis zum Beispiel vom Geld abzuziehen. 

Sorry ist doof erklärt aber weiss auch nicht wie ich es anders machen soll.

Auf jeden Fall nochmal vielen Dank für deine ganze Hilfe ich werde mich dann jetzt mal wieder dran setzen und schauen wie weit ich komme.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Gerade eben schrieb Strooja0108:

Noch einmal zum Verständniss. Das heisst in Unity ist alles ein Object, von einem bestimmten Typ.Objects  vom Typ GameObject z.B.  können  andere Objects aufnehmen.Und zwar Objects wie ein Script,Image, Renderer..... die man in dem Fall dann auch Komponenten nennt. Ausserdem bedeutet es das man eigentlich IMMER mit Instancen arbeitet. Denn sobald man z.B. ein script auf ein Object zieht ist das nur eine Instance vom original script ,richtig?

Exakt, bis auf eine Kleinigkeit: Das ist meiste ist nichts Unity-spezifisches, dass alles und jeder ein Objekt ist, ist normal bei objektorientierten Sprachen wie C#. Das GameObject/Komponenten-System gehört da schon nicht mehr zu, ist aber auch nichts, was Unity erfunden oder patentiert hätte :)

vor 2 Minuten schrieb Strooja0108:

Da du sagt das es bei der Performance kein Problem gibt, würde ich einfach im script checken welcher der beiden Buttons geklickt wurde (sword oder schild)

Von Performanceproblemen kann hier so oder so nicht die Rede sein, aber ich empfehle, das ganze so aufzubauen, dass dein Code nicht zu einer großen Portion Spaghetti wird. Und dafür ist es sinnvoller, auf dem Button zu definieren, was der Button macht, als irgendwo anders eine Abfrage einzuführen. Du könntest einem Script zwei Methoden geben: "ShowSwords" und "ShowShields", und dann ruft der eine Button die eine Methode auf und der andere die die andere.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Sehr gut wenigstens hab ich ein wenig verstanden.^^ Noch einmal zurueck zu dem Button problem. ICh habe mal ein Bild erstellt . Wo zu sehen ist was ich habe. Du sieht hier das Fenster das sich oeffnen soll wenn ich auf Schwert oder Schild klicke .Je nachdem worauf ich geklickt habe wird halt ein unterschiedliches Array geoeffnet. Ich habe jetzt auf den buttons vorher und next die abfragen gemacht ob das schwert/schild schon freigeschaltet ist und ob man genug geld hat. Ausserdem wird natuerlich der index des arrays hoch und runter gezaehlt. Ueber den Buy button kaufe ich dann logischerwise das item ind em ich einfach in dem iobject array "gekauft" auf eins setze und das geld abziehe. Soo jetzt ist halt dieses Problem das ich gerne das selbe Fenster benutzen moechte und zurzeit ueberpruefe ich halt bei jedem Button klick welcher Button am Anfang geklickt wurde und je nachdem oeffne ich das passende Array(Schild oder Sword). Sollte ich das Fenster einfach zweimal erstellen und die scripte seperat erstellen .Oder denkst du mit der if Abfrage ist es zwar etwas mehr durcheinander dafuer aber kompakter??

Sorry das ich nochmal mit dem Thema komme. Wuerde nur gerne wissen wie das jemand erfahrendes das machen wuerde.

untitled.png

Link zu diesem Kommentar
Auf anderen Seiten teilen

Einmal das Fenster erstellen und es für alle Items immer wieder benutzen klingt sehr gut. Du kannst das so machen, dass du die UI-Elemente, die die Daten des Items anzeigen, referenzierst (wieder mit reinziehen) und dann deren Eigenschaften (Text, Bildinhalt, ...) mit denen des Sword-ScriptableObjects überschreibst, sobald du wechselst.

Könnte zum Beispiel so aussehen:

public Text nameDisplay;
public Text priceDisplay;
public Text speedDisplay;
public Image itemGraphicDisplay;

public Sword[] swordsForSale;
// The index of the currently displayed sword
private int displayIndex = 0;

private void Start()
{
  UpdateDisplays();
}

// Das hier muss der "Next"-Button auslösen
public void DisplayNext()
{
  displayIndex++;
  if (displayIndex >= swordsForSale.Length)
  {
    displayIndex = 0;
  }
  UpdateDisplays();
}

// Das hier muss der "Previous"-Button auslösen
public void DisplayPrevious()
{
  displayIndex--;
  if (displayIndex < 0)
  {
    displayIndex = swordsForSale.Length - 1;
  }
  UpdateDisplays();
}

private void UpdateDisplays()
{
  var sword = swordsForSale[displayIndex];
  
  nameDisplay.text = sword.name;
  priceDisplay.text = sword.price + " Gold";
  speedDisplay.text = sword.speed + "";
  itemGraphicDisplay.sprite = sword.graphic;
}

In die Displays oben ziehst du die richtigen Objekte, dann gibt's wieder die Liste an Schwertern, wo du alle Schwerter reinziehst. Dann verkabelst du noch die Buttons mit den richtigen Methoden. DisplayNext und DisplayPrevious machen nichts weiter als hoch- und runterzählen, aber wenn der index am Anfang oder am Ende vorbei geht, fängt's an der jeweils andere Seite wieder an. Dann wird UpdateDisplays aufgerufen, welches das Schwert mit dem aktuellen Index aus dem Array holt und dessen Werte in die UI-Elemente stopft.

Link zu diesem Kommentar
Auf anderen Seiten teilen

^^ Jepp genau so mach ich das.Das einzige Problem was ich halt habe ist wie ich feststellen soll ob gerade Sword oder SCchild reingeladen werden soll. Ich hab mir jetzt ueberlegt das ich dem Button Schild eine  onclick variable mitgebe "2" und Sword "1" waehrend die methode updateDisplays aufgerufen wird und dann bei den 3 Buttons teste was geladen werden muss. Z.b:

private void UpdateDisplays(int clicknumber)
{
  if(clicknumber==1)
  var liste = swordsForSale[displayIndex];
  else
  var sliste= schildForSale[displayIndex]; 
  
  nameDisplay.text = liste.name;
  priceDisplay.text = liste.price + " Gold";
  speedDisplay.text = sliste.speed + "";
  itemGraphicDisplay.sprite = liste.graphic;
}

 

Also ist jetzt gerade natuerlich nicht richtig geschrieben alles.Ist nur als Beispiel gedacht um mein Problem bis jetzt zu erklaeren. Denkst du eine mitgegebene variable per klick um zu checken welche liste gerade geladen werden musst ist der richtige Ansatz?

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hey ja ich hab es einfach doof erklärt denke ich.Ich weiss nicht wirklich wie ich das machen könnte. Aber jetzt läuft es erstmal.Nur ein Problem habe ich. Ich habe in der CreateAssetMenu scriptableObject klasse  eine variable erstellt und wenn ich die in meinem Spiel hochzählen lasse und das Spiel wieder neustarte wird die variable nicht wieder auf 0 gesetzt. Wie mache ich das. Ich habe es ganz normal mit public int amount =0 ;     versucht,aber das geht nicht.

Link zu diesem Kommentar
Auf anderen Seiten teilen

ScriptableObjects eignen sich erstmal am besten für Daten, die einfach nur geladen werden, sich dann im Spielverlauf aber nicht ändern. Bei meinem ScriptableObject-basierten Paket können die das zwar, dass sie sich wieder zurücksetzen, aber das ist keine ganz einfache Sache gewesen. Es ist daher eher eine Idee, die ScriptableObjects ausschließlich für konstante Daten zu benutzen und dann andere Objekte für die dynamischen Daten zu nehmen.

Es sei denn natürlich, du brauchst keine serialisierten Startwerte. Also, sprich: Du brauchst keine Startwerte im Editor eingeben, dann kannst du Variablen auch einfach komplett aus Unitys Händen nehmen. Wenn deine Variable öffentlich sein soll, kannst du dieses Attribut drübersetzen:

[System.NonSerialized]
public int amount = 0;

Falls da jetzt ein paar offene Fragen zu dem Thema sind, hilft vielleicht das hier: http://blog.13pixels.de/2019/an-intro-to-serialization-in-unity/

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hi danke wieder einmal für deine super Antwort.Ich habe mir das durchgelesen und verstehe es so das erstmal alle public variablen gespeichert werden.Ich verstehe aber nicht was die Scriptable Objects damit zutun haben, dass die Werte nicht auf ihren Default wert zurückgesetzt werden. Das passiert doch bei all meinen anderen public variablen auch. Ich denke schon das ich die variablen serializable haben möchte.Gerade sowas wie anzahl der schwerter sollte man ja speichern können.Ich habe mir jetzt überlegt das ich für die Anzahl der items dann doch einfach ein array mache.Das wäre dann ja immernoch kompakt genug.Anhand des index kann ich die Menge der Schwerter dann ja einfach den Schwertern zuordnen.

Es tut mir leid aber ich komme mit weiteren Fragen zu dir wo ich hoffe das du mich in die richtige Richtung lenken kannst. Es geht wieder einmal um das Menü ;) . Ich habe es jetzt mal etwas ausführlicher gezeichnet um mein Problem zu verdeutlichen. Die grünen Buttons sollen alle das grüne Kauf Menü aufrufen und sollen nur andere Gegenstände anzeigen. Wenn ich jetzt den Schwert Button  drücke könnte ich eine Methode erstellen die dann das erste Schwert anzeigt.Das ist richtig und so ähnlich mache ich das auch. Das Problem ist die drei roten Buttons müssen ja auch wissen in welchen Listen sie gerade gucken müssen, um das nächste Object anzuzeigen oder um zu überprüfen ob man genug Geld für das Object hat. Zurzeit gebe ich den roten Buttons eine Variable mit die von den grünen Buttons kommt, um zu überprüfen welche Listen geladen und angezeigt werden müssen. Z.b. als onclick event  sage ich beim Schwert Button " selection=1 " und überprüfe dann bei den roten Buttons welchen wert selection hat und rufe dementsprechend die Listen auf. Du sagtest du würdest das nur mit Methoden machen .Ich weiss nicht wie ich den roten Buttons mehrere onclick Methoden geben soll und die aufgerufen werden sollen je nachdem welcher grüner Button geklickt wurde. Ich hoffe jetzt habe ich das Problem genau erklärt. Tut mir leid wenn es vorher zu undurchsichtig war.

 

Eine kleine Endfrage habe ich noch. Wenn ich zum Beispiel den Schwert Button klicke möchte ich, dass das grüne Menü aufgeht und rechts die beiden panels mit den buttons sich schliessen.Gibt es da einen besseren weg als immer zu schreiben panel1.setActive(false)  panel2.setActive(false). Gibt es einen Befehl womit man alle schliessen kann und ich mache nur das eine dann wieder auf?

 

Sorry für den ganzen Text. Wenn es dir zu viel wird verstehe ich das natürlich.

Danke nochmal für deine Hilfe und ein schönes Wochenende

 

 

DesignIdee.jpg

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor einer Stunde schrieb Strooja0108:

Ich verstehe aber nicht was die Scriptable Objects damit zutun haben, dass die Werte nicht auf ihren Default wert zurückgesetzt werden. Das passiert doch bei all meinen anderen public variablen auch.

Die anderen Variablen sind Teil von Komponenten, auf GameObjects, in einer Szene. Szenen werden beim Spielstart bzw. während des Spielverlaufs geladen und dann irgendwann, spätestens beim Shutdown des Programms, wieder zerstört. Der Zustand einer Szene, vom Vorhandensein eines GameObjects bis hin zu jeder kleinen Eigenschaft jeder Komponente, wird nicht gespeichert, sondern neu aus der Szenendatei geladen, wenn du den Play Mode beendest. Ist ja auch logisch: Du willst nicht deine Spielfigur nach jedem Test wieder manuell auf Anfang zurückschieben.

ScriptableObjects (so wie wir sie hier benutzen) sind allerdings sind nicht Teil deiner Szene, sie existieren in den Assets, neben deinen Texturen, Sounds und 3D-Modellen. Wenn du im Play Mode z.B. ein Material änderst, dann bleibt das auch nach dem Beenden des Play Modes so. Und das gilt halt auch für ScriptableObjects.

vor einer Stunde schrieb Strooja0108:

Es tut mir leid aber ich komme mit weiteren Fragen zu dir wo ich hoffe das du mich in die richtige Richtung lenken kannst.

Wenn die Frage kein direkter Follow-Up zum eigentlichen Thema ist, mach gerne ein neues Thema dafür auf. Gerne auch mehrere auf einmal wenn du mehrere (unzusammenhängende) Fragen hast ;)

Link zu diesem Kommentar
Auf anderen Seiten teilen

Würdest du denn dann bei den Scriptable Objects für die Items bleiben und sowas wie amount, unlocked,equipt einfach wieder in array listen auslagern? Also die variablen die man während des spiels verändern wird. Ich muss sagen ich finde die scriptable objects nämlich sonst sehr schön übersichtlich.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Gibt da verschiedene brauchbare Varianten, aber lauter Listen, die eine versteckte semantische Verbindung haben, dass Werte mit demselben Index zusammengehören, ist keine davon. Du möchtest in jedem Fall Objekte haben und dann eine Liste dieser Objekte, ob das jetzt ScriptableObjects sind oder nicht.

Du kannst z.B. eine neue Klasse SwordInstance anlegen, die irgendwie so aussehen könnte:

public class SwordInstance
{
  public Sword swordClass { private set; get; }
  public int someVariableData;
  
  public SwordInstance(Sword swordClass)
  {
    this.swordClass = swordClass;
  }
}

Wenn du dann deinen Laden hast und du kaufst davon ein Schwert, dann erstellst du eine neue Instanz dieses Schwerts. Das ScriptableObject enthält nur die immer gleichbleibenden Daten, während die SchwertInstanz neben der Referenz auf die Schwert-Klasse die ganzen variablen Daten enthält.

public void BuySelectedSword()
{
  var swordClass = swordsForSale[displayIndex];
  
  playerInventory.AddSword(new SwordInstance(swordClass));
}

Da gibt's dann wieder neue offene Fragen, wie man das baut, aber... so als Beispiel dafür, wie du ScriptableObjects mit dynamischen Laufzeitdaten kombinieren kannst.

Link zu diesem Kommentar
Auf anderen Seiten teilen

ah  das klingt interessant .Nochmal fürs verständnis.

public class SwordInstance	//erstellt die klasse
{
  public Sword swordClass { private set; get; }  // variable vom typ sword wo ich mein Scritable Object hinzufüge.Wofür brauche ich das in klammern?
  public int someVariableData;		//Die extra variablen die ich haben will, die sich danna uch verändern dürfen.
  
  public SwordInstance(Sword swordClass)	// wofür ich die letzten beiden lines brauche verstehe ich nicht
  {
    this.swordClass = swordClass;
  }
}

im zweiten Teil deines Beispiels erzeuge ich dann ein neues Schwert. Das heisst ich erzeuge nichtmehr nur ein Scriptable Object pro Schwert sondern zusaätzliche eine klasse in der ich dann das Scriptable Object + die extra variablen speicher.Ist das korrekt?  Ich versteh nicht warum du

playerInventory.AddSword(new SwordInstance(swordClass));

 

verwendest? Ich brauch ja nicht immer ein neues Object ich will ja nur eine Variable hochzählen wenn ein weiteresSchwert der selben Id gekauft wird.

Ich hab das Gefühl das ich mir das mehr als eine Art Datenbank vorstelle und du mehr als eine Ansammlung Objekte .Vielleicht liegt darin mein Fehler bei dem ganzen..Könntest du mir sagen ob ich deinen Code und das ganze richtig verstanden habe?

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 3 Stunden schrieb Strooja0108:

Wofür brauche ich das in klammern?

Damit können Instanzen anderer Klassen den Wert dieser Variablen (ich bleibe jetzt mal bei dem Namen...) zwar ansehen, aber nicht ändern.

vor 3 Stunden schrieb Strooja0108:

wofür ich die letzten beiden lines brauche verstehe ich nicht

Das ist ein Konstruktor. Der wird beim Erstellen eines Objekts dieser Klasse ausgeführt. Da dieser Konstruktor einen Parameter hat, kann man kein Objekt erstellen, ohne da einen Wert zu übergeben, siehe

new SwordInstance(swordClass)

 

vor 3 Stunden schrieb Strooja0108:

Ich brauch ja nicht immer ein neues Object ich will ja nur eine Variable hochzählen wenn ein weiteresSchwert der selben Id gekauft wird.

Da hast du einen guten Punkt. Dann lass mich dir eine andere Variante vorschlagen: Ein Dictionary. Weiß nicht, ob du das kennst, aber ein Dictionary ist ähnlich einer Liste, aber anstatt lauter Dinge in einer Reihenfolge 0, 1, 2, 3, ..., n gelistet zu haben, werden hier Werte ihren Schlüsseln zugeteilt. Wie ein Wörterbuch eben: Du kannst nach einem Wort (Schlüssel) suchen und dann die Übersetzung (dazugehöriger Wert) anschauen. So kannst du auch dein Schwert als Schlüssel verwenden und der dazugehörige Wert ist eine Zahl.

private Dictionary<Sword, int> swordPurchases = new Dictionary<Sword, int>();
swordPurchases[theSwordThatWePicked] += 1;

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

jepp kenn ich. Okay zum Verständnis, dass würde es einfach übersichtlicher machen ,oder gibt es noch einen anderen Vorteil. Und es ist richtig das ich den Namen des Schwertes nicht mehr ändern darf oder ich muss ihn auch im Dictionary ändern. Bei einem normalen array kann ich alles ändern nur nicht die reihenfolge in dem array nicht. Hab ich das so richtig verstanden? Ok, dass heisst deine Idee für mein Problem wäre zum einen ein Scriptable Object für die Sachen die ich nicht verändern möchte. Plus  2 Dictionarys einmal zum gucken ob das Schwert schon freigeschaltet ist und einmal zum gucken wie viele man davon besitzt.  Ist das so richtig? Ich finde das klingt nach einer guten Lösung.

 

Wieder einmal danke schön für deine Hilfe. Meinst du du könntest auch einmal in meinen anderen Thread reinschauen, wegen des Menüs? Wenn dir die Antwort da zu lange dauert würde mir auch nur eine Antwort zu der Zusatzfrage sehr weiterhelfen.

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 27 Minuten schrieb Strooja0108:

Und es ist richtig das ich den Namen des Schwertes nicht mehr ändern darf oder ich muss ihn auch im Dictionary ändern.

Du benutzt nicht den Namen des Schwertes als Schlüssel, sondern das Schwert selbst. Du kannst deshalb sämtliche Eigenschaften des Objekts ändern, denn dadurch geht dessen Identität nicht verloren.

vor 27 Minuten schrieb Strooja0108:

Bei einem normalen array kann ich alles ändern nur nicht die reihenfolge in dem array nicht. Hab ich das so richtig verstanden?

Warum solltest du die Reihenfolge der Elemente in einem Array nicht ändern können?

vor 27 Minuten schrieb Strooja0108:

Plus  2 Dictionarys einmal zum gucken ob das Schwert schon freigeschaltet ist und einmal zum gucken wie viele man davon besitzt.

Brauchst nur eins. Dann du kannst einfach nachschauen, ob ein bestimmtes Schwert überhaupt als Schlüssel drinsteht. Wenn nicht, ist das Schwert offenbar nicht freigeschaltet.

Edit: Ach ja, wegen des Menüs: Da hatte ich reingeschaut, aber da wäre etwas mehr Aufwand für mich, mich da reinzufuchsen, und da habe ich bisher keine Zeit zu gehabt. Generell hilft es, ein Problem ein kleinstmögliche Teile runterzubrechen, und sich dann bei den kleinen Problemen helfen zu lassen, als bei einem großen ;)

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ah okay mit dem Schwert selbst meinst du also das Scriptable Objekt richtig? Das mit dem Array war nur nen Beispiel da ich ja nur ne liste aus einsen und nullen verwendet haben um zu identifizieren ob ein schwert freigeschaltet ist oder nicht. Darf ich natürlich nicht die reihenfolge der schwerter ändern da sonst ein andere schwert plötzlich freigeschaltet ist. DA ich es ja bis jetzt anhand des index miteinander verbunden habe.

 

mh ja stimmt ich könnte nur ein dictionary verwenden .Aber ich finde es angenehmer wenn ich nicht überprüfe ob das schwert drin  steht sondern einfach alle schwerter schon drin sind und ich gucke ob die passende variable auf eins ist. So kann ich es auch einfach testen meiner Meinung nach.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Archiviert

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

×
×
  • Neu erstellen...