Jump to content
Unity Insider Forum

Lightstorm

Members
  • Content Count

    154
  • Joined

  • Last visited

  • Days Won

    3

Everything posted by Lightstorm

  1. Ich möchte für ein Spiel Dialoge entwickeln. Der Spieler soll auf eine bestimmte Nachricht mit mehreren Antwortmöglichkeiten reagieren können. Abhängig von der ausgewählten Antwort des Spielers, kommt dann eine darauf eingestellte neue Nachricht. Diese Dialoge werden zahlreich und jeder einzelne Dialog kann mehrere Verläufe haben. Wie ich das programmiere weiß ich bereits. Ich frage mich nur wie ich das am besten übersichtlich organisieren kann. Am liebsten wäre mir ein Tool, womit ich visuelle Elemente erstellen kann: Nachrichten Boxen, Antwort Boxen und diese Boxen kann ich beliebig miteinander verbinden, um den Pfad des Dialogs zu bestimmen. Nachdem der Dialog geschrieben und verzweigt ist, will ich dann das ganze z.B. als JSON oder in einem anderen Format exportieren, um es dann im Spiel zu importieren. Jede Editierung und Erstellung der Dialoge würde über das visuelle Tool ablaufen. Gibt es so etwas bereits oder etwas ähnliches?
  2. Das ist der einzige Grund wieso ich manchmal überlege die Vorgehensweise ohne geschweifte Klammern zu unterlassen. Es ist dann nervig wenn man zum testen die Klammern wieder hinzufügen muss. Es ist schnell gemacht, aber es nervt wirklich
  3. Ich mag es nicht wenn verhältnismäßig viele Leerräume entstehen und ich viel scrollen muss um den Code zu lesen. Etwa in Situationen wo man dann mehrere If Abfragen hintereinander ausführt um jedes mal dabei nur eine Zeile Code auszuführen.
  4. Wenn in den Klammern nur eine Zeile Code nötig ist mache ich es meistens so: if (X == Y) print("wahr") else print("falsch") Wichtig ist zu wissen das ohne Klammern nur eine Zeile von der if Bedingung abhängt. Wenn man den Code also später erweitert und noch eine Zeile einfügt muss man die Klammern wieder hinzufügen. Folgendes geht also nicht: if (X == Y) print("wahr") print("wirklich wahr") else print("falsch")
  5. Hm ok verstehe. Ich belasse es vorerst bei der Lösung dass das rigidbody auf der Plattform auf extrapolate eingestellt wird und außerhalb auf interpolate. private void OnTriggerEnter2D(Collider2D collision) { collision.transform.parent = gameObject.transform; if (collision.attachedRigidbody) collision.attachedRigidbody.interpolation = RigidbodyInterpolation2D.Extrapolate; } private void OnTriggerExit2D(Collider2D collision) { collision.transform.parent = null; if (collision.attachedRigidbody) collision.attachedRigidbody.interpolation = RigidbodyInterpolation2D.Interpolate; }
  6. @malzbie Wenn ich die Kameraposition mit der Lerp Methode über Update aktualisiere und das Rigidbody des Spielcharakter auf Interpolate setze funktioniert es so wie es soll. Kein ruckeln auf der Plattform. Aber es taucht ein anderes Problem auf. Wenn der Spielcharakter sich auf der beweglichen Plattform bewegt stottert es dabei und bewegt sich nur langsam vorwärts. Wenn ich Interpolate auf Extrapolate einstelle ist auch dieses Problem gelöst. Ist das ok so? Über Extrapolate heißt es in der Dokumentation dass dadurch schnelle rigidbody Objekte bei Collisionen in die Collider rein geraten könnten.
  7. Das Thema bewegliche Plattformen geht in die nächste Runde glaube ich Ich habe eine Kamera die den Spielcharakter verfolgt. Im Prinzip so: transform.position = Vector3.SmoothDamp(transform.position, targetPos, ref velocity, .1f); targetPos ist die Position des Spielcharakter. Das ganze wird in FixedUpdate() ausgeführt. Der Spielcharakter wird über rigidbody2D bewegt. Wenn ich die Position der Kamera in Update() ändere entsteht ein hässliches ruckeln wenn die Kamera den Spieler verfolgt. Nun habe ich bemerkt dass eine animierte Plattform (Unity Animation mit Animator Komponente) das selbe ruckeln erzeugt nachdem der Spielcharakter auf die Plattform hüpft und zum Kindsobjekt der Plattform wird. Siehe auch: Das liese sich lösen wenn die Kameraposition in Update() statt FixedUpdate() aktualisiert wird. Dann verschwindet das ruckeln beim verfolgen auf der Plattform. Dann aber habe ich wie oben erwähnt das ruckeln wenn sich der Spielcharakter normal außerhalb der Plattform bewegt. Soweit ich verstehe hat das damit zu tun das FixedUpdate() und Uptate() unterschiedlich oft aufgerufen werden. Die Frage ist wie kann ich das nun angleichen. Wie kann ich die animierte Plattform dazu bringen dass es sich mit der Frequenz von FixedUpdate() aktualisiert?
  8. @Gadakar86 Wie @malzbie schon richtig schreibt, der Code funktioniert. Wenn du es richtig bei dir verwendest sollte es gehen. Du musst einen Collider für deine bewegliche Plattform erstellen und es als Trigger einstellen. Alles was im Spiel in diesen Collider rein geht wird durch die Funktion OnTriggerEnter2D zum kindsobjekt der Plattform.
  9. Du willst den Ball nur bewegen wenn es keine Bodenhaftung hat bzw. IsGround false ist? Das machst du damit nämlich mit !IsGrounded() Du prüfst mit IsBlocked() ob rechts vom Ball ein Hindernis ist und schaltest dann die Richtung um. Mit !IsBlocked schaltest du um wenn kein Hindernis da ist? Wenn der Ball aber nicht auf Anhieb sich vom Hindernis entfernen kann trifft der Raycast wieder auf das Hindernis und ändert wieder die Richtung. Das passiert ganz schnell und der Ball kommt gar nicht weg. Also ich habe dein Script bei mir ausprobiert und mit dem Code bewegt sich der Ball gar nicht. Erst wenn du IsGrounded nicht mehr negierst, also IsGrounded statt !IsGrounded fängt der Ball an sich zu bewegen, bleibt aber beim nächsten Hindernis kleben und ändert nicht die Richtung. Versuch doch das mit Trigger Collidern zu lösen. Wie es Sascha schon mit OnCollisionEnter2D zeigte oder mit OnTriggerEnter2D. Damit würde der Ball sich bei einem Hindernis nicht ständig rechts und links bewegen. OnCollisionEnter2D wird nur einmal ausgelöst wenn du auf ein Hindernis stößt. Wenn du den Ball stoppen willst musst du die horizontalMovement Variable auf 0 setzen. Das könntest du mit einem Trigger am Loch machen.
  10. Modularisierung. Man unterteilt ein Programm in sinnvolle Einzelteile. Ein Vorteil ist dass ein Programm so übersichtlicher wird und ein anderer Vorteil ist dass du Module bzw. Scripte miteinander unterschiedlich kombinieren kannst. Du vermeidest es gleichen oder ähnlichen Code immer wieder neu schreiben zu müssen. Ein konkretes Beispiel ist folgendes: Ich habe im Prinzip zwei Scripte um einen Charakter zu steuern. CharakterController.cs und PlayerCharacterMovement.cs. Ich könnte beides vereinen und einen einzigen Script schreiben. Kann man machen. Aber die Trennung macht den Code flexibler. Ich wollte eine automatische KI Steuerung für Gegner Charaktere und ich dachte mir, eigentlich brauchen die Gegner Charakter die selben Eigenschaften wie mein Player Charakter. Sie müssen sich bewegen, springen, Wände und Böden erfassen, Animationen abspielen. Warum soll ich den Code von CharakterController.cs neu schreiben oder kopieren wenn ich doch nur den PlayerCharacterMovement.cs Script einfach durch ein AICharakterMovement.cs ersetzen muss? Die Modularisierung macht es einfacher. Um Gegner Charaktere automatisch zu steuern musste ich nur sehr wenig Code schreiben, denn ich konnte CharakterController.cs unverändert nutzen, das ging nur weil es diese Aufteilung gibt Du könntest den Code von CharakterController.cs auch einfach kopieren aber mit so einer Vorgehensweise hast du irgendwann sehr viele Scripte mit gleichem Code. Das ist unschön und wenn du später etwas daran ändern musst, musst du es in allen Scripten ändern wo du es genutzt hast. Die Vorteile einer sauberen Vorgehensweise merkt man übrigens erst so richtig im Laufe eines Projektes. Am Anfang ist die Verlockung groß einfach schnell eine Lösung zu schaffen, weil es ja kein großer Aufwand ist Teile eines Scriptes einfach zu kopieren oder neu zu schreiben. Aber das wiederholt sich dann hunderte mal im Laufe der Entwicklung und irgendwann verwandeln sich die schnellen unschönen Lösungen zu einem unübersichtlichen und fehlerhaften Chaos. Das kann so schlimm werden dass man so nicht mehr weiter entwickeln kann ohne vieles umzubauen. Daher lohnt es sich bereits am Anfang eine disziplinierte Vorgehensweise anzugewöhnen. Wenn du weitere Fragen hast oder noch etwas unklar ist frag ruhig.
  11. Nur wenn die Reibung eines Physics Material hoch eingestellt ist. Ab einer bestimmten Geschwindigkeit der Plattform rutscht das rigidbody trotzdem. Was physikalisch korrekt ist. Bei hohen Werten für die Physic Reibung hat man unter Umständen das Problem dass man an der Platform seitlich leicht hängen bleibt weil die Reibung so hoch ist.
  12. Hallo @Schokokeks15 Ich bin auch noch am lernen und bin kein erfahrener Programmierer. Ich hatte schon früher einige Anläufe mit der der Programmierung. Der Unterschied dieses mal ist dass ich versuche systematischer vorzugehen. Früher oder später musst du dir überlegen wie deine Code Architektur in Unity aussehen soll. Schau dir diesbezüglich auch mal das an: https://gitlab.com/FlaShG/Unity-Architecture Es ist vielleicht am Anfang mühseliger sich gedanklich damit zu beschäftigen, aber es lohnt sich wirklich.
  13. @Sascha Wieder mal eine Frage Eines verstehe ich noch nicht. Wenn man ein Feld wie "[SerializeField] private int test" anlegt kann man es beispielsweise in der Reset Methode mit "test = 10" initialisieren. Aber wenn es ein Feld wie "[SerializeField] private IntReference test" ist und man es in der Reset Methode mit "test.Value = 10" festlegen will gibt es einen Fehler: NullReferenceException: Object reference not set to an instance of an object Um das zu beheben muss man das Objekt direkt erstellen. Also "[SerializeField] private IntReference test = new IntReference()". Wieso ist das so? Wenn man auf die Referenz Variable in irgendeiner anderen Methode im Script zugreift klappt das ohne zuvor "new IntReference()" aufzurufen. Den NullReferenceException gibt es meistens wenn man auf das Feld in einer frühen Phase zugreifen will. Also in der Reset Methode im Editor oder manchmal auch in der Start Methode.
  14. Was vielleicht auch hilfreich sein kann ist dir zu überlegen ob du für alle solche Aufgabenstellungen eigene Scripte erstellen willst. Vielleicht willst du z.B. ein anderen Gegner machen der sich ähnlich aber etwas anders verhalten soll. Dann könntest du deinen ganzen Script kopieren und eine leicht abgeänderte Version erstellen. Und wenn ein anderer Gegner sich ganz deutlich anders verhalten soll musst du vielleicht ein ganz neuen Script erstellen. Um so was zu vermeiden könntest du überlegen ob du nicht möglichst universell verwendbare Scripte erstellen kannst. Objekte simple hin und her bewegen macht man recht häufig. Du könntest überlegen wie du ein Script erstellen kannst das Objekte bewegen kann, die Parameter und Variationen der Bewegungen kannst du dann über den Inspector einstellen. Das was du versuchst könnte ich mit drei universell einsetzbaren Komponenten umsetzen: Bei einer Kollision löst "Collider Trigger 2D" ein Unity Event aus, mit diesem Event kann ich direkt auf "Auto Movement 2D" zugreifen und Werte wie Translation Direction verändern. "Entity Movement 2D" kümmert sich um die Bewegung der Objekte und wird von "Auto Movement 2D" angesteuert. In einem anderen Fall wird Entity Movement über einen Player Script angesteuert, es wird häufig verwendet. Ich kann über den Parameter Movement Mode einstellen mit welcher Methode das GameObject bewegt werden soll. Mit transform.Translate, AdForce, AdForce Impuls oder über rigidbody2D.velocity. Sachen wie Speed Curve sind optional. Hast du einmal solche Komponenten erstellt kannst du sie in verschiedenen Kombinationen in GameObjects nutzen. Damit werden die Fälle wo man neuen Code schreiben muss deutlich reduziert. Ich versuche jedes mal wenn neuer Code nötig wird, wieder eine möglichst universell verwendbare Komponente zu erstellen. Diese Komponenten entwickeln sich weiter. Nach und nach findet man heraus welche weiteren einstellbaren Parameter sinnvoll sind, dann passe ich die Komponenten an, irgendwann ist ein Optimum erreicht wo keine Änderungen mehr nötig sind. Mit einer Reihe von spezialisierten und einstellbaren Komponenten kann man erstaunlich viele Variationen an Objekt Verhalten erstellen. Erst wenn für eine Aufgabenstellung sehr viele solcher Komponenten nötig werden, wird es im Editor unübersichtlich und vom Code her vermutlich ineffizient. Dann kann und sollte man neue Scripte und Komponenten erstellen. Für Charakter Bewegungen nutze ich aber andere Komponenten. Ich habe einen CharakterController Script. Über das lassen sich grundlegende Eigenschaften einstellen. Dann gibt es einen PlayerCharacterMovement Script. Damit wird CharakterController angesteuert, über den Player Input. Wenn ich Gegner Charaktere machen will die sich selbst bewegen nutze ich statt PlayerCharacterMovement ein AICharacterMovement Script. Auch dieser AI Script steuert CharakterController an, nur halt nicht über Player Input sondern mit Steuermustern die andere Komponenten senden. Ich habe beispielsweise eine Timer Komponente die in einstellbaren Zeitabständen das Steuermuster für AICharakterMovement verändert. Auch kann die Komponente "Collider Triger 2D" eingesetzt werden, Gegner Charaktere bzw. die Steuereingaben können also auch über Trigger verändert werden und nicht nur über Timer. Mit einer handvoll Komponenten kann man sehr komplexe Verhaltensmuster erzeugen. Der Nachteil ist dass die Entwicklung der einzelnen Komponenten am Anfang etwas dauert. Aber man spart später enorm viel Zeit und kann die Komponenten in anderen Projekten wieder verwenden.
  15. Wegen der Tür. Du könntest links und rechts von der Tür unsichtbare Trigger Collider setzen und beim triggern davon die gleiche Funktion auslösen wie bei OnCollisionEnter2D. Also mit OnTriggerEnter2D. Alternativ kannst du einen Trigger Collider um die Tür herum machen und die darin eingetretenen unerwünschten Objekte registrieren und beim öffnen und schließen der Tür diese aus dem Trigger Bereich raus schieben oder raus spawnen.
  16. Oh man ich habe gerade nach längerer Zeit erst etwas bemerkt. Man findet im Internet folgenden bzw. ähnlichen Code. Und ich wunderte mich wieso es bei mir nicht funktionierte. //HoldOnPlatform can be your name of the script public class HoldOnPlatform : MonoBehaviour { void OnTriggerEnter(Collider col) { col.transform.parent = gameObject.transform; } void OnTriggerExit(Collider col) { col.transform.parent = null; } } Damit funktioniert es perfekt. Kein rutschen auf der Plattform, der Charakter kann perfekt stehen, sich bewegen und problemlos jederzeit weg springen. Allerdings funktioniert es nur wenn die Plattform über ihre transform Eigenschaft bewegt wird. Bewegt man es über rigidibody2D dann funktioniert es nicht. Und das habe ich gerade zufällig so spät bemerkt Das ist so bitter... aber besser spät als nie.
  17. Habe nun eine andere einfache Möglichkeit gefunden: private void OnTriggerStay2D(Collider2D collision) { if (collision.gameObject.tag == platformTagName) { autoMove = collision.GetComponentInParent<AutoMovement2D>(); charakterController2D.relativeVelocity = autoMove.Direction; } } private void OnTriggerExit2D(Collider2D collision) { if (collision.gameObject.tag == platformTagName) { charakterController2D.relativeVelocity = Vector3.zero; } } relativeVelocity wird auf die Bewegung des Player Charakter dazu addiert. Der Charakter bewegt sich damit mit der selben Geschwindigkeit in die selbe Richtung wie die Plattform solange es keinen Input gibt. Wenn die Plattform verlassen wird, wird relativeVelocity einfach auf Null gesetzt, dadurch gelten wieder nur die Bewegungen durch den Spieler Input. Mit dieser Vorgehensweise ist es nicht notwendig das Ridigbody2D auf Kinematic zu setzen und das GameObject zum Child des Platform GameObject zu machen. Einen Haken hat das ganze: Wenn die Platform die Richtung ändert rutscht das Charakter Rigidbody2D ein ganz bisschen in die vorherige Bewegungsrichtung. Wie durch Fliehkraft aufgrund der Richtungsänderung der Platform. Wie wenn die Bahn bremst und man nach vorne gedrückt wird. Das sieht sogar schön aus und macht es ein bisschen realistischer. Wenn man das aber nicht haben möchte weiß ich gerade nicht wie man das verhindern kann.
  18. Dann habe ich ein anderes Problem: Wenn der gebundene Charakter auf der Plattform sich etwas horizontal bewegt, muss ich durch diesen Input den Charakter wieder loslösen. Damit bewegt sich der Charakter aber nur innerhalb des Trigger Colliders, es wird kein erneutes OnTriggerEnter2D zum erneuten binden ausgelöst sobald der Charakter wieder zum stehen kommt. Nach einer kurzen horizontalen Bewegung würde der Charakter also nicht mehr fest auf der Plattform stehen. Edit: Langsam bin ich etwas genervt So was triviales kostet jetzt so viel Zeit, mir vergeht die Lust.
  19. Danke für den Vorschlag. Ich probiere gerade mehrere Möglichkeiten und irgendwie gefällt mir keines wirklich gut. Damit der Player Charakter nicht einfach beim bloßen Kontakt an allen Seiten des Plattform hängen bleibt, muss man dafür sorgen dass das binden nur passiert wenn der Charakter auf der Oberseite der Plattform steht. Dafür musste ich der Plattform ein child GameObject hinzufügen und einen Trigger Collider. Das binden passiert nur wenn der Charakter diesen Trigger auf der Oberseite der Plattform berührt. Die Berührung der Oberseite erfasse ich mit OnTriggerStay2D im Player Charakter GameObject. private void OnTriggerStay2D(Collider2D collision) { if (collision.gameObject.tag == "MovedPlatform") { if (!playerFixed) { transform.parent = collision.gameObject.transform; rigidbody2D.isKinematic = true; playerFixed = true; } } } Ein anderes Problem ist dass der Spieler frei werden muss sobald man sich horizontal bewegt oder springt. Das mache ich so: if (Input.GetAxis("Horizontal") != 0.0f || Input.GetButtonDown("Jump")) { transform.parent = null; rigidbody2D.isKinematic = false; playerFixed = false; } Funktioniert. Aber habe irgendwie das Gefühl dass das besser geht. Ich habe es auch mit einem Fixed Joint 2D probiert. Funktioniert ja im Prinzip genau so. Ich weiß nicht warum, aber beim entbinden vom Joint hat der Player Charakter immer eine kleine komische Bewegung in die Plattform hinein vollführt und sich dann normal weiter bewegt. Deswegen habe ich es mit dem Joint gelassen. Dann habe ich es noch so probiert: private void FixedUpdate() { Collider2D[] colliders = Physics2D.OverlapCircleAll(transform.position, 0.02f, whatIsGround); for (int i = 0; i < colliders.Length; i++) { if (colliders[i].gameObject.tag == "MovedPlatform" && !move) { transform.parent.gameObject.transform.parent = colliders[i].gameObject.transform; rigidbody2D.isKinematic = true; } } } An meinem Player Charakter ist ein GroundCheck GameObject als child vorhanden, mit dem erfasst wird wann der Charakter auf dem Boden steht. Ich dachte mir ich kann mit dem selben Prinzip erfassen wann der Charakter auf einem Boden mit dem tag "MovedPlatform" steht um es dann zu binden. Funktionierte auch nicht perfekt. Bei Sprüngen aus größerer Höhe auf die Plattform kam der Player Charakter immer wieder mal einige Pixel innerhalb der Platform zum stehen statt wie üblich direkt auf dem Collisions Collider. Was ich gerne will ist eine Lösung die in meine modulare Architektur passt. Die andere Herausforderung ist wie man eine saubere Entbindung hinkriegt. Solange man mit einem Sprung den Trigger Bereich auf der Plattform nicht verlässt wird der Charakter sofort wieder gebunden bevor es noch den Trigger Bereich verlassen kann. Denn OnTriggerStay2D wird ja ständig ausgeführt.
  20. Der Player Charakter hat ein Rigidbody2D (Dynamic). Damit hüpfe ich auf eine Plattform die über rigidbody2D.MovePosition() bewegt wird. Dabei rutscht der Player Charakter auf dem Plattform weil diese sich bewegt. Wie kann ich das verhindern? Mit Physik Material und Friction Wert 1 entsteht das Problem dass der Player Charakter auch an den Seiten des Plattforms hängen bleibt statt runter zu rutschen. So gehts also nicht.
  21. Ja mit Blender könntest du es machen. In Unity könntest du ein empty game object erstellen und es an die Unterseite deines Diagramm Cubes positionieren. Dann fügst du das Diagramm Cube als child zum empty game object hinzu. Wenn du dann das empty game object skallierst müsste das Diagramm nur in eine Richtung skalieren. Das ganze kann man natürlich auch mit einem Script erstellen. https://i.imgur.com/TNiMvxM.gif https://stackoverflow.com/questions/39216454/scale-gameobject-on-just-one-side
  22. Du kannst ein Cube in einem 3D Programm erstellen und den Pivot Point exakt auf den unteren Face des Cube setzen. Wenn du in Unity dann als handle position Pivot wählst und skalierst wird es sich nur in eine Richtung skalieren, ausgehend vom Pivot Punkt.
  23. @Bradley Kann ich nur empfehlen. Den "Hipple-Stil" und die Architektur Vorlage auf Gitlab von Sascha. Schau es dir mal an! Hier ist es auch nochmal beschrieben: https://unity3d.com/de/how-to/architect-with-scriptable-objects @Sascha Ich hatte übrigens den ValueReferenceDrawer übersehen und fand es schon bisschen unschön das dass im Editor so wucherte mit aufklappbaren Variablen. Habe das dann gestern übernommen und war nochmal begeistert.
  24. Du kannst als Parameter ein ScriptableObject übergeben das dann wiederum beliebig viele Variablen enthalten kann, auf die in der Methode zugegriffen werden kann. Dafür muss die Methode natürlich angepasst sein. Ich kam auf die Idee aber sie gefällt mir nicht besonders, da ich dann in jeder Komponente wo ich so zugreifen will eine spezielle Methode anlegen muss die ScriptableObjects akzeptiert..
  25. Ja du könntest die Namen Vergleichen. Wenn du nur wissen willst ob es überhaupt doppelte Einträge in einer Liste gibt kannst Distinct nutzen: if(list.Count != list.Distinct().Count) { //doppelte Einträge vorhanden } Distinct entfernt doppelte Einträge von der Liste. Mit LINQ kann man auch komplexere Abfragen erzeugen, kenne mich damit aber nicht aus. Hier: https://stackoverflow.com/questions/18547354/c-sharp-linq-find-duplicates-in-list
×
×
  • Create New...