Jump to content
Unity Insider Forum

Leaderboard

Popular Content

Showing content with the highest reputation since 12/24/2021 in all areas

  1. Hallo Leute, ich war lange wieder nicht aktiv weil viel um die Ohren. Der Jahreswechsel ist immer eine gute Zeit um kreativ zu werden. Vielleicht staut sich auch einfach etwas in mir weil meine tägliche Arbeit sehr Fakten basiert ist und sehr viel Analytik dazu gehört. Also wenig Raum um Kreativ zu sein. Sind halt Zahlen und Fakten. Also habe ich mich die letzten Wochen wieder damit beschäftigt meine zeichnerischen Fähigkeiten auszubauen. Das Ergebnis meiner Mühe möchte ich hier Euch zeigen. Das erste Bild zeigt einfach einen Mann oder Cyborg (keine Ahnung) mit einer Waffe Das zweite Bild ist Phantom ein Held aus meiner Kindheit. Habe viele Comic über die Abenteuer von Phontom gelesen. Das dritte Bild ist ein weiterer Comicheld aus meiner Kindheit, aber der ist ja heute bekannter als Phantom. Hoffe es gefällt
    2 points
  2. Hallo Du könntest einen LineRenderer nutzen. https://docs.unity3d.com/Manual/class-LineRenderer.html Christoph
    2 points
  3. Moin! 1. Die üblichere Schreibweise ist die Lambda-Schreibweise. Die gibt's in mehreren Sprachen und wird, wenn man sie erstmal kennt, meistens als angenehmer empfunden als da "delegate" hinzuschreiben. Ein Lambda-Ausdruck (genau wie mit "delegate") ist einfach eine Schreibweise für eine Methode ohne Namen. Man kann also als Beispiele Methoden nehmen und dann die entsprechenden Lambda-Ausdrücke zeigen: a) private void Foo() { Debug.Log(5); } als Lambda-Ausdruck wäre () => Debug.Log(5) b) private void Foo() { Debug.Log(5); Debug.Log(10); } als Lambda-Ausdruck wäre () => { Debug.Log(5); Debug.Log(10); } Hier braucht man geschweifte Klammern, weil mehr als eine Anweisung drinsteht. c) Jetzt mal mit Parametern: private void Foo(int number) { Debug.Log(number); } wäre number => Debug.Log(number) und private void Foo(int number, string text) { Debug.Log(number + text); } wäre (number, text) => Debug.Log(number + text) Man bemerke hier, dass keine Parametertypen angegeben werden - da steht also nix davon, dass "text" ein string ist. Das liegt daran, dass Lambda-Ausdrücke zu Methodenreferenzen evaluieren. Diese werden als normale Werte behandelt - man kann sie also in eine Variable speichern oder eben als Parameter übergeben. Und in diesen Fällen ist vom Typ der Variable bzw. des Parameters her schon vorgegeben, dass da eine Referenz auf eine Methode kommen muss, die ein int- und einen string-Parameter hat. Action<int, string> foo = (number, text) => Debug.Log(number + text); // und jetzt kann man die Methode aufrufen foo(5, " Stück"); Mit Lambda-Ausdrücken kann man einem Objekt mehr als nur simple Werte in die Hand drücken, sondern ganze Verhaltensweisen. Deshalb kannst du die Dinger benutzen, um Buttons zu sagen, was sie tun sollen. btn.onClick.AddListener(() => GetComponent<MenuManager>().ButtonAction(i)); Soviel erstmal dazu. 2. Jetzt musst du (leider) das Konzept von Closures kennenlernen. Eine Closure ist wie ein Objekt, also ein Ding, das bestimmte Werte hat. Und jede anonyme Methode (also die, die du mit einem Lambda-Ausdruck erzeugst), hat so eine. Sie enthält die für die Ausführung der Methode relevanten Variablen aus der Umgebung, in der der Lambda-Ausdruck steht. var number = 5; Action foo = () => Debug.Log(number); foo(); Hier wird eine int-Variable mit dem Wert 5 definiert, eine Methode die den Wert der Variable ausgibt, und dann wird diese Methode aufgerufen. Es sollte also recht klar sein, dass die Zahl 5 ausgegeben wird. Die Variable "number" ist Teil der Closure der Methode, die von der Variable "foo" referenziert wird. Jetzt kommt der Knackpunkt: Closures machen pass-by-reference. Das heißt, dass hier nicht die 5 in der Closure gespeichert wird, sondern eine Referenz auf die Variable "number". Wenn du folgendes tust: var number = 5; Action foo = () => Debug.Log(number); number = 10; foo(); dann wird tatsächlich 10 ausgegeben und nicht 5, weil beim Aufruf der Methode der aktuelle Wert der Variable angeschaut wird. Wenn du also eine Schleife hast und in dieser Schleife Methoden erzeugst, die irgendetwas mit der Zählvariable i tun, dann wird am Ende jede dieser anonymen Methoden den aktuellen Wert von i nehmen - und das wird nun einmal der Wert am Ende des Schleifendurchlaufs sein, also in deinem Fall 1 bei einem Button bzw. 6 bei sechs Buttons. Die Lösung des Problems ist jetzt ein bisschen stumpf: Du machst in der Schleife eine neue Variable und kopierst da den Wert rein; dann benutzt du diese Variable in deinem Lambda-Ausdruck statt i: for(int i = 0; i < list.count; i++) { var btn = list[i]; var index = i; btn.onClick.AddListener(() => GetComponent<MenuManager>().ButtonAction(index)); } Dann wird die Variable "index" angeschaut, wenn man auf einen Button klickt - und der Wert dieser Variable ändert sich nicht mehr, weil sie am Ende des jeweiligen Durchlaufs (eigentlich) out of scope geht. Übrigens kannst du es dir (so als Schmakerl) sparen, jedes Mal GetComponent aufzurufen, indem du das vorher einmal machst: var menuManager = GetComponent<MenuManager>(); for(int i = 0; i < list.count; i++) { var btn = list[i]; var index = i; btn.onClick.AddListener(() => menuManager.ButtonAction(index)); }
    2 points
  4. Hallo Das müsste passen https://docs.microsoft.com/de-de/dotnet/csharp/language-reference/operators/operator-overloading Christoph
    2 points
  5. Entweder du nimmst einen Shader, der Beidseitig funktioniert, oder aber du erzeugst dir ein Kugel in einem 3d Programm, wie z.B. Blender, und drehst da einfach die Normalen der Flächen um.
    2 points
  6. Soda ist während des aktuellen Unity Asset Store Sales übrigens um stolze 50% reduziert! https://assetstore.unity.com/packages/tools/integration/soda-scriptableobject-dependency-architecture-137653
    2 points
  7. 😄 habe meinen Fehler bemerkt und wollte den Eintrag schon abschließen, aber du bist ja unglaublich schnell...
    1 point
  8. Nimmste halt den Teil mit dem "Controlpoint" aus deinem Code raus? var Controlpoint1GameObject = new GameObject($"Controlpoint 1");
    1 point
  9. Habe mir das mal angesehen. Es vereinfach die Organisation und vereinfacht den Programmcode. Es erspart mir die Implementierung eines eigenen "Event-Systems" wie ich das bis jetzt mit den anderen Gegnern gemacht habe und das ganze eingebaut in ein recht große Update()-Methode. Hmmm wenn ich das vorher gewusst hätte....ich versuche mal das für die Endgegner zu benutzen.
    1 point
  10. Hallo Grundsätzlich würde ich mir über Geschwindigkeit erst sorgen machen, wenn es so weit ist. Da die Abfrage eh nicht jeden frame, sondern immer nur beim Bauen stattfindet, dürfte es auch kein Problem sein. Welches Objekt dort steht, weiß du wenn du entweder alle Objekte durchgehst und deren Positionen checkst oder du speicherst in deinem grid jeweils noch eine variable für den objettyp, der auf ihm steht. Christoph
    1 point
  11. Ein Event ist einfach nur ein Ding, das eine Liste von Reaktionen hat und ausgelöst werden kann. Wird ein Event ausgelöst, werden dadurch alle dessen Reaktionen ausgelöst. Das ist alles. Events können auf verschiedenste Arten implementiert werden. Was du dadurch gewinnst ist, dass du nicht jeden Frame immer wieder dieselben Checks ausführst, obwohl sich die allermeiste Zeit gar nichts ändert, sodass sowieso immer dasselbe herauskommt.
    1 point
  12. Wieso kann ich da nichts drin bearbeiten? Gelöst: Einfach Dupliziert
    1 point
  13. Persistent sind die Listener, die im Editor eingestellt werden. Mit AddListener, RemoveListener und RemoveAllListeners arbeitest du nur mit Listenern, die im Code behandelt werden. Du hast quasi zwei Listen: Die im Editor und die, die du im Code erzeugst.
    1 point
  14. Das kann schon normal sein, aber da ich sowas nie selber gebaut habe, weiss ich es nicht. Du kannst dich ja mal mit dem neuen Inputsystem vertraut machen. Da hast du Objekte oder Komponenten im Spiel, die all deine Inputs übernehmen. Die sollten, wenn sie beim Szenenwechsel aktiv bleiben, komplett durchgängig funktionieren. Aber ich muss dir sagen, so mächtig das neue Inputsystem auch ist, so schwierig ist es zu verstehen. Es gibt mindestens 3 unterschiedliche Arte, das Sytem einzubinden und alle haben Vor- und Nachteile. Ich nutze jedenfalls das neue System und bin zufrieden damit.
    1 point
  15. Haha! Ja wer wer war denn DAS? Mach dir nichts draus. Solche Dinge passieren einfach. Schön dass du den Fehler gefunden hast.
    1 point
  16. Doll! Also nach dem, was du da schreibst, bleibt eigentlich echt nur die Möglichkeit, dass das Canvas zwar geschlossen wird, aber trotz allem danach sofort wieder geöffnet wird. Bist du dir sicher, dass es nur einen Ort gibt, von dem aus das Canvas wieder geöffnet wird? Wird das nur über einen Button gemacht oder ist da eine Variable mit im Spiel? Wenn du das Canvas GameObject deaktivierst/aktivierst, dann gib ihm doch mal ein kleines Script, mit OnEnable und OnDisable Funktionen. In beiden Funktionen führst du ein Debug.Log aus. Mit unterschiedlichen Texten und vielleicht der Time.time, um zu sehen, wann etwas passiert ist. Ach so. Du hast scheinbar Schwierigkeiten damit, wann etwas enalbled und wann etwas activated wird. Kurze Erklärung dazu: Enabled werden nur Komponenten, die an einem Gameobject dran hängen. Also die Dinger, die ein Häkchen Im Inspector haben. Scripte, Audiosources, Collider, Meshrenderer usw. Manche Komponenten kannst du nicht Enablen/Disablen. Das sind z.B. Transform, Material und Rigidbody. Aktivated werden komplette GameObjects ! Wenn du ein Canvas erzeugst, dann baut Unity dir ein GameObject mit mehreren Canvas-Components zusammen. Du kannst jetzt die Canvas Hauptkomponente disablen, und lässt alle anderen Komponenten, wie den CanvasScaler und den GraphicRaycaster an, oder du deaktivierst das ganze GameObject mit all seinen Komponenten da drin. Das bleibt dir überlassen. Es ist aber eben ein Unterschied, ob man nur eine Komponente disabled und den Rest laufen lässt, oder ob man das ganze GameObject deaktiviert. Wenn du das GameObject aktivierst/deaktivierst, musst du eine Referenz zum Objekt gebildet haben, weil es sonst, wenn deaktiviert, nicht mehr gefunden werden kann. Ich persönlich deaktiviere das ganze Canvas GameObject, denn dann ist alles aus.
    1 point
  17. Der Lambda-Ausdruck ist ein Statement, das zu einem Wert evaluiert. Dieser Wert ist eine Referenz auf die Methode, die du erzeugst. Mit diesem Wert musst du bei Lambda-Ausdrücken etwas machen. Genauso wie du nicht 5 + 5; in deinen Code schreiben kannst, sondern das Ergebnis irgendwie benutzen musst var number = 5 + 5; musst du das auch bei Lambda-Ausdrücken machen. () => Debug.Log(number); // Geht nicht Action foo = () => Debug.Log(number); // Geht Damit ist hoffentlich auch die Frage geklärt: Die Methode hat keinen Namen, genau wie Objekte keinen Namen haben. Aber die Variable, die die Methode referenziert, hat einen Namen (hier foo), über den du die anonyme Methode aufrufen kannst. Sie zu erzeugen passiert genau da, wo sie gebraucht werden. Man kann halt tatsächlich auch eine ganz normale Methode definieren und diese in einer Action-Variable referenzieren: private void Start() { Action foo = MyMethod; foo(); } private void MyMethod() { Debug.Log("hi"); } Das kann auch oft die bessere Variante sein. Beim Button geht das genauso: btn.onClick.AddListener(MyMethod); und es spricht erstmal wirklich nicht viel dagegen. Wenn deine Methode einen guten Namen hat, ist das 1a. Knifflig wird es dann aber, wenn du z.B. sechs verschiedene Verhaltensweisen haben willst, und wenn diese sich auch nur durch eine einzige Zahl unterscheiden. So wie bei dir Die vordefinierte Methode hat nämlich im Gegensatz zur anonymen keine Closure. Naja, abgesehen vom Objekt, in dem sie steckt. Oder anders gesagt: Du kannst keine Parameterwerte an MyMethod binden, wenn diese Methode Parameter hätte. Nehmen wir dein Beispiel: private void Start() { btn.onClick.AddListener(MyMethod); } private void MyMethod(int index) { menuManager.ButtonAction(index); } hier würde das Programm erwarten, dass der Button deiner Methode beim Aufruf den Index übergibt. Tut er ja aber nicht. Und du kannst auch nicht schreiben btn.onClick.AddListener(MyMethod(index)); weil du dann nicht MyMethod übergibst, sondern MyMethod aufrufst und dann das übergibst, was dabei zurückkommt. Mit () => menuManager.ButtonAction(index) erzeugst du eine neue, parameterlose Methode, in die dein Index fest integriert ist. Wenn deine Schleife also sechsmal durchläuft, hast du sechs neue Methoden generiert, die wegen des sich ändernden Index tatsächlich auch alle unterschiedlich sind. Das Äquivalent dazu wäre MyMethod1, MyMethod2, MyMethod3 usw. zu definieren... merkste Du erzeugst also neue Methoden zur Laufzeit, damit z.B. so ein Unity-Button einfach stumpf eine Methode zum ausführen in die Hand kriegt. Diese Methode ist dann einzigartig und braucht beim Aufrufen keinen Parameter mehr, um anders zu sein als die der anderen Buttons. Und zuallerletzt: "Action" ist in System definiert. Du musst also System.Action schreiben oder, was fast immer besser ist: using System; an den Anfang.
    1 point
  18. Danke, habe ich schon geahnt. Wer sucht der findet ...... geklärt ..... In der Nähe der "Grenze" befindet sich ein Enemy mit einem sehr großen Collider (bewußt so gestaltet, aber vergessen !), der noch nicht bearbeitet ist.
    1 point
  19. Im text steht, dass es geht. Wichtig ist, wenn man > overloaded muss auch < existieren.
    1 point
  20. Hallo Auch auf die Gefahr hin, als Fanboy zu gelten: http://blog.13pixels.de/2019/why-strings-are-not-your-friend/ Christoph
    1 point
  21. Joa, ich auch, aber das ist so ein kurzer Code dass es mir egal war. Sobald es minimal komplizierter wird, kommt man mit der Herangehensweise nicht mehr weit
    1 point
  22. Hallo Lies dir das mal durch: http://blog.13pixels.de/2019/what-exactly-is-fixedupdate/ Christoph
    1 point
  23. Ein kleines Update zum aktuellen stand der Dinge; wir haben jetzt bewegliche Plattformen, Falltüren, Sprungfedern und einen neuen Gegner. 😃
    1 point
  24. Hallo Habe ich schon, aber dein pooling asset habe ich mir gegönnt. Christoph
    1 point
  25. Mit dem Profiler wusste ich bis vor 3 Stunden noch nicht wirklich umzugehen. Ich konnte aber durch Zufall im Profiler das Problem oder Probleme lokalisieren und verstehe jetzt auch wo ich beim nächsten Mal suchen muss. Zum Glück hat sich ein weiterer Zufall dazu gesellt und ich konnte eine Lösung finden. Durch Spine 2D wurde ein Mesch-Generator angezeigt mit um die 40% Auslastung und im Deep Mode konnte ich das ganze auf Spine's Clipping Funktion zurück führen. Die Lösung war in diesem Fall das Clipping zu vermeiden, dafür genügt es den Hacken in der Skeleton Animation bei "Use Clipping" zu entfernen(Für Alle die das selbe Problem haben)(Clipping scheint ein Feature zu sein, welches ich in meinem Fall nicht benötige). MfG DI3FL4MM3
    1 point

Announcements

Hy, wir programmieren für dich Apps(Android & iOS):

Weiterleitung zum Entwickler "daubit"



×
×
  • Create New...