Jump to content
Unity Insider Forum

Sascha

Administrators
  • Content count

    10,933
  • Joined

  • Last visited

  • Days Won

    486

Everything posted by Sascha

  1. Sascha

    Dateien(Texturen) speichern

    Die musst du dann wohl selber machen. Dein Workflow ist aber auch etwas eigenartig... warum soll die Normal Map aus Unity kommen? Warum hast du dafür keine normal importierte Datei?
  2. Sascha

    Anzahl eines Items aus einer Liste bestimmen

    Du kannst auch eine Suppe mit einer Gabel essen.
  3. Sascha

    [Frage] GUI Optimieren

    Es gibt nicht für alles eine Anleitung. Als Programmierer muss man auch einfach mal etwas selber bauen, ohne sich dabei leiten zu lassen.
  4. Sascha

    [Frage] GUI Optimieren

    Klar... ich glaube, Canvas-Objekte machen das tatsächlich nicht von alleine, aber du kannst die Position der Objekte (nicht einmal unbedingt ihre Transform-Position, sondern einfach den Index in der Liste) verwenden, um relativ zum aktuellen Listenausschnitt festzustellen, ob die Elemente im Bild sind oder nicht. Eine geiwsse Ladezeit für die Liste bei vielen Elementen wird es dabei aber sicherlich geben. Wie das beim Scrollen mit der Performance aussehen würde, kann ich gerade nicht vorhersagen.
  5. Sascha

    [Frage] GUI Optimieren

    Vielleicht ist es einfacher, keine lange Liste zu haben, sondern Pagination zu benutzen. Also X Elemente anzuzeigen, Knöpfe zum Blättern anzubieten und dann die nächsten X Elemente anzuzeigen.
  6. Sascha

    Zufallszahlen mit Schrittgrößen

    Also ich kriege mit dem Code 1 und 3 raus, wie erwartet.
  7. Sascha

    Anzahl eines Items aus einer Liste bestimmen

    In diesem Fall solltest du keine Liste benutzen, sondern ein Dictionary. Ein Dictionary ist ein Datentyp, bei dem ein Wert zu einem Schlüssel zugewiesen werden. Typ von Schlüssel und Wert kannst du dir aussuchen. Es erlaubt dir, den Schlüssel hineinzustecken und den entsprechenden Wert herauszubekommen. Du definierst es so: Dictionary<TKey, TValue> wobei TKey der Typ des Schlüssels und TValue der Typ des Wertes ist. Da der Typ deines Items "InventoryItem" ist und der Wert eine Zahl (die Anzahl) sein soll, muss das so aussehen: Dictionary<InventoryItem, int> storedItems = new Dictionary<InventoryItem, int>(); So fragst du die Anzahl ab: storedItems[ip] // z.B. Debug.Log("Ich habe " + storedItems[ip] + " Stück " + ip); Gleichermaßen kannst du die Anzahl setzen: storedItems[ip] = 100; Wenn du ein Item anfragen willst, das aber gar nicht in der Liste ist, dann kracht es. Deshalb gibt es TryGetValue, falls du dir nicht sicher sein kannst: int amount; if (storedItems.TryGetValue(ip, out amount)) { // Es gibt dieses Item im Dictionary Debug.Log("Ich habe " + storedItems[ip] + " Stück " + ip); } else { Debug.Log("Ich habe kein " + ip + " in meinem Inventar"); } Auf diese Weise kannst du auch Dinge hinzufügen oder wegnehmen: public void ChangeAmount(InventoryItem item, int changeAmount) { int currentAmount; if (storedItems.TryGetValue(item, out currentAmount)) { // Das Item gibt's schon im Inventar var newAmount = currentAmount + changeAmount; if (newAmount > 0) { // Ändere die Anzahö storedItems[item] = newAmount; } else { // Lösche das Item aus dem Inventar storedItems.Remove(item); } } else { // Das Item ist noch nicht im Inventar if (changeAmount > 0) { // Füge das Item in das Inventar hinzu storedItems.Add(item, changeAmount); } } }
  8. Sascha

    Zufallszahlen mit Schrittgrößen

    Öh... habe schon mehrere Male etwas geschrieben, hab's dann aber wieder gelöscht, ohne es abzuschicken. Anstatt groß darüber nachzudenken, würde ich die Herangehensweise leicht ändern. public static int RandomWithSteps(int min, int max, int interval) { var range = max - min; var maxIntervalCount = range / interval; var intervalCount = Random.Range(0, maxIntervalCount + 1); return min + intervalCount * interval; }
  9. Sascha

    Dateien(Texturen) speichern

    Naja... dein Original ist eine Bilddatei die von irgendwo her kommt. Sie hat jede Menge Import Settings weil die Daten, die du hast, so oder so gemeint sein können. Deine eigene Textur hast du direkt in Unity erstellt. Die Daten, die du reingegeben hast, kommen auch so wieder heraus, wenn du die Textur benutzt. Da gibt's also kaum etwas beim Import einzustellen. Die Frage ist: Was willst du denn eigentlich mit der Textur machen? P.S. Bitte keinen Vierfachpost nächstes Mal, sondern einfach den Bearbeiten-Knopf benutzen.
  10. Sascha

    [Frage] GUI Optimieren

    Die Listen sind vermutlich recht lang? Ist nicht unüblich, mehrere "Blöcke" von Listenelementen zu haben und diese beim Scrollen wiederzuverwenden. Also... Jeder Block ist etwas länger als auf einmal angezeigt wird. Man scrollt von Block 1 zu Block 2, zu Block 3, und sobald man in Block 3 ankommt wird Block 1 genommen, inhaltlich verändert und zu Block 4 gemacht.
  11. Sascha

    Invoke ruft nicht auf

    Witzig, damit ist mein Hauptkritikpunkt in der Tat beseitigt. Man könnte also mal Performance vergleichen. Verbleibende Vorteile meines Invokers sind, dass man die gestartete Coroutine manuell wieder abbrechen kann (kann man afaik bei Invoke nicht) - und die zusätzlichen Funktionen (sind ja nicht nur Invoke und InvokeRepeating). Aber jetzt wird's Geschmackssache
  12. Sascha

    Zufallszahlen mit Schrittgrößen

    Random.Range(x, y) gibt Zahlen zwischen x und y-1 zurück, wenn beides Ganzzahlen sind.
  13. Sascha

    Anzahl eines Items aus einer Liste bestimmen

    Du hast IndexOf falsch verstanden. Wie der Name sagt, gibt es dir den (ersten) Index des Elements zurück. Wenn du also [Apfel, Apfel, Birne] hast gibt dir IndexOf(Apfel) 0 zurück und IndexOf(Birne) 2. Ist ein Element gar nicht vorhanden, wird -1 zurückgegeben, da 0 ja heißen würde, dass das Element an erster Stelle steht. Ist denn die Reihenfolge der Items in deinem Inventar überhaupt wichtig? Also - ist es wichtig dass du [Apfel, Birne, Apfel] hast oder wäre 2 Äpfel, 1 Birne auch in Ordnung?
  14. Sascha

    Dateien(Texturen) speichern

    ScriptableObject brauchste nicht, du kannst eine Textur direkt als .asset-Datei speichern. AssetDatabase.CreateAsset(myTexture, "Assets/My Texture.asset"));
  15. Sascha

    [Gelöst]Script ohne deklaration verwenden

    Ja, das geht, aber ich sage voraus, dass sich herausstellen wird, dass das nicht das gewesen sein wird, was du eigentlich wolltest. Bei Objektorientierung gibt es Vererbung und/oder Implementation als Grundkonzepte, die eine "ist-ein"-Beziehung realer Zusammenhänge wiederspiegeln. "Ein A ist ein B" ist gleichbedeutend mit "Ein B hat alle Eigenschaften, die ein A hat, vielleicht noch mehr". Wenn du deshalb eine Klasse "FeuerwehrAuto" schreibst, kannst du diese von "Auto" erben lassen, denn ein Feuerwehrauto kann alles, was ein Auto kann. class FeuerwehrAuto : Auto Da du damit definiert hast, dass "FeuerwehrAuto ist-ein Auto", kannst du überall, wo es um Autos geht, auch ein FeuerwehrAuto benutzen. Auto meinAuto = new FeuerwehrAuto(); Das geht, weil ein FeuerwehrAuto nunmal alles kann, was ein Auto kann. meinAuto.GibGas(); Allerdings reden wir hier von einem Auto, und deshalb können wir nicht die Sirene anmachen. meinAuto.SireneAn(); // Kompiliert nicht Es könnte ja sein, dass weiter oben ein anderes Auto, das kein FeuerwehrAuto ist, in der Variable referenziert wurde. Zurück zu Unity: Wenn du ein Script erstellst, dann erbt deine Scriptklasse von MonoBehaviour. class MeinScript : MonoBehaviour MonoBehaviour erbt von Behaviour, welches wiederum con Component erbt, und Component ist die Klasse, die die Funktionialität hat, dass man Objekte der Klasse als Komponenten auf GameObjects ziehen kann. Davon erben z.B. wiederum Renderer, Light und Collider. Wenn du jetzt ein beliebiges Script referenzieren willst, kannst du eine Variable vom Typ MonoBehaviour anlegen. MonoBehaviour mb = GetComponent<MeinScript>(); // oder eben public MonoBehaviour mb; Allerdings weiß der Compiler natürlich wieder nicht, ob du da ein MeinScript oder ein AnderesScript reinziehst. Deshalb kannst du keine MEthode aufrufem, die du in MeinScript definiert hast, und auch keine der Eigenschaften auslesen oder setzen. Es gibt jetzt die Möglichkeit, dein MonoBehaviour-Objekt darauf zu testen, von welcher Klasse es nun genau stammt. Als ob du zum Auto gehst und fragst "bist du ein FeuerwehrAuto?" Das ist allerdings etwas, das man niemals machen sollte. Das ist so eines des Dinge, die ganz schlechten Code ausmachen. Was du stattdessen machen kannst ist, die Gemeinsamkeiten zu nutzen, die in der Superklasse definiert sind. So ist in Behaviour die "enabled"-Eigenschaft definiert, mit der man Komponenten an und aus machen kann. Diese Eigenschaft haben alle Klassen, die von Behaviour erben, und deshalb kannst du sie benutzen, wie GibGas. Jetzt ist natürlich die Frage: Was willst du denn eigentlich damit machen?
  16. Sascha

    Invoke ruft nicht auf

    Ja, dann mal ran an den Speck!
  17. Ist vielleicht nicht das, was du hören willst, aber: Selber einen schreiben. Einen simplen FPS controller, der nicht durch Wände läuft und sich umgucken kann, ist gar nicht mal so ein dickes Ding. Der Standard-FPS-Controller hat einige Features drin, die eine kleine XR-Präsentation nicht einmal ansatzweise braucht - lass dich also con dessen Umfang nicht abschrecken. Generell sind diese ganzen Standard Assets eher nur für Prototyping geeignet. Sobald du damit wirklich ein Produkt erstellen willst, fängt's an, überall zu haken, weil du eben bei jedem Projekt etwas andere Ansprüche hast, und diese eben nicht alle vorausschauend erfüllt werden können. Versuche also nicht, Standard Assets umzubiegen - schreib dir etwas eigenes. Und ja, im Zweifelsfall heißt das Programmieren lernen. Du du rumspringen möchtest, bietet sich ein CharacterController mehr an als eine NavMesh-Lösung, also bleiben wir dabei. Du nimmst erstmal ein leeres GameObject und packst einen CharacterController drauf. Dann machst du ein neues C#-Script und packst es auch drauf. Dieses Script wird den CharacterController steuern, indem es den Move-Befehl ausführt. Dafür besorgt es sich in Awake erst einmal eine Referenz auf den CharacterController und speichert sie: private CharacterController controller; private void Awake() { controller = GetComponent<CharacterController>(); } Danach kannst du im Code an jeder Stelle mit dem Namen "controller" auf den CharacterController zugreifen, der auf demselben GameObject liegt wie das Script. Wir fügen noch einen Bewegungsvektor zum Script hinzu, den wir mit Input und Gravitation beeinflussen, und den füttern wir in die Move-Funktion, damit sich der Controller bewegt. Das Gerüst, um den Bewegungsvektor zu setzen, schreibe ich einfach mal hin. Ich hoffe, der ist weitestgehend selbsterklärend. private Vector3 movement; public float speed = 10; public float gravity = 10; public float jumpPower = 10; private void Update() { if (controller.isGrounded) { // controller berührt den Boden var input = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical")); input = Vector3.ClampMagnitude(input, 1); movement = transform.TransformDirection(input) * speed; if (Input.GetButtonDown("Jump")) { movement.y = jumpPower; } else { movement.y = -1; } } else { // controller ist in der Luft movement.y -= gravity * Time.deltaTime; } controller.Move(movement * Time.deltaTime); } Eigentlich will man nicht Update, sondern FixedUpdate benutzen, damit das Gameplay deterministisch ist... aber damit macht man wieder ein neues Fass auf. Diese Menge an Code reicht jedenfalls schon, um mit einem CharacterController durch die Gegend zu laufen und zu springen. Wenn du jetzt noch etwas Code hinzufügst, um das Objekt um die Y-Achse zu drehen, kannst du dich auch umschauen. Die Zeile mit "TransformDirection" sorgt dafür, dass man bei gedrehter Figur weiterhin nach vorne läuft.
  18. Sascha

    Invoke ruft nicht auf

    Programmieren seit ~20 Jahren. Unity seit ~10, glaube ich. Aber glaube nicht, dass du 10-20 Jahre brauchst, um "gut genug" zu sein. Du hörst nie auf, dich zu verbessern. Ich selbst habe mich gerade letzte Woche hier im Forum korrigieren lassen müssen, weil ich falsch lag Ob es realistisch ist, in einem Jahr ein Spiel zu releasen, und das auch als anfänger, hängt komplett von dir, deiner Lernfähigkeit und deinem Projekt ab. Flappy Bird klatsche ich dir an einem Tag hin. Rechne das mal X weil du noch dies und das lernen willst oder musst, um das zu implementieren, und du bist vielleicht bei einer Woche. Wenn dein Projekt allerdings keine Kleinigkeit ist, dann kann's auch mehr als ein Jahr dauern, egal, wie gut du solo bist. Ich sitze jetzt seit etwas über einem Jahr an meinem aktuellen Projekt. Da geht zeitweise schonmal die Motivation flöten und dann wird eine Woche lang eher nur gezockt... aber naja. Anderes Thema. Solange du an den Erfolg deines Projekts glaubst, wirst du auch Fortschritte machen. Als Anfänger würde ich vielleicht nicht unbedingt deine finanzielle Sicherheit von einem Traumprojekt abhängig machen, aber solange du dir die Zeit nehmen kannst, weiter zu arbeiten, wirst du auch immer weiter kommen. Und dich währenddessen weiterentwickeln und verbessern.
  19. Sascha

    Invoke ruft nicht auf

    Naja, es ist immer noch mindestens ein Dictionary Lookup und damit in jedem Fall nicht so schnell und elegant wie die Verwendung einer direkten Referenz. Aber... wie gesagt. Die Code-Qualität geht bei Verwendung von Strings immer nach unten (außer zum Ausgeben ), und damit ist diese ganze Palette von Funktionen für mich schon disqualifiziert.
  20. Sascha

    Invoke ruft nicht auf

    Ich bin gar nicht mal so der Performance-Freak. Mein Hauptaugenmerk bei Code ist "Code-Qualität". Das beschreibt Vorzüge von Code, die über das reine Funktionieren hinausgehen. Wichtige Begriffe sind Lesbarkeit, Robustheit (dass man Code später ändern oder erweitern kann, ohne dass gleich alles kaputt geht), Modularität, und einige andere. Strings haben generell das Problem, dass es Werte sind. "Player" ist ein String, und "PIayer" ist auch ein String. Siehst du den Unterschied? Beim zweiten folgt dem "P" ein großes "i". Der Compiler merkt sowas, denn er ist ein Computerprogramm... aber eben nicht bei Strings. Anders z.B. Klassen- oder Methodennamen. Wenn du so etwas schreibst: GetComponent<Lighht>() oder GetComponnent<Light>() dann wird dein Code nicht kompilieren und du kriegst eine Fehlermeldung, in welcher Zeile du etwas geschrieben hast, das nicht existiert. Oft sagt dir der Compiler bei solchen Fehlern sogar, welches Wort genau er nicht erkennt. Bei Strings kann er das nicht, da es Werte sind, und alle Werte sind erst einmal korrekt. Dein Code wird also kompiliert und ausgeführt. Dann kommt es zu "GameObject.Find" und er findet das Objekt nicht. Vielleicht, weil du dich vertippt hast und es dir keiner gesagt hat, vielleicht aber auch, weil irgendjemand in der Szene den Namen des Objekts kürzlich geändert hat, weil der neue Name besser passt - und schon funktioniert dein Code nicht mehr (Thema Robustheit, s.o.). Aber es kommt noch schlimmer: Bei solchen Funktionen kriegst du das gar nicht unbedingt direkt mit, wenn kein Objekt gefunden wurde. Oft geben die Dinger einfach null zurück und sind glücklich. Krachen tut es dann erst, wenn du das Objekt benutzt. Dann hast du als Fehlermeldung, dass du mit dem Objekt etwas machen wolltest, das dir rausgesucht wurde, das aber nicht ging, weil keines vorhanden ist. Der Fehler passiert also nicht bei GameObject.Find, sondern irgendwo später. Und dann darfst du suchen gehen, wo der Fehler ist. Zusammengefasst also: Warum solltest du dir Fehler aufhalsen, bei denen du selber recherchieren musst, was los ist? Du hast eine mächtige Rechenmaschine unter deinen Fingern, die diese Aufgabe viel besser bewältigen kann als du. Du musst nur deinen Code so schreiben, dass sie ihren Job auch machen kann. Und es gibt immer elegante Wege, GameObject.Find zu ersetzen. Wenn du mal nicht weißt, wie, frage gerne nach Hast du das mal gebenchmarked? Ich wäre mit solchen Aussagen vorsichtig. Ich meine mich zu erinnern, dass Unity zumindest für Tags eine vernünftige Beschleunigungsstruktur im Hintergrund laufen hat. Aber wie gesagt... um Performance geht's mir sowieso nicht. Und deshalb stellt sich mir die Frage gar nicht erst, wenn diese Funktionen sozusagen schon "eine Runde früher ausscheiden".
  21. Sascha

    Invoke ruft nicht auf

    Lasst uns das Thema nicht allzuweit von der ursprünglichen Frage entfernen, aber: Ich habe gehört, MEC soll ganz gut sein. Vor allem ist es kostenlos, also schadet's sicher nicht. Grundsätzlich gilt allerdings, dass man sich über Performance nicht zu viele Gedanken machen soll, bevor sie sich als Problem entpuppt. Für die drei Coroutines in einem kleinen Projekt also unbedingt MEC einzubauen, ist zwar kein Fehler, aber eben Zeitverschwendung. Bei weiteren Fragen, die nicht allzu viel mit der Frage von @cncrete zu tun haben, gerne ein neues Thema aufmachen
  22. Sascha

    Invoke ruft nicht auf

    Ich glaube, die haben andere Prioritäten. Abhilfe ist halt schnell geschaffen, wie du selber sagst. Andererseits bin ich aber scheinbar auch etwas radikaler als die, was Code-Qualität angeht. Die sind inzwischen selber einigermaßen vom GameObject.Find(WithTag)-Kurs runter, aber das hat auch schon eine Weile gedauert. Ich glaube, das kam damals in den ersten Versionen von der JavaScript-Kultur, an der sie sich orientiert haben. Naja, langer Rede kurzer Sinn: Strings sind bäh. Außer zum Ausgeben. Ach ja, kleiner Nachtrag zu @malzbies Coroutine - Es gibt WaitForSecondsRealtime, damit wäre das ebenfalls eine funktionierende Lösung.
  23. Sascha

    Einzelne Teile eines Objektes anklicken

    Naja, von nix kommt nix.
  24. Sascha

    Invoke ruft nicht auf

    Invoke benutzt Time.deltaTime, welches als Faktor Time.timeScale hat, welches wiederum 0 ist. Anders gesagt: Du hast die Zeit angehalten - und du kannst keine 2 Sekunden warten, wenn keine Zeit vergeht. Invoke ist sowieso Käse. Die von @malzbie beschriebene Coroutine hilft hier leider auch nichts, da WaitForSeconds ebenfalls über skalierte Zeit läuft, aber Invoke setzt nochmal einen obendrauf, weil es strings benutzt. Ieh! Nimm stattdessen meine Invoker-Klasse, die gibt's hier: https://gist.github.com/FlaShG/09b80bbc02a4bb6f9e2dda23ff9c5f8d. Einfach komplett herunterladen und irgendwo in deine Assets packen. Benutzt du dann wie Invoke, nur ohne Strings. Und damit das in Echtzeit abläuft, habe ich gerade noch InvokeInRealtime eingebaut. Statt Invoke("Methode", 2f); machst du damit StartCoroutine(Invoker.InvokeInRealtime(Methode, 2f)); Beachte: Der Name der Methode jetzt nicht mehr in Anführungsstrichen. Ansonsten ist absolut richtig und wichtig, was @malzbie sagt - du musst nochmal über die ganze Sache rüberschauen, dass du den Invoke-Befehl nicht jeden Frame auf's Neue ausführst.
  25. Sascha

    Icon von Gameobject erstellen

    Ich rate einfach mal, dass das heißt, dass du einen Screenshot von einem 3D-Modell im fertigen Projekt (nicht im Editor) anzeigen willst. Dafür musst du einfach tatsächlich einen Screenshot machen und das Bild in deine Assets speichern. Eine vorgefertigte Funktion zum automatischen Generieren eines solchen Bildes zur Laufzeit gibt es nicht. Ich meine... man könnte da etwas bauen, aber solange man nicht prozedural generierte Modelle hat, ist das etwas unnötig.
×