Jump to content
Unity Insider Forum

Sascha

Administrators
  • Posts

    13,414
  • Joined

  • Last visited

  • Days Won

    756

Sascha last won the day on October 27

Sascha had the most liked content!

About Sascha

  • Birthday 08/13/1990

Contact Methods

  • Website URL
    http://13pixels.de

Profile Information

  • Gender
    Male
  • Location
    Hamburg
  • Interests
    Programmierung

Recent Profile Visitors

96,806 profile views

Sascha's Achievements

Advanced Member

Advanced Member (3/3)

2.7k

Reputation

  1. Hey, willkommen! Das ist doch mal eine motivierende Backstory. Viel Erfolg!
  2. Moin! SpriteRenderern ist ihre Reihenfolge in der Hierarchie egal. Deren Zeichenreihenfolge ist undefiniert, solange sie auf demselben Layer mit derselben sortingOrder sind. Du kannst den SpriteRenderer ansprechen und einen sortingOrder setzen, der dem Index des Elements entspricht: temp.GetComponent<SpriteRenderer>().sortingOrder = snakeBody.Count;
  3. Moin! Dein Objekt besteht ja aus irgendwelchen Daten. Wenn du von einem Mesh (also einem 3D-Modell) redest, dann hast du einen Haufen Punkte (Vertices), die wiederum zu einem Haufen Dreiecke (Triangles) verbunden werden, um eine 3D-Form darzustellen. Um den Mittelpunkt eines Meshs zu finden, musst du dir diese Punkte anschauen und dann von den Mittelpunkt von ihnen finden. Dazu kannst du z.B. eine AABB (Axis-Aligned Bounding Box) berechnen, oder ggf. auch einfach die nehmen, die Unity sowieso schon hat. Der Mittelpunkt dieser Box ist dann der Mittelpunkt deines Objekts. Ist das das, was du suchst, oder meinst du eher etwas anderes?
  4. Was ich ja sogesehen damit getan habe... Die Liste könnte bis ins unendliche gehen. Deswegen weiß ich nicht ob das so sauber ist. malzbie meinte damit die tatsächlichen Layer. Wenn du die sortingOrder-Eigenschaft genommen hast, ist das schon völlig in Ordnung so. In dem Moment, wo du mit einem Laufindex auf deine Liste zugreifst, solltest du keine LinkedList mehr nehmen. Kann gut sein, dass einige LinkedList-Implementationen deshalb gar keinen Index-Zugriff erlauben. Nimm einfach ne normale Liste. Wenn du nicht zehntausende Elemente hast, bringt dir ne LinkedList keinen Performance-Vorteil. Ich nenne die inzwischen "MonoBehaviour-Events", und ich glaube das machen viele so. Mach selber nen Raycast (oder vermutlich eher Physics2D.OverlapPointNonAlloc) und filtere dir dann das Objekt mit der höchsten sortingOrder raus.
  5. Ich glaube zunehmend, dass ich meinen Singleton-Artikel mal überarbeiten muss. Ich bleibe dabei, dass es wichtig ist, das im Gang of Four-Buch vorgestellte Pattern klar von dem zu trennen, was die Leute so in Unity machen. Einfach schon, weil es im Unity-Kontext Serialisierung und MonoBehaviour nur für Instanzen gibt. Was im Artikel noch fehlt ist, dass ich mir angewöhnt habe, dass Code möglicht wenig Restriktionen im Editor erzeugen soll. Deshalb finde ich das Standardpattern für Unity- Singletons auch so doof - der Code tut nur was er soll, wenn man auch ja nicht vergisst, das Ding in die Szene zu schmeißen. Wenn man wie @MaZy ein anderes Pattern benutzt, mit dem der Code tut, egal was mit im Editor anstellt... dann sieht das schon gleich ganz anders aus. Ein Beispiel für so ein Pattern wäre dieses: public static class MusicPlayer { private static AudioSource audioSource; [RuntimeInitializeOnLoadMethod] private static void Initialize() { var go = new GameObject("Music Player"); go.AddComponent<AudioSource>(); go.hideFlags = HideFlags.HideAndDontSave; Object.DontDestroyOnLoad(go); } public static void PlayMusic(AudioClip clip) { audioSource.Stop(); audioSource.clip = clip; audioSource.Play(); } } Das ist halt im Prinzip auch ein Singleton, und es ist auch sinnvoll, weil eine statische Klasse halt keine AudioSource haben kann - dazu braucht man eine GameObject-Instanz. Allerdings erzeugt das Ding sich sein GameObject automatisch bei Spielstart, macht es unsterblich und versteckt es. Im Editor kriegst du nichts davon mit. Und vor allem muss keiner daran denken, das Ding auch in eine Szene einzufügen, damit der Code tut was er soll. Es bleibt nur noch Serialisierung als Problem, das ich für mich über SettingsProvider gelöst habe - ich kann meinen statischen (oder beliebigen anderen) Klassen damit in den Project Settings Referenzen und andere Werte zuweisen. Hab das in Soda eingebaut *hust* Lange Rede, kurzer Sinn... ich muss mal den Artikel updaten.
  6. Ne. Es gibt gleich eine Handvoll Dinge, die "Layer" heißen. Das da ist der GameObject-Layer - der wird für selektives Ausblenden von Objekten - Sichtbarkeit, Beleuchtung oder in der Physik - benutzt. Du kannst z.B. deine Raycasts durch bestimmte Layer hindurchschließen lassen. Oder die Kollision zwischen zwei Layern komplett abschalten. Hier brauchen wir den "Sorting Layer", das ist eine Eigenschaft von Renderern. Im SpriteRenderer kannst du das direkt einstellen. Da gibt es zum einen die Layer selbst, von denen du ein paar anlegen kannst. Typisch wären so Layer wie "Background, Gameplay, Foreground" oder so. Reicht dann auch. Was du dir hier anschauen musst, ist aber die zweite Eigenschaft: "Sorting Layer". Das ist schlicht eine Zahl, die innerhalb eines Layers benutzt wird, um eine Ordnung festzulegen. Ob hohe Zahl = vorne oder = hinten ist, kann ich mir immer nicht merken Da das nur eine Zahl ist, musst du hier nichts anlegen. Du kannst also sowas machen: for (var i = 0; i < spriteRenderers.Length; i++) { spriteRenderers[i].sortingOrder = i; } (for-Schleife natürlich nicht bei einer LinkedList, da bräuchtest du eine foreach-Schleife die nebenbei hochzählt... oder du nimmst halt ne List)
  7. Hey, da hab ich doch mal einen Blogeintrag zu geschrieben http://blog.13pixels.de/2019/unity-and-the-mysterious-singleton/ Aber ich erzähl trotzdem mal. Das klingt furchtbar. Ich hoffe für deinen Kollegen, dass du seine Aussage nur nicht gut verstanden hast Ein Singleton (bzw. das, was unter Unity-Entwicklern als solches bezeichnet wird) ist dazu da, dass eine Referenz auf ein einzigartig gemeintes Objekt global bekannt gemacht wird. Einzigartig könnte z.B. die Spielerfigur, die Ziellinie oder die Lebensanzeige des Spielers im UI sein. Mit diesem Muster kannst du Objekten der jeweiligen Klasse sagen, dass sie sich im Code als "DAS" Objekt dieser Sorte anmelden sollen. Jeglicher anderer Code kann dann auf dieses Objekt direkt zugreifen, ohne es erst heraussuchen zu müssen. Hast du im Vergleich dazu eine beliebige Menge von Objekten (z.B. Zombies), dann kannst du schlecht einfach so auf eines dazu zugreifen, weil der Computer natürlich nicht raten will, welchen der im Zweifelsfall vielen Zombies du gerade meinen könntest. Nun stellt sich aber, wenn man lang genug über das Thema nachdenkt, eben jenes heraus: und genau das ist auch die Hauptkritik am originalen (nicht-Unity-bezogenen) Singleton-Pattern. Wenn man verstanden hat, was eine statische Klasse ist, dann ist es nicht schwer zu erkennen, dass eine Objekt, von dem immer nur eines existieren soll, im Prinzip dasselbe macht wie statische Klasse (was ein Ding ist, das Daten speichern oder Methoden haben kann, und es kann immer nur eine davon pro Sorte im Programm geben). Im Unity-Kontext gibt es ein paar mehr Argumente für dieses Pattern. Zum einen können nur Component-Instanzen MonoBehaviour-Events (wie z.B. Update) empfangen und zum anderen kann man nur auf Objekten in der Szene, Prefabs oder ScriptableObjects Werte serialisieren (bzw. anders gesagt: im Editor eingeben). Wenn du z.B. eine Textur aus den Assets im Editor zuweisen willst, geht das nicht in eine statische Klasse hinein. Wenn man versucht, sich zu diesem Pattern zu informieren, dann hört man gefühlt sehr viele Stimmen die entweder aus ihrer begrenzten Erfahrung heraus voll dafür sind, oder andere die immer mal wieder gehört haben dass das schlecht sein soll und das deswegen verteufeln. Meiner Meinung nach gibt es Situationen, in denen die Anwendung sinnvoll ist, aber auch sehr oft Leute, die das Ding voll toll finden, es viel zu oft benutzen und sich dann wundern warum ihr Projekt so schlecht voran geht. Besonders übel sind die "Manager"-Klassen. Das sind dann oft so Klassen, die gar nicht großartig Teil der Szene sind, sondern einfach nur da sind, um irgendeine globale Aufgabe zu erfüllen. Zum Beispiel der "LevelManager". Der hat dann Methoden zum Laden verschiedener Level. Und da wird's dann halt echt lächerlich, weil eine statische Klasse genau dasselbe machen kann, ohne dass man deine Szenen-Hierarchie zumüllt. Wenn dich das weiter interessiert, empfehle ich dir dafür das Video meinem verlinkten Artikel. Warum ich erstmal das Gesicht verzogen hab, als ich das Zitat von deinem Kollegen gelesen habe: Wir hatten hier früher mal so Anfängertutorials, von denen eines genau dieses Pattern vorgeschlagen hat, damit ein Knopf eine Tür öffnen kann. Wir hatten dann alle Nase lang die Frage, wie man das denn machen soll, wenn man zwei Türen und zwei Knöpfe hat. An dieser Stelle war das Pattern nämlich total fehl am Platz. Darum: Static und das Singleton-Pattern sind nicht dazu da, dir das Leben einfacher zu machen, wenn es generell darum geht, auf andere Objekte zuzugreifen. Sie erlauben es dir, "das eine" Objekt einer Sorte (den einen Spieler, die eine Health Bar) global zugreifbar zu machen, sodass man da nicht unnötig Referenzen definieren und Objekte suchen muss. Und wenn du ein Objekt hast, das sowieso Teil deiner Szene sein soll, weil es dort hineingehört, und du dir sicher bist, dass du davon immer nur eines zur Zeit haben wirst - dann kannst du dieses Pattern guten Gewissens verwenden. Der einzige Fehler, den du nicht begehen solltest, ist, das Ding ständig zu benutzen ohne jedes Mal kurz darüber nachzudenken, ob das an dieser Stelle nicht totaler Quark ist.
  8. Es ist auch nicht schlecht, wenn du eine Datenstruktur hast, in der alle deine SpriteRenderer in einer Liste sind, die ihre Reihenfolge darstellt. Du kannst dann bei jeder Änderung der Liste einmal komplett durch sie durchgehen und allen Objekten darin einen auf-/absteigenden Order In Layer geben. Wenn du dann deine Klicks checkst, kannst du von vorne nach hinten durch deine Liste durchgehen und das erste von den getroffenen Objekten, das du findest, wird aufgehoben. Das klingt auf den ersten Blick vielleicht fragwürdig in Sachen Performance, ist aber voll okay.
  9. Moin, überdenke nochmal das puplic
  10. Die ID muss als Teil der Komponente serialisiert werden. "Serialisiert" heißt hier, dass ein Wert dafür in der Szene gespeichert wird, sodass er dann im laufenden Spiel beim Laden der Szene "deserialisiert", also geladen werden kann. Kennst du evtl. mit public, aber sauberer ist's so: [SerializeField] private int coinId; Dann kannst du direkt per Hand eindeutige IDs an deine Coins im Editor vergeben. Automatischer Kram würde darauf aufbauen, das serialisierte Feld bleibt dabei dann. Noch als Hinweis: Dieser Code müsste auf die Coins - wenn da also if (other.CompareTag("Coin")) steht, dann würde nur Kollision zwischen Coins und... anderen Coins das auslösen. Ich glaube nicht, dass du das willst.
  11. Korrekt! Und der niedrigste Wert ist (hier und sowieso meistens) 0.
  12. Naja, was du da stehen hast ist wenn linke maustaste: rechne +1 wenn höchstes: gehe auf "aus" sonst, wenn rechte maustaste: rechne -1 wenn höchstes: gehe auf "schnell" Siehst du das Problem?
  13. Wie sah denn dein Versuch aus?
  14. Moin, naja, du hast vom höchsten zum niedrigsten in den Teil mit der linken Maustaste eingebaut, jetzt musst du halt auf die gleiche Art vom niedrigsten zum höchsten bei der rechten einbauen.
  15. Moin! Wenn du eine Szene lädst, dann werden alle GameObjects darin in dem Zustand geladen, den du im Editor eingestellt hast. Wenn da dieses oder jenes Objekt nicht dabei sein soll, dann hast du nur zwei Möglichkeiten: Das Objekt war gar nicht in der Szene, sondern wird nach dem Laden durch Code erstellt. Und dieser Code macht das dann eben nicht, wenn der Spielstand nein sagt. Das ist etwas doof, weil du da standardmäßig erstmal keine Münzen im Editor erstellst - das macht ja der Code. Aber im Editor zu sehen, wo man seine Dinge hinpackt, ist schon eine der schönen Sachen am Arbeiten mit Unity. Da kann man zwar drumherum arbeiten, aber das ist ein Stückchen mehr Arbeit als Variante 2. Das Objekt schaut in Start(), ob es laut Spielstand bereits eingesammelt ist, und zerstört sich ggf. selbst direkt wieder. In beiden Fällen brauchst du einen Weg, deine Münzen eindeutig zu identifizieren. Die ID einer Münze kann dann in den Spielstand geschrieben werden, um anzugeben, dass sie eingesammelt ist. Leider gibt Unity dir nicht für jedes Objekt eine eindeutige, persistente (!) ID, die bei jedem Spielstart gleich wäre. Die brauchst du aber, damit die Münze schauen kann, ob sie irgendwo im Spielstand drin steht. Man kann da ein bisschen kreativ werden: Wenn dein Spiel auf einem Grid ist, kannst du z.B. die Position der Münze auf dem Grid nehmen. Wenn du für so etwas keine Möglichkeit siehst, wirst du nicht drumherum kommen, deinem Münz-Prefab eine Komponente zu geben, die eine ID speichert. Diese Komponente kann dann auch gleich den Check in Start implementieren. Du musst dann sichergehen, dass jede Münze auch wirklich eine eindeutige ID hat, also keine ID doppelt belegt ist. Zumindest innerhalb einer Szene. Dann benutzt du diese eindeutige ID und speicherst einen Wert dazu über PlayerPrefs. Zum Beispiel so: PlayerPrefs.SetInt($"Coin-{sceneName}-{coinId}", 1); sceneName wäre der Name der aktuellen Szene - so musst du nicht über mehrere Szenen hinweg deine IDs eindeutig halten. coinId ist dann die zugewiesene ID. Die Coin-Komponente macht dann etwa sowas: private void Start() { if (PlayerPrefs.GetInt($"Coin-{sceneName}-{coinId}", 0) == 1) { Destroy(gameObject); } } Das Zuweisen der ID kannst du mit der Hand machen, oder du baust dir da ein bisschen Editor-Code. Dieser könnte einmal alle Coins in der Szene anschauen und die kleinstmögliche ID, die noch nirgendwo verwendet wird, an den jeweils nächsten Coin vergeben, dessen ID noch 0 ist. Das kann man auch so bauen, dass das beim Platzieren eines neuen Coins automatisch passiert. Ist dann aber zunehmend kein Anfängerkram mehr. Als Randnotiz: Man muss bei sowas immer ein bisschen aufpassen. Wenn du z.B. irgendwann eine Szene umbenennst, sind alle Spielstände vor dieser Änderung erstmal kaputt.
×
×
  • Create New...