Jump to content
Unity Insider Forum

Leaderboard

Popular Content

Showing content with the highest reputation since 09/22/2020 in all areas

  1. Moin! Ich habe jetzt schon lange nichts mehr gepostet obwohl ich an diversen Spielen dran bin. Nun will ich euch mal zeigen, woran ich hauptsächlich bastle. Es ist ein Arcade-lastiges Spiel, bei dem man mit Flugzeugen und nem Zeppelin Missionen erfüllen muss. Natürlich wird dabei geballert! Obwohl es ein 3D Game ist, bewegt sich alles nur auf 2 Ebenen. So wie bei alten Sidescrollern. Aber seht einfach selbst. Hier ist mal eine Minute aus meinem Prototyp.
    5 points
  2. Aktuell hatte ich einige Tage Zeit, um ein neues Projekt im Comic LowPoly Stil zu beginnen. Noch gibt es nicht viel zu sehen, aber 2 Flitzer sind modelliert: Mal sehen, wie weit ich diesmal kommen werde. 🙂
    4 points
  3. Hallo, heute möchte ich euch das erste Video von meinem Orfaya-RPG Projekt vorstellen. Zu sehen ist ein kleiner Rundgang am Strand und ein Dialog mit Lomar, einem Fischer aus dem Dorf. Vorab zum Ton. Mein schönes Studio-Micro ist leider defekt. Daher musste meine Webcam ran. Ich bitte den Ton zu entschuldigen. Was noch fehlt sind die Hintergrundgeräusche und es ist noch etwas leblos am Strand. Ich werde noch ein paar Krabben, Möven etc. einbringen.
    3 points
  4. Heute gibts mal wieder neue Bilder! Es hat sich die letzten Monate viel getahn, vor allem in der Landschaft hat es größere Änderungen gegeben, die ich euch gern präsentieren möchte.
    3 points
  5. Youtube Video Präsentation unserer Möglichkeiten, Augmented und Virtual Reality Anwendungen im Zusammenspiel zu erleben. Unser Hauptaugenmerk lag auf der hochwertigen Visualisierung eines interaktiven Modells für AR und VR und der Vernetzung der Anwendung. Sowohl AR- als auch VR-Anwendungen funktionieren für sich alleine, können aber auch miteinander vernetzt werden. Neue Produkte oder Ideen können so live einem breiten Publikum präsentiert werden. Alle Kunden erleben die gleiche Interaktion mit unterschiedlichen Technologien (VR-Brille, Handy, Tablet, PC...). Diese Demo ist als Beispiel für den Einsatz bei virtuellen Messen, Tagungen oder anderen innovativen Herausforderungen angedacht. Weitergehende Information über uns findet Ihr auf www.virtence.com Über Feedback jeder Art freuen wir uns. Virtence
    3 points
  6. Benutze einfach dafür DateTime. Das tut schon alles was du brauchst.
    3 points
  7. Hi, habe die letzten vier Tage damit verbracht mich tiefer in Blender einzuarbeiten. Habe das Raumschiff Comet aus der Serie Captain Future nachmodelliert. Nicht ganz perfekt, aber für einen Anfänger nicht schlecht -denke ich-
    3 points
  8. Ja und nein. C# ist eine typstarke Sprache. Das heißt, dass alle Variablen, Felder, Parameter und Funktionen (also Methoden, die etwas zurückgeben) einen Typ deklariert haben müssen. ...aber... C# ist auch eine objektorientierte Sprache. Deine Komponente erbt von MonoBehaviour, erbt von UnityEngine.Object, erbt (iirc) von System.Object. Und am Ende dieser Kette kommt immer System.Object. Sogar primitive Typen wie int und float erben davon. Was man machen kann ist, dass man einen gemeinsamen Supertyp benutzt: class Weapon : Item class Potion : Item class Armor : Item Dann gibt deine Methode ein Objekt vom Typ "Item" zurück. Und weil Vererbung "ist-ein" bedeutet (ein "Weapon" ist-ein "Item"), kann das Item eben eine Waffe oder ein Rüstungsteil sein. Wenn aber jetzt der Code, der den Rückgabewert in die Hand kriegt, eine Referenz auf eine Waffe erwartet, gibt's nen Compilerfehler - denn es könnte ja ein Trank sein, der da zurück kommt. C# ist aber auch eine Sprache, die Generics versteht. Man kann einen Typ (oder mehrere) in einer Methodensignatur definieren und diesen dann im Rest der Signatur und im Rumpf benutzen: public T FindAThing<T>() Der generische Parameter "T" steht für einen Typ, der hier nicht weiter definiert ist, aber die Methode soll bitte ein Objekt dieses Typs zurückgeben. Der Typ wird dann woanders definiert, z.B. beim Aufruf der Methode. Kennst du vielleicht von GetComponent. Light light = GetComponent<Light>(); // Geht Collider collider = GetComponent<Light>(); // Aua Die beiden Zeilen rufen dieselbe Methode auf, aber die untere Zeile wird nicht einmal kompiliert, weil der erwartete Typ (Collider) und der Rückgabetyp (Light) nicht passen. Die Methode gibt also unterschiedliche Dinge zurück, je nach generischem Parameter. Du kannst das auch weiter spezifizieren: public T GetItem<T>() where T : Item Hier beschränkst du T auf alle Typen, die von "Item" erben (und Item selbst). GetComponent hat z.B. das hier: public T GetComponent<T>() where T : Component Sodass GetComponent meckert, wenn du GetComponent<GameObject>() schreibst, weil GameObject keine Component ist. Vielleicht auch interessant ist Instantiate. Instantiate gibt ja immer etwas von dem Typen zurück, den man reinsteckt: public MyComponent prefab; MyComponent instance = Instantiate(prefab); // oh yes GameObject goInstance = Instantiate(prefab); // oh no Das machen die so: public T Instantiate<T>(T original) where T : UnityEngine.Object Man kann einen generischen Typen also auch als Parameter benutzen, und dieser ist dann der gleiche Typ wie beim Rückgabewert. Hier also: Was reinkommt, kommt auch raus... zumindest Typ-weise. Wenn C# dann den Typen aus dem Parameterwert herleiten kann, braucht man den Parameter beim Aufruf auch nicht mehr explizit in die spitzen Klammern schreiben. Aber... das führt schon etwas weit. In deinem Fall ginge also public T GetItem<T>() where T : Item Aber was macht man damit jetzt im Rumpf der Methode? Zuerst einmal kannst du T als Variablentyp benutzen: T thing = GetATFromSomewhere(); Dann kannst du den generischen Parameter in ein System.Type-Objekt umwandeln: System.Type type = typeof(T); Und jetzt wird's leider knifflig und sogar ein bisschen hässlich. Man kann nämlich nicht einfach schreiben: return (T)myWeapon; Das wäre unsicher. Man kann das aber enforcen: return (T)System.Convert.ChangeType(myWeapon, typeof(T)); Da muss man dann nur echt aufpassen, dass T auch wirklich "Weapon" ist. if (typeof(T) == typeof(Weapon)) { return (T)System.Convert.ChangeType(weapon, typeof(T)); } Switch-Statement wird da schwieriger, aber man kann da evtl. auf Strings ausweichen. Hier ist sowieso alles unsicher, da machen Strings den Kohl auch nicht mehr... mager. Und man kann mit nameof ein bisschen den Schaden mitigieren. switch (typeof(T).Name) { case nameof(Weapon): return (T)System.Convert.ChangeType(weapon, typeof(T)); }
    3 points
  9. Übrigens kleine änderung bei mir, falls das hier jemals jemad liest : Ich habe mit einem Studium an der WBH im bereich Game Development begonnen. Bin jetzt seid ca 3 Monaten dabei. Also so ziemlich genau zwei Jahre nachdem ich mich hier im Forum vorgestellt habe. Mensch wie die Zeit vergeht... 🙃
    2 points
  10. Hallo, ich habe meine Inselkarte bezüglich der Arbeitstitel etwas überarbeitet. Ich hatte ja zwei ähnliche Regionen vorgesehen. Es sollte den Fantasy-Wald und den Magie-Wald geben. Ich habe es jetzt beim Fantasy-Wald belassen und eine zusätzliche Region, die Bergwelt, dazu genommen. Das Sieht jetzt so aus: Desweitere habe ich mich an den Arbeitstitel „Das Dorf“ gemacht und diesen Bereich etwas detaillierter ausgearbeitet. Geschichte/Beschreibung: Das Dorf stellt die grundsätzliche Versorgung von Orfaya sicher. Die Bewohner des Dorfes gehen dem Fischfang nach und liefern den gefangenen Fisch an die Ostküste in den Fantasy-Wald. Der andere Teil der Bewohner arbeitet in den Minen. Die dort abgebauten Rohstoffe (Gold, Mineralien etc.) gehen ebenfalls in die Stadt an die Ostküste. Vor ein paar Jahren gab es merkwürdige Vorfälle auf Orfaya. Der einst so sichere Transportweg verwandelte sich nach und nach zu einem gefährlichen Unterfangen. So richtete sich plötzlich die heimische Tier- und Pflanzenwelt gegen die eigene Bevölkerung. Von Zeit zu Zeit öffneten sich auch Portale aus denen monströse Gestalten erschienen und den Bewohnern nach dem Leben trachteten. Somit verharren die Bewohner des vorgelagerten Dorfes an diesem Ort. Niemand traut sich mehr an die Ostküste zu gehen. Legende: = gesunkenes Schiff = Strand = Druide = Portal = Händler = Zauberbrunnen = Teich = Händler = Hochplateau = Wasserfall = Übergang Hochebene = Mine = Mine = Mine = Erfinder = Mine
    2 points
  11. Wünsche euch allen ein schönes Wochenende!
    2 points
  12. Moin, hier mal ein neues Video von mir. Ich stelle hier die Funktionsweise verschiedener Reflexionstechniken anhand der Unity-Engine, in Verbindung mit gerenderten Szenen vor und zeige einen direkten grafischen Vergleich der einzelnen Techniken. Verglichen & erklärt wird das Ray-Traced Reflection, Screen-Space Reflection, Planar Reflection und die klassischen Cubemaps. In diesem Video habe ich versucht, soviele Details wie möglich einfließen zu lassen, ohne Zuschauer, die nicht mit der Spieleentwicklung vertraut sind "abzuschrecken". Jedoch denk ich, dass die Informationen meiner Recherche, die auch auf der Analyse des Sourcecodes einiger Renderer/Renderpipelines basiert, in dieser Form auch für den ein und anderen Entwickler interessant ist. Ich wünsche mal viel Spaß mit dem aufwendigsten Video, das ich bisher gemacht habe:
    2 points
  13. Vielen Dank! das ganze Video war auf jeden Fall extrem Aufwändig und ich musste für solche Effekte einige Tricks nutzen. Es handelt sich bei den Animationen aus einer Mischung von Unity 3D und Cinema 4D. Für den Übergang von 3:11 bis 3:15 wurden beispielsweise 8 verschiedene Renderpässe / Rendervorgänge benötigt: - Zwei dieser Pässe bestehen aus ein in Unity gerendertes statisches Bild, welches in Cinema 4D auf Geometrie projiziert wurde - Zwei weitere für eine beleuchtete Geometrie - Zwei Wireframe-Versionen - Und zuletzt zwei Masken, die in After Effects dabei helfen, alles zu dem gewollten Effekt zusammen zu mischen. Hier mal ein Beispiel mit dem Frame 139 dieser Animation: Die anschließende Welle war dabei relativ einfach, hier wurde die Szene ein weiteres Mal gerendert. Das rote Netz war hier während der gesamten Animation sichtbar, so konnte ich während der Videobearbeitung entscheiden, wann ich es ein oder ausblende. Die verformende Animation wurde ebenfalls in Cinema 4D erstellt. Insgesamt wurde diese Szene mit allen Effekten 13-mal mit verschiedenen Einstellungen gerendert. So ähnlich hat es sich während des ganzen Videos durchgezogen.
    2 points
  14. Ist gut, wenn man von solchen Dingen eine vernünftig große Sammlung hat
    2 points
  15. Hab es gelöst bekommen. Das die Lösung ist, dass die Position als Parameter übergeben werden musste. Hier meine lösung: using System.Collections; using System.Collections.Generic; using UnityEngine; using Photon.Pun; public class WallPlacing : MonoBehaviourPunCallbacks { public GameObject wallPrefab; bool isInstantiated = false; PhotonView view; void Start() { //get the photon view component view = GetComponent<PhotonView>(); } // Update is called once per frame void Update() { if (view.IsMine) { if (Input.GetKeyDown(KeyCode.LeftControl)) { view.RPC(nameof(PlaceWall), RpcTarget.All, Camera.main.ScreenToWorldPoint(Input.mousePosition)); //view.RPC(nameof(RotateWall), RpcTarget.All ); } } } //place a wall at cursos pos [PunRPC] void PlaceWall(Vector3 position) { GameObject wall = PhotonNetwork.InstantiateRoomObject(wallPrefab.name, new Vector3(position.x, position.y, 0), Quaternion.identity); } [PunRPC] void RotateWall(GameObject wall) { var dir = Input.mousePosition - Camera.main.WorldToScreenPoint(wall.transform.position); var angle = Mathf.Atan2(dir.x, dir.y) * Mathf.Rad2Deg; wall.transform.rotation = Quaternion.AngleAxis(angle, Vector3.forward); } }
    2 points
  16. Hallo Community, heute möchte ich euch ein kleines Video zeigen. Es basiert auf meinem ersten Testlevel. Somit könnt ihr euch das schon mal in Bewegung ansehen.
    2 points
  17. Hallo Community, ich melde mich nach langer Zeit mal wieder zurück. Eine lange Zeit hatte ich keine Lust an einem Spieleprojekt zu arbeiten. Mein letztes Projekt war bezüglich des Umfangs und er Machbarkeit bezogen auf meine Person etwas überdimensioniert gewesen. Allerdings lässt mich der Drang etwas in dieser Richtung zu erstellen nicht los. Daher startete ich seit ein paar Tagen mit einem neuen Projekt. Diesmal soll es etwas sein was ich auch fertig bekommen möchte. In diesem Zusammenhang habe ich mir einen Klassiker ausgesucht. Ich erstelle einen Tower-Defence Clone. Einen Arbeitstitel habe ich noch nicht. Daher erhält es von mir vorerst die Bezeichnung „Tower“. Die erste Location habe ich bereits fertig. Jetzt geht es um die Spielbalance der Anzahl der Wellen, Gegner, Waffen etc. Hier ein paar Bilder vom ersten Level.
    2 points
  18. Moin Leute! Gestern wurden vermehrt Spamnachrichten versendet und auch heute versucht der Spammerbot sich weiterhin anzumelden und danach Nachrichten zu versenden. Wir sind an dem Problem dran! Momentan heißen alle Spammer Inda mit ner Zahl hinten dran. Solltet Ihr von einer IndaXX eine Nachricht bekommen haben, dann bitte löschen.
    2 points
  19. @Peanut Ja, wir könnten eigentlich schon beim Eingang der Foruen gleich einen Link zum Unity-Mutterforum setzen. Dann bräuchten wir hier nichts mehr schreiben. Wer will schon ein deutsches Forum haben. @Alessio Jeder Compressor verringert dir die Datenmenge, die im Spiel geladen und auch der Grafikkarte übergeben werden muss. Das ist der Vorteil und der Grund dabei. Eine Komprimierte Grafik zu nutzen, macht bei der Performance eigentlich nichts aus. Unity nutzt eh komprimierte Grafiken und Sounds intern. Bei der Meshkompression ist das so ähnlich. Da werden eigentlich nur die Dinge entfernt bzw. komprimieret, die nicht weiter nötig sind. Da ist z.B. der Punkt eine Meshes, der ganz genau angegeben werden kann, aber nicht muss. Fazit: Du wirst keine Performance-Einbußen bekommen. Du wirst aber bei den Grafiken unschöne Kompressionsartefakte oder Farbverwaschungen sehen.
    2 points
  20. Cool zu wissen! Hast du auch eine Frage? Ansonsten ein Schuss ins Blaue: Nutze dafür keinen Collider, sondern z.B. einen Raycast.
    2 points
  21. Moin, lösch mal in der if Abfrage das "int" vor randomNumbr.
    2 points
  22. Moin! Es kann sein, dass jetzt einiges kommt, was du schon weißt, aber ich fange einfach mal von vorne an. Nur zur Sicherheit... und wenn in Zukunft jemand UI-Probleme hat, kann ich einfach auf diesen Post verweisen Also... wenn er nicht auf "Constant Pixel Size" gestellt ist, sorgt der Canvas Scaler dafür, dass der Canvas immer einigermaßen™ gleich groß bleibt. Ansonsten nimmt er Höhe und Breite des Spielfensters an. Meine übliche Konfiguration ist "Scale with Screen Size", eingestellt auf "Match Width Or Height", weil ich meine Grafiken nicht gestreckt haben will. "Match" ist dann ganz nach rechts auf "Height" gezogen. Damit verhält sich der Canvas wie die normale Spielwelt: Die Höhe ist immer gleich, und wenn das Spiel relativ dazu breiter wird, dann nimmt die Kamera halt mehr auf. Siehe Bild rechts: Bei 4:3 werden halt einfach links und rechts Teile abgeschnitten, aber die Höhe bleibt konstant. Daraus ergibt sich jetzt aber leider, dass sich das UI ändern muss, wenn sich das Seitenverhältnis ändert. Ich nehme an, genau davor sitzt du gerade. Hier gibt es leider keine simple Einstellung, die das Problem löst. Das liegt daran, dass der Computer unmöglich raten kann, was gut aussieht. Schauen wir uns einfach mal Diablo 3 an: Hier haben wir die Questanzeige links, eine Minimap rechts oben und das Skillmenü samt Lebensanzeige usw. unten mittig. Dazu noch zwei kleine Knöpfe unten rechts. Das Skillmenü wird sicherlich unten zentriert bleiben und nicht skalieren. Wird der Bildschirm breiter, bleiben links und rechts einfach mehr Platz. Das Questmenü hat auch eine feste Breite, würde aber im Zweifelsfall sicherlich in der Höhe mitgehen. Ich denke, Questmenü füllt immer die gesamte Höhe aus, minus der Höhe des Skillmenüs. Die Minimap ist einfach oben rechts verankert und verändert seine relative Größe nicht. Wird der Bildschirm breiter, bleibt die Minimap einfach an der rechten Seite kleben und geht mit. Was ich gerade als Text formuliert habe, kannst du Unity mitgeben, und dann passiert genau so ein verhalten. Dafür musst du dir die RectTransform-Komponente deiner UI-Elemente genauer ansehen. Genauer das Menü, das aufgeht, wenn du oben links auf das quadratische Symbol klickst: Hierbei handelt es sich um den "Anker" (Anchor). Es ist dieselbe Einstellung, die du in Form von 4 Zahlen siehst, wenn du "Anchor" aufklappst. Allerdings ist es viel intuitiver, mit diesem Popup zu arbeiten, und die genauen Zahlenwerte brauchst du eigentlich so gut wie nie. Dein UI-Element lässt sich also in eine dieser 16 Kategorien einsortierten. Für jeweils die Höhe und die Breite kannst du abgeben, ob auf dieser Achse zentriert werden soll, an eine der jeweiligen beiden Kanten angeklebt werden oder gestreckt werden soll. Wählst du eine neue Kategorie aus, ändern sich auch die Beschriftungen der Eingabefelder rechts davon in der RectTransform-Komponente. Ein zentriert verankertes Objekt wie im Bild hat z.B. Position, Höhe und Breite. Ein Objekt, das vertikal gestreckt wird, keine vertikale Position oder Höhe mehr, sondern stattdessen jeweils den Abstand nach oben und unten. Die Questanzeige wäre also ein Kandidat für ganz unten links (vertikal gestreckt, horizontal linksbündig). Der Abstand nach unten würe dann die Höhe des Skillmenüs. Das Skillmenü selbst wäre vermutlich bottom center. Die Minimap top right. Neben dem Anker kann man sich den Pivot-Punkt nochmal ansehen, der in manchen Situationen besser nicht mittig gesetzt sein sollte. Dafür kann man die Werte der "Pivot"-Einstellung anfassen oder im Anker-Popup mal Shift gedrückt halten. Aber das führt hier eventuell ein bisschen zu weit. Wenn du jetzt zur Laufzeit Objekte erzeugst, dann musst du weiterhin mit diesen Dingen arbeiten. So nimmt man nicht die position-Eigenschaft, sondern anchoredPosition, wenn man die Position setzen will. Für die Größe des Objekte nicht localScale benutzen, sondern SetSizeWithCurrentAnchors. Von deinem Prefab sollten Anker und Pivot im Vorfeld richtig eingestellt sein. Und dann kommen da noch die Layout-Komponenten. Wenn du z.B. eine Liste von Dingen hast (und da könnten auch die Knöpfe im Skillmenü in Diablo zuzählen!), dann bietet es sich an, eine LayoutGroup zu benutzen. Wenn du da dann Objekte reinspawnst (also am besten bei Instantiate direkt die LayoutGroup als Parent mitgibst), dann sorgt so eine Komponente dafür, dass Dinge richtig angeordnet werden. Wenn dir als das nichts hilft, poste doch einfach ein paar Screenshots, vielleicht liegt das Problem ja ganz woanders
    2 points
  23. Mit deiner Methode würde ich die Beiden Collider Tagen und mithilfe von CompareTag() in einer If abfragen welcher Collider nun getroffen wurde. Aber das ruft einige Probleme auf . Zum Beispiel was passiert wenn dein Spieler beide Collider trifft usw. Ich würde anders an die Sache rangehen. Unzwar nachdem dein Spieler mit dem Gegner collidiert ist würde ich einen Richtungsvektor zwischen Gegner und Spieler berechnen und diesen normaliesieren. Und je nachdem welche Werte dieser hat weißt du ob der Spieler über dem Gegner war oder nicht. Hoffe ich konnte helfen
    2 points
  24. Für die 3 Likes gibt es eine gerenderte Variante von dem Raumschiff.
    2 points
  25. Du meinst ein Script, das die Bewegung des Objekts direkt kontrolliert? Ich kaufe ein Z und löse: Der Autor dieses Controllers hat sich halt keine Sekunde lang um Physic Materials geschert
    2 points
  26. Ja, ist schon eine sehr mehrschichtige Frage. Zum einen das Thema, das @Thariel beantwortet: Welches Format wird genutzt? PlayerPrefs, eine Datei (Xml, Json, Yaml, ...?) oder vielleicht doch eine Datenbank (Sql oder was anderes)? Die Daten können auch auf einem Server verwaltet werden, aber ich nehme an, du möchtest lokal auf dem Rechner des Spielers speichern. Dann wäre da die Frage nach dem Inhalt des Spielstandes. Diese Frage hat direkt Einfluss darauf, welches Format sinnvoll ist. Wenn du einfach ein paar Zahlenwerte hättest (welches Level ist fregespielt, wieviele Münzen/Leben hat der Spieler), dann wäre PlayerPrefs auf jeden Fall unproblematisch. Je komplexer es wird, desto unpraktischer werden sie, auch wenn sie theoretisch alles könnten. XML-Dateien sind etwas... "schwerfällig" und werden schnell groß, weil da so viel Zeug drinsteht, was nicht direkt deine Daten sind. Dafür versteht .NET ohne weitere Pakete sofort, wie die Dinger funktionieren (siehe @Thariels Link). Für Json müsstest du dir schon eine Json-Bibliothek besorgen. Gibt's aber ein paar für, Json ist sehr verbreitet und wird von Unity-Devs gerne genutzt. Unity versteht Json sogar (JsonUtility), aber das ist so lala im Handling, wenn du mich fragst. Es macht auch in der Implementation einen spürbaren Unterschied, ob du einfach konstant X Sachen speicherst oder nicht. So als Beispiel die VR-Spiele von Owlchemy Labs; Job Simulator oder Virtual Rick-ality. Die speichern nicht wirklich viel, sondern nur in welchem Level du bist. Da gibt's aber halt soundso viele Objekte, und von denen könnte man einfach die Positionen speichern und fertig. Beim Spielstart besorgt sich jedes dynamische Objekt in der Szene seine Position aus dem Savegame und gut ist. In einem Spiel wie Skyrim dagegen kommen Objekte hinzu oder werden gelöscht. Da brauchst du dann ein anderes System, das eine variable Anzahl von Objekten beliebiger Art speichern und laden kann. Es muss also alle deine Prefabs kennen, von denen Instanzen geladen werden können, und diese dann spawnen. Wie deine Implementation aussieht, hat aber keinen Einfluss darauf, welchen Dateitypen du nehmen solltest. Xml, Json, Yaml... die speichern alle dasselbe ab, nur in unterschiedlicher Syntax. Ist ein bisschen, als ob du dich entscheidest, ob du deine Notizen auf deutsch oder englisch aufschreibst. Sobald du dir einmal für alle diese Fragen eine Antwort ausgesucht und bewusst gemacht hast, werden alle weiteren Schritte einfacher.
    2 points
  27. Moin! Also... ich fang mal recht weit vorne an, ich glaube das hilft. Wenn du so etwas schreibst: void Blub(zeug) { kram } dann nennt man das eine Methode. Das ist ein Stück Code, das ausgeführt werden kann. Wenn man "Blub" aufruft, dann passiert "kram". (Statt "void" kann da auch was anderes stehen, ist aber hier erstmal nicht wichtig.) "zeug", also das, was in den runden Klammern steht, nennt man Parameter. Damit bestimmt man, wie "kram" passieren soll. Wenn du zum Beispiel eine Methode schreibst, die "Losgehen" heißt und das auch tun soll, dann ergibt es vielleicht Sinn, mit einem Parameter zu definieren, wohin das Objekt losgehen soll. Aber vielleicht weiß das Objekt das ja schon vorher und wartet nur noch auf das Startkommando - dann braucht die Methode keinen Parameter. Wenn eine Methode einen oder mehrere Parameter hat, dann kann man sie nicht aufrufen, ohne für jeden Parameter einen Wert zu übergeben (lassen wir für's erste so stehen... ). Wenn du z.B. die Methode "transform.Translate" aufrufst, dann musst du beim Aufruf in die Klammern schreiben, in welche Richtung sich das Objekt bewegen soll: transform.Translate(Vector3.up); Irgendwo in Unity drin ist diese Methode definiert, und das sieht dann wieder so aus wie oben: void Translate(Vector3 direction) { kram } (Sieht in Wirklichkeit ein bisschen anders aus, aber das ist gerade nicht so wichtig.) Und jetzt macht Unity halt irgendeinen "kram". Dabei benutzt es den Wert, den du beim Aufruf in die Klammern geschrieben ("übergeben") hast (Vector3.up), sodass du dich nach oben bewegst und nicht irgendwo anders hin. Wenn du jetzt OnTriggerEnter2D als Methodennamen hast, dann ruft Unity diese Methode magisch für dich auf, wenn eben ein anderer Collider mit diesem Collider in Berührung kommt und einer davon ein Trigger ist. Jetzt ist es Unitys Aufgabe, da einen Wert zu übergeben. Und Unity übergibt da den Collider, mit dem dieses Objekt in Berührung gekommen ist. Also "den anderen" Collider zum Beispiel. Und du kannst jetzt entscheiden, was du mit dieser Information anfängst. Du kannst zum Beispiel ganz simpel in die Konsole schreiben, wen du da berührt hast: void OnTriggerEnter2D(Collider2D collider) { Debug.Log(collider.gameObject.name + " hat mich berührt!"); } Bemerke, dass da "Collider2D collider" steht. Ein Parameter ist immer wie eine Variable definiert, heißt: Typ name Der Typ bestimmt, was für eine Art von Wert hier übergeben werden kann (z.B. ein Vector3 wie bei Transform.Translate), aber hier ist es eben ein Collider2D. Normalerweise bist du beim Schreiben einer Methode der Chef und kannst da reinschreiben, was auch immer du meinst, was die Methode braucht, um richtig arbeiten zu können. Wenn du aber hier etwas anderes als "Collider2D" schreibst, dann weint Unity aufgrund von Problemen mit der Magie, die ich eben meinte. "collider" ist hier ein beliebiger Name. Da kannst du auch "other" oder "otherCollider" oder "wurstbrot" hinschreiben. Wie du magst. Am Ende definierst du hier einfach einen Variablennamen, damit du im Rumpf der Methode (also dem "kram") beschreiben kannst, wovon du gerade redest. Hier zum Beispiel benutze ich collider.gameObject.name, also den Namen des GameObjects, zu dem der Collider2D gehört, und lasse ihn mit Debug.Log in der Konsole ausgeben. (Wieder ein Parameter hier, der in die Klammern kommt!) Hieße der Parameter anders, müsste ich halt wurstbrot.gameObject.name schreiben. Jetzt kannst du mit einer if-Abfrage dein Objekt identifizieren. Für den Anfang, aber wirklich nur für den Anfang, kannst du da Tags oder Namen benutzen und die abgleichen. Das würde ich auf Dauer keinesfalls empfehlen, aber die Gründe dafür führen hier zu weit. Du kannst z.B. einem Objekt oben im Inspektor den Tag "Player" geben: Und dann in deinem Code sowas schreiben: void OnTriggerEnter2D(Collider2D collider) { if (collider.gameObject.CompareTag("Player")) { Debug.Log("Der Player hat mich berührt!"); } } Du kannst dem Collider2D auch sagen, dass er Dinge tun soll. Du kannst z.B. sein GameObject zerstören: void OnTriggerEnter2D(Collider2D collider) { if (collider.gameObject.CompareTag("Player")) { Destroy(collider.gameObject); } } Wenn jetzt der Player in diesen Trigger läuft, dann wird er sofort zerstört. Alle anderen Objekte werden nicht betroffen.
    2 points
  28. Hallo, mir ist heute ein etwas älteres Projekt in die Hände gefallen mit dem ich mich letzten Sommer etwas beschäftigt habe. Es handelt sich um ein FPS-Projekt. Ich hatte schon vor einiger zeit hier im Forum mein Projekt „Die Zone“ vorgestellt. Das hatte ich mit der Leadwerks-Engine versucht umzusetzen. Allerdings hat mir die gesamte Engine, das Handling und letztendlich das Ergebnis nicht sonderlich gut gefallen. Daher wurde das Projekt mit dieser Engine nicht weitergeführt. Allerdings wollte ich die Idee nicht verfallen lassen. Daher habe ich das Projekt, wie oben bereits erwähnt, letzten Sommer mit Unity wieder aufleben lassen. Das Projekt die Zone spielt in der Gegenwart. Es gab also einen Reaktorunfall, der ein Areal nuklear verseucht hat. In dieser Region herrscht Chaos und es ist unbewohnbar geworden. Selbstverständlich kriecht auch eine Menge von mutierten Lebewesen in der Welt umher die jeden Eindringlich gerne aufessen möchten. Die Aufgabe des Protagonisten ist ebenfalls schnell erzählt. Damit die Verseuchung sich nicht noch mehr ausbreiten kann, muss der Reaktor abgeschaltet werden. Dafür werden aber diverse Schaltelemente benötigt. Diese wurden aber von den mutierten Wesen im gesamten Areal verteilt und müssen (natürlich von Protagonisten) eingesammelt werden. Dafür erhält der Spieler von der Zentrale entsprechende Aufträge. Des weiteren gibt es andere Fraktionen und Söldner, die in den verseuchten Gebieten ihr Unwesen treiben. Der Spieler wird nach und nach in die Story einbezogen und erfährt somit im Laufe der Zeit die gesamte Story. Ich stehe noch am Anfang und habe vom Gameplay noch nichts zum Vorstellen. Ich kann euch allerding schon mal ein paar Screenshoots der Militärbasis geben, die bereits von Söldnern besetzt ist. Etwas umherschießen kann auch schon.
    2 points
  29. Heute habe ich fünf weitere Regionen fertiggestellt. Somit sind es dann schon insgesamt acht von 21 Leveln. Hier die einzelnen neuen Regionen mit einem kleinen Screenshot. Hier der Link zum Download der Demo: http://www.pchobbyspieleschmiede.de/lara/lara_0.1.0.rar Region Goldhain: Region Hochberge: Region Kleintann: Region Tieffels: Region Unterfelde: Region Wolfsfelde:
    2 points
  30. Hallo, heute möchte euch ein kleines Video vom neuen Projekt zeigen. Um die ersten Ergebnisse mal vorzustellen, sollte ein unmoderiertes Video reichen. Zu sehen ist der Menü-Level, die Karte von Symira und die erste Spielwelt Silberhöhe. Im fertigen Spiel wird es natürlich eine größere Monsterwelle geben. Dies dient nur zur Demonstration. Nach Abschluss eines Monsterangriffs öffnet sich der „Laden“ für Upgrades.
    2 points
  31. Du kannst gerne Code einfügen, indem du beim Betrag-Schreiben über dem Text auf den Code-Button drückst (<>, neben dem Unity-Symbol) und da den Code einfügst PlayerPrefs.Get...-Methoden geben meines Wissens nach alle einen Default-Wert zurück, wenn kein gespeicherter Wert gefunden wird. Und wenn dem nicht so sein sollte, werfen die Dinger keine NullReferenceException. NullReferenceExceptions treten ja allermeistens dann auf, wenn vor einem Punkt ein Ausdruck steht, der zu null evaluiert (z.B. eine Variable, dessen Wert null ist, oder eine Methode, die null zurück gibt). Schauen wir also mal in deinen Code... da gibt es: PlayerPrefs.GetInt CoinsText.text Coins.ToString SceneManager.GetActiveScene() SceneManager.GetActiveScene().buildIndex LevelText.text NumberOfThisScene.ToString Debug.Log SceneManager.LoadScene Playerprefs, SceneManager und Debug sind Klassen, die können also nicht null sein. Bleiben nur noch: CoinsText.text Coins.ToString SceneManager.GetActiveScene().buildIndex LevelText.text NumberOfThisScene.ToString Wenn eine Exception fliegt, läuft die Methode nicht zuende. Wenn die Exception nicht gefangen wird, bevor sie zurück zu Unity kommt (z.B. Unity ruft Start auf, Start ruft X auf, Exception fliegt, Exception wird zurück zu Start gereicht, Exception wird zurück zu Unity gereicht), dann deaktiviert Unity das Script. Dein Button kann allerdings wunderbar Methoden auf deaktivierten Scripts aufrufen. Wenn also Start abbricht, dann ist danach irgendetwas falsch/gar nicht initialisiert. CoinsText kann theoretisch null sein, aber warum sollte es das nur im Build sein? Halte ich für unwahrscheinlich. es sei denn, du hast den EditorOnly-Tag benutzt. Coins kann nicht null sein - ist ein int. SceneMananger.GetActiveScene() kann nicht null zurückgeben, weil Scene ein Struct ist. LevelText kann null sein, aber wieder: Warum nur im Build? NumberOfThisScene kann auch nicht null sein, ist auch ein int. Kommt also alles nicht so richtig hin. Schau dir bitte mal in der Build-Konsole an, in welchem Script in welcher Zeile der Fehler auftritt.
    2 points
  32. Nachdem das erste Szenarium weitestgehend fertiggestellt ist geht es heute an die zweite Spielwelt. Diesmal wird es nicht darum gehen Türme zu bauen. Vielmehr sind die Türme bereits fertig aufgebaut. Der Spieler muss jetzt die Gegnerwellen geschickt durch die Turmplattformen leiten damit sie den größtmöglichen Schaden erhalten und so zerstört werden. Hier ein paar Bilder vom neuen Level.
    2 points
  33. Das machst du bei den Importeinstellungen. Nicht im Debugmodus. Schau mal hier: https://docs.unity3d.com/Manual/GenericAnimations.html
    2 points
  34. Ob du jetzt deine bools überall verteilt oder alle auf einem Haufen hast, ändert ja an der Anzahl nichts. Das einzige, was sich ändert, ist dass die Daten plötzlich nicht mehr an der Stelle des Programms sitzen, wo sie relevant sind, sondern irgendwo anders. Von daher sind Werte auf den Kisten selbst schon ganz wünschenswert. ScrtipableObjects sind für viele irgendwie schwierig initial zu greifen. Du bist da nicht alleine. Ich versuch's mal so auszudrücken: Mit Komponenten kann man ja eine Menge cooler Sachen machen. Man kann welche im Editor erstellen und dann lauter Werte einstellen, damit man ein Ding hat, das genau so ist, wie man es haben will. Komponenten müssen aber auf GameObjects sitzen, und GameObjects wollen in einer Szene sein. Gibt natürlich auch Prefabs, aber die sind halt dafür da, dass man davon mit Instantiate Instanzen erzeugt, die dann in eine Szene geschmissen werden. Komponenten haben deshalb auch etwas Zeugt dabei, wie z.B. die .gameObject-Eigenschaft oder GetComponent, um andere Komponenten auf demselben GameObject zu finden. ScriptableObjects erlauben dir ebenfalls, Dinge zu bauen und Einstellungen vorzunehmen. Dabei haben sie aber den ganzen Ballast nicht. Sie müssen nicht auf ein GameObject und wollen dadurch auch nicht unbedingt in einer Szene sein (können aber). Dadurch kannst du z.B. welche erzeugen und in deine Assets packen. Es sind damit einfach nur Objekte, die im Editor erstellt und eingestellt werden können, und die genau wie Komponenten über Drag and Drop in den Inspektor gezogen werden können. Typisches Beispiel für ScriptableObject-Anwendung ist ein Inventar. Du hast eine ScriptableObject-Klasse "Item" und kannst davon beliebig viele in deine Assets erzeugen. Jedes Item hat einfach nur einen Namen, ein Bild, einen Geldwert, was auch immer du willst. Was es nicht hat, sind Referenzen oder Methoden die irgendwas mit GameObjects oder Nachbarkomponenten zu tun haben. Sie sind einfach nur da. Letztenendes ist die häufigste Anwendung, sich damit eine Art Datenbank für statische Daten (wie "alle Items, die es im Spiel gibt" oder "eine Sammlung von KI-Verhaltensmustern") zu bauen. Was ScriptableObjects dir nicht geben, sind irgendwelche Vorteile in Sachen Savegame. Das denken initial auch viele, aber ScriptableObjects besitzen null Funktionalität, um irgendetwas zu speichern, was der Spieler macht. Aber wie gesagt, das wäre so meine Variante - ist nicht die einzig sinnvolle. ❤️
    2 points
  35. Hallo an alle, Ich wünsche uns für 2021 ...dass Corona wieder ein Bier ist ...dass Positiv wieder etwas Positives ist ...dass Tests wieder in der Schule stattfinden ...dass Isolieren wieder für Häuser und Kabel gilt ...dass man mit einer Maske Karneval feiern kann ...und dass Donald wieder eine Ente ist (Quelle Unbekannt) In diesem Sinne ein gutes Neues Jahr. Gruß Jog
    2 points
  36. joar das ist das typische Problem das du hier wie ein Mensch denkst (in einem 3D raum). Das ist aber nicht der Weg wie computer so etwas lösen. Im speicher liegt im prinzip alles kreuz und qure verteilt und wenn du so etwas wie ein grid haben willst ist das quasi nichts anderes als eine liste mit speicheradressen zu diesem objekt. Ein GameObject hat viele eigenschaften wie z.B. die position. Kennst du die Referenz zu dem Objekt kannst du auch die Position abfragen. Das ist das was Sascha meinte. Was du machen willst ist zum beispiel die IDs und die gameObjects in einem Dictionary ablegen Dictionary<int, GameObject> gameObjectDictionary = new Dictionary<int, GameObject>(); // dann kannst du beim erstellen alle GameObjects z.B. So adden gameObjectDictionary[ID] = myGameObject; // und wenn du dann dein GameObject wieder finden willst machst du GameObject myGameObject = gameObjectDictionary[ID];
    2 points
  37. Moin! Mach dir da mal keine Sorgen. Ich bin bei weitem nicht der einzige, der eine vernünftige Problembeschreibung einem Zweizeiler vorzieht, bei dem man noch 70% durch Raten rausfinden muss, bevor man weiß, was eigentlich los ist Also... AddForce ist in der Tat in Weltkoordinaten. AddRelativeForce ist im lokalen Raum. Heißt: Wenn du dein Objekt so ausrichtest, dass die Nase nach oben zeigt und dann AddRelativeForce mit Vorwärts-Vektor benutzt, dann fliegt das Objekt nach "vorne" aus der eigenen Sicht - also nach oben. Du könntest also dein Objekt irgendwie ausrichten und dann einfach AddRelativeForce nach vorne machen. Du kannst aber auch ein bisschen Mathematik auf deinen Richtungsvektor draufschmeißen. Die wohl simpelste Methode wäre ein kleiner Vector2, der obendrauf gerechnet wird: var gunDirection = transform.right; // So als Beispiel - das wäre die Richtung, in die die Waffe gerade genau zielt var spread = Random.insideUnitCircle * 0.3f; bullet.AddForce((gunDirection + spread).normalized * force, ForceMode.Impulse); Sollte funktionieren, ist aber evtl. etwas schwer zu kontrollieren Durch die Verteilung der Zufallsvektoren innerhalb eines Kreises hast du eine wesentlich höhere Chance auf eine geringe Abweichung, und nach außen wird's weniger wahrscheinlich. Aber ist ja evtl. auch nicht so ganz schlecht. Die Skala dafür ist aber auch etwas komisch. Wenn du mit 0.6f multiplizierst anstatt mit 0.3f, dann hast du nicht doppelt so viel Streuung, sondern etwas weniger. Ist vielleicht nicht so intuitiv zu editieren. Du kannst auch eine Rotation bauen und diese draufmultiplizieren: var gunDirection = transform.right; // So als Beispiel - das wäre die Richtung, in die die Waffe gerade genau zielt var spread = Quaternion.Euler(Random.Range(-20, 20), 0, 0); bullet.AddForce(spred * gunDirection * force, ForceMode.Impulse); Hier kannst du schön intuitiv -20° bis +20° oder eben alles andere einstellen. Die Wahrscheinlichkeit ist für alle möglichen Winkel gleich hoch.
    2 points
  38. Ich verstehe zwar die Situation nur sehr wenig, aber das klingt, als wärst du an dem Punkt angelangt, wo "ich habe mit Unity programmieren gelernt" seine Nachteile mit sich bringt. Wenn du anfängst, irgendein Programm mit Java oder so zu schreiben, dann hast du erstmal keine Szene, in der du Objekte hast, die magisch geladen werden, sobald das Programm startet. Selbst bei einer Fenster-Anwendung, wo du heutzutage auch einfach klickibunti deine Knöpfe platzieren kannst, schmeißt du keine Datenhalter-Objekte auf deine UI-Elemente oder so. Dass, zumindest bei weniger komplexen Projekten, 95% deiner Klassen Komponenten sind, die du dann auf GameObjects ziehst, ist schon eine Besonderheit in der Software-Welt. Und man gewöhnt sich ein bisschen sehr daran Es kann, wenn ich deine Situation jetzt überhaupt richtig gesehen habe, sinnvoll sein, Unity mal links liegen zu lassen und mal etwas ganz anderes anzufassen. Java mit BlueJ ist super zum lernen imo, einfach mal Python (sind wieder ne neue Spachen, aber kann trotzdem helfen... oder gerade deswegen), oder halt eine Konsolen-/Fenster-Anwendung mit C#. Wie gesagt, ich blicke die Situation nicht so ganz... ich nenne einfach mal ein paar Dinge, die du so kannst. GameObjects in deiner Szene, die Komponenten haben, in denen Daten stehen. Das ist dann sinvoll, wenn die Daten auch Teil deiner Szene sein sollen. Welcher Schalter öffnet welche Tür? Welche Farbe hat das Licht? Wo spawnen Gegner? Wie viel Schaden macht dieser Bereich? ScriptableObject in den Assets. ScriptableObjects sind unheimlich wichtig, wenn die Projekte anfangen, etwas komplexer zu werden. Man kann auch andere Dinge damit tun, aber die wohl wichtigste Anwendung ist, dass man sie in die Assets erzeugen kann. Sie sind ganz normale Objekte mit serialisierbaren Feldern (also wie bei Komponenten, dass man die Werte im Editor einstellen kann und sie dann gemerkt werden), die in diesem Fall aber nicht in deiner Szene existieren, sondern außerhalb, so wie deine Sounds, 3D-Modelle und Texturen, die überall im Projekt verwendet werden können. Klassisches und imo sehr gutes Beispiel für ScriptableObjects sind Item-Arten in einem RPG. Denk z.B. an Pokémon. Du hast ein Inventar, das als eine Liste von Items daherkommt. Das Inventar soll in jeder Szene funktionieren, und die Items als Prefabs zu definieren wäre doof, weil du eigentlich keine GameObjects in der Szene haben willst, nur damit sie in der Liste auftauchen. Und die Transform-Komponente ist auch überflüssig. Also machst du einfach eine ScriptableObject-Klasse (hier hast du eine Vorlage) und schmeißt da deine Felder rein: Item-Name, Wert beim Verkaufen, Referenz auf ein Sprite, um es im UI anzuzeigen, vielleicht noch eine Beschreibung. Dann kannst du im Editor im Asset-Fenster Rechtsklicken, Create, und deine ScriptableObject-Klasse taucht da auf. Dann erstellt du da mehrere Items und kannst die in deine Szene ziehen, um sie zu referenzieren (so, wie du z.B. ein AudioClip auf deine AudioSource ziehst). Wenn du also z.B. eine Schatztruhe hast, kannst eine Schatztruhe-Komponente machen, die ein Item-Feld hat, wo du dann das Item reinziehst, was aus der Kiste rauskommen soll. In deinem Fall kannst du deine Genres als lauter ScriptableObjects machen, vielleicht noch eine weitere SO-Klasse, die eine Liste der Genres enthält, oder du packst gleich alle Genres direkt in die Liste (so wie es jetzt scheinbar ist). Die Entscheidung sollte danach gehen, ob du auf die Genres einzeln zugreifen willst. Auch hier müsstest du erstmal ein Feld in deinen Komponenten deklarieren, in das du dann ein SO reinziehen kannst. Diese Variante ist also dann sinnvoll, wenn du mehrere mögliche Objekte (z.B. Genre-Listen) haben willst und dann im Editor durch Reinziehen entscheiden kannst, welches davon deine Komponente benutzen soll. ScriptableObject sollte man so oder so mal ansehen, auch wenn das hier am Ende nicht die beste Lösung sein sollte. Stinknormale Objekte, die nix mit Unity ab Hut haben. Du kannst auch einfach Objekte erzeuge, ohne, dass der Editor die jemals zu Gesicht bekommt. Wenn du im Inspektor Dinge eintragen können willst, ist das natürlich eher weniger die richtige Variante. Wenn du Objekte hast, die zur Laufzeit generiert werden, wie z.B. eine Waffe in Borderlands mit den zufällig gewählten Eigenschaften, dann willst du dafür evtl. ScriptableObjects benutzen um die möglichen Parameter zu definieren (z.B. Waffe "Grüne Pistole", hat Schaden zwischen 3 und 5, kann eines von folgenden Visieren haben, etc.), aber der Waffendrop selbst wäre dann ein ganz normales Objekt, das du mit new erzeugst. Zusätzlich zu diesen Varianten muss man sich die Frage stellen, wo man überall Referenzen zu den Objekte aufbewahrt. Du kannst z.B. Objekte jeder dieser Varianten statisch referenzieren. Statisch (weiß nicht, ob du "static" schon verinnerlicht hast) bedeutet, dass der Ort fest innerhalb des Programms definiert ist. Wenn du also z.B. eine statische Variable in deine Klasse packst, dann ist es egal, wie viele Instanzen dieser Klasse du hast - die statische Variable existiert nur einmalig in der Klasse selbst. Während du bei nicht statischen Dingen immer angeben musst, von welchem der Instanzen jetzt die Rede ist (ist ja klar - du musst ja definieren, welches deiner Lichter jetzt rot werden soll), musst du das bei statischen Dingen nicht, und so entfällt der Arbeitsschritt, das Objekt irgendwie herauszusuchen (wie du es z.B. durch dein Feld machst, in das du deine Genres ziehst). Statische Dinge sind entsprechend nur dann sinnvoll, wenn du absolut sicher bist, dass du das Ding nur einmalig brauchst. Wenn du sicher bist, dass du nur exakt eine Genre-Datenbank brauchst, dann kannst du diese irgendwo statisch deponieren und von überall aus drauf zugreifen, ohne noch zusätzlich zu spezifizieren, wo das Ding überhaupt ist. Sieht dann z.B. so aus: // Die Klase selbst muss nicht statisch sein, aber es verhindert hier, dass wir Instanzen hiervon erstellen. // Wir wollen ja nur EINE Datenbank haben, und das ist hier die Klasse selbst. public static class GenreDatabase { public static Genredetails[] GenreList; } Damit kannst du jetzt von überall schreiben: foreach (var genre in GenreDatabase.GenreList) oder wie auch immer du mit dem Array arbeiten willst. Der Punkt ist: Du schreibst "Klassenname.Variablenname" und fertig. Die große Frage, und da wird jetzt halt einfach Fortgeschritten, ist: Wie bekommst du deine Daten in die statische Welt? Und da gibt's in Unity mehrere Varianten, aber leider einfach keine, die ich als optimal ansehen würde. Du kannst deine Genres z.B. alle im Code definieren: public static class GenreDatabase { public static Genredetails[] GenreList; [RuntimeInitializeOnLoadMethod] private static void Initialize() { GenreList = new Genredetails[] { new GenreDetails { genreName = "Foo", genreEXP = 10f, // ... }, new GenreDetails { //... }, // ... } } } Das Attribut RuntimeInitializeOnLoadMethod ist hervorragend. Es macht ganz simpel, dass diese Methode einmalig direkt am Anfang des Spiels ausgeführt wird, völlig egal, was für eine Szene du hast oder was da drinsteckt. (Nebenbei: Ein statischer Konstruktor ginge hier auch, aber mit dem Attribut ist man immer auf der sicheren Seite.) Ist natürlich irgendwie hässlich, solcherlei Daten hart im Code zu definieren. Weil Unitys neues Input-System das auch so macht, finde ich das auch ein bisschen käsig. Alternativ könnte man ein ScriptableObject mit allen Genres drin machen und das einmalig am Anfang laden in einem statischen Feld referenzieren. Dafür muss man halt irgendwie definieren, wo dieses SO überhaupt liegt. Dafür bietet sich Resources.Load an, auch wenn ich das Ding ja immer gerne vermeide. public static Genredetails[] GenreList; [RuntimeInitializeOnLoadMethod] private static void Initialize() { GenreList = Resources.Load<GenreListScriptableObject>("Name der Datei hier").GenreList; } Hier ist wieder das übliche Problem, dass wenn die SO-Datei irgendwie minimal anders heißt oder verschoben wird, erstmal der Code nicht mehr das tut, was er soll. Eine dritte Variante wäre, ein GameObject in einer Szene zu haben, das dasselbe macht, nur halt ohne Resources.Load, sondern indem man das SO da reinzieht. Da ist halt der Käse dran, dass der Code wieder nicht funktioniert, wenn man im Play Mode eine andere Szene startet und das Objekt da nicht da ist. So... das war jetzt ne Menge Text. Tut mir auch leid, dich damit so zu bombardieren, und vor allem, dass da nicht mal "die richtige" Lösung drin steckt. Aber Tatsache ist: Du bist mit dieser Frage ganz eindeutig aus dem Noobschutz-Areal draußen. Die Stützräder sind ab, das Tempolimit aufgehoben. Jetzt geht's ans Eingemachte! Da wird es leider immer häufiger vorkommen, dass du Vor- und Nachteile verschiedener Wege analysieren und verstehen musst, um dann einen Weg zu finden, der am wenigsten doof für dich ist. Und du wirst dich immer wieder schlecht entscheiden, die Konsequenzen oft erst Monate später bemerken und einen besseren Weg erst Jahre später entdecken. Willkommen im Club!
    2 points
  39. Wieder ist viel Zeit verstrichen, bis ich den nächsten Endgegner erstellt habe (nur Model, noch nicht programmiert). Level 3, Saturn: Die Flügel fahren erst später raus, sind also nicht von Anfang an zu sehen. Der lange Schwanz wird am Ende nach dem Player schlagen.
    2 points
  40. Achso, hab mich schon gewundert Das neuste Update (inzwischen 1.4.1) enthält das ModuleSettings-System. Die Erklärung dazu ist viel komplexer als das System selbst... Ich mache ja kein Geheimnis daraus, dass ich kein Freund von "...Manager"-Komponenten bin. Wenn du mich fragst, soll man eher versuchen, dass Objekte sich selbst (ansonsten untereinander) managen, anstatt dafür eine zusätzliche Instanz zu haben. Im Zweifelsfall auch mit statischen Feldern und Methoden in der eigenen Klasse. Geht aber auch nicht immer, manchmal muss einfach ein Service Provider her. Aber auch der sollte nicht Leute dazu zwingen, ihn in eine Szene einzufügen oder sowas. Grundregel bei mir ist: Wenn du eine neue Szene erstellst, sollte es keine Checkliste von Dingen geben, die du erfüllen musst, damit dein Code funktioniert. Du willst eine Spielfigur haben? Zieh dein Prefab in die Szene. Du willst, dass Input funktioniert? Dann solltest du dafür nichts extra tun müssen. Da gibt's halt zwei Probleme: MonoBehaviour-Events. Du willst in vielen Services auf z.B. Start, Update oder OnApplicationFocus reagieren können. Dafür empfehle ich einen kurzen Code mit [RuntimeInitializeOnLoadMethod]-Attribut, der ein GameObject erstellt, HideFlags drauf, DontDestroyOnLoad drauf, Worker-Komponente drauf, fertig. Die Komponente ruft dann Methoden in der statischen Service-Klasse auf. Serialisierte Felder. Viele Services wollen Referenzen auf AudioClips, Sprites usw., vor allem aber auf ScriptableObjects oder Prefabs haben. Jetzt kann man halt sowas machen wie eine Initialisierungs-Szene, in der alle wichtigen Systeme drin sind, DontDestroyOnLoad drauf, vielleicht noch ein bisschen Editor-Code, damit man den Play Mode in einer beliebigen Szene starten kann und die Init-Szene dann additiv geladen wird... geht schon. Da hat man dann einen Haufen Komponenten drin, die einen auf Pseudo-Singleton machen. Aber eine andere Regel von mir ist: Wenn du einen Klebezettel an etwas im Editor pappen musst, auf dem steht, dass man da bitte die Finger von lassen soll, sonst könnte was kaputt gehen... dann ist der Code nicht besonders gut. Ich will halt einfach den Editor für Game/Level/UI-Designer haben. Und ich will möglichst wenig Restriktionen für sie haben. Wenn ich in einem Team einen neuen Designer habe, dann soll so wenig wie möglich im Editor rumfliegen, worüber der Mensch Bescheid wissen muss. Also bleibt der technische Kram schön im Code und der Design-Kram schön im Editor. Und damit kommt das neue ModuleSettings-System ins Spiel. Du baust eine statische Service-Klasse und dazu eine Settings-Klasse: using UnityEngine; using ThirteenPixels.Soda.ModuleSettings; internal class InputSystemSettings : ModuleSettings { protected override string title => "My Input System"; // This is optional. public Sprite gamepadIcon; } Mehr musst du nicht machen, dann kümmert sich das System um eine Instanz, die in den ProjectSettings liegt statt in den Assets. Sie taucht dann im Project Settings-Fenster auf: Dort kannst du alles mögliche zuweisen. In deiner statischen Service-Klasse musst du die Settings dann nur noch so laden: ModuleSettings.Get<InputSystemSettings>(); und schon hast du die Daten zur Laufzeit! Bei mir im Projekt kann ich halt einfach eine Szene anfangen und abgesehen von so Unity-Dingen (wie das EventSystem-GameObject...) gibt's da exakt nichts einzurichten. Ich tu das rein, was ich in der Szene vom Design-Standpunkt aus haben will und lasse alles weg, was ich nicht brauche. Verpflichtendes Setup, damit die Systeme funktionieren? Gibt's nicht. Entsprechend einfach ist halt auch Testing. Kurz mal nen Spieler und zwei Boxen in die Szene, schauen ob das mit dem Springen klappt, fertig.
    1 point
  41. Dazu sei gesagt, dass sich dieser Satz auf Iteratoren bezeichnet. Die foreach-Schleife benutzt einen solchen Iterator. Eine for-Schleife tut das nicht. Du kannst also statt deiner foreach-Schleife eine for-Schleife benutzen und dann gemächlich mit [i] auf die Listenelemente zugreifen. Wenn die Objekte sich in DestroyMe selbst aus der Liste austragen (wovon ich ausgehe), dann kannst du einfach i runter statt hochzählen, dann musst du da auch nicht zu doll auf den Index aufpassen. Es sei außerdem gesagt, dass das Zerstören eines Objekts keinen Einfluss auf irgendeine Liste hat, in der sich das Objekt befindet. Dass du diese Exception kriegst, passiert nur, weil du in DestroyMe, OnDestroy oder OnDisable irgendwo stehen hast, dass sich das Objekt von der Liste abmeldet.
    1 point
  42. 1 point
  43. ...er lebt noch... und hier mal ein Lebenszeichen:
    1 point
  44. Ich vermute stark, dass dein Raycast (oder was auch immer du als Ground Check benutzt) den Trigger trifft und du deshalb als Grounded zählst, bis du den Trigger verlassen hast. Du springst also in jedem Frame ein bisschen weiter.
    1 point
  45. Vermutlich! Dann halt var direction = 0f; if (Input.GetKey(KeyCode.A)) { direction -= 6; } if (Input.GetKey(KeyCode.D)) { direction += 6; } rb2D.velocity = new Vector2(direction, 0);
    1 point
  46. Hallo Ich kann nur sehr dringend empfehlen, Rechnung und Vergleiche bei Zeit immer mit einer fertigen Lösung zu machen. (DateTime) Man muss sehr genau sein und es gint einige Fallstricke. Es lohnt meist null, das alles selber zu machen. Christoph
    1 point
  47. Ne, das geht meines Wissens nach mit Onboard-Mitteln nicht. Letztenendes hast du aber einen Punkt, an dem der AudioListener liegt und kannst den mit der Position und Ausrichtung der AudioSource abgleichen. Wenn du also deiner AudioSource ein Script gibst, das etwa so anfängt...: [RequireComponent(typeof(AudioSource))] public class AudioSourceCubeVolume : MonoBehaviour { private AudioSource audioSource; [SerializeField] private Bounds bounds = default; private void Awake() { audioSource = GetComponent<AudioSource>(); audioSource.spatialBlend = 0f; } private void LateUpdate() { var listenerPosition = AudioListenerSingleton.instance.position; var relativeListenerPosition = transform.InverseTransformPoint(listenerPosition); audioSource.volume = CalculateVolume(relativeListenerPosition); } private float CalculateVolume(Vector3 relativeOffset) { // ... } private void OnDrawGizmosSelected() { Gizmos.matrix = transform.localToWorldMatrix; Gizmos.DrawWireCube(bounds.center, bounds.size); } } localToWorldMatrix und InverseTransformPoint sollten richtig sein, hab's aber nicht geprüft. Wenn ich mich da geirrt habe, einfach jeweils das Inverse nehmen. AudioListenerSingleton ist eine Komponente, die auf dem AudioListener sitzt und seine Position bereitstellt. CalculateVolume kriegt jetzt einen Vector3, der den relativen Offset zu den Bounds darstellt. Wenn das ganze von z.B. oben so aussieht: Dann ist es irgendwie schwer, mit dem Vektor zu arbeiten, der durch die roten Striche dargestellt wird. Durch InverseTransformPoint wird der Vektor aber so transformiert, dass er relativ zu den transformierten Bounds ist: Jetzt sind die Komponenten des Vektors aligned mit der Box, sodass du einfach relativeOffset.x mit (bounds.center + bounds.extents).x vergleichen kannst. Und dasselbe für die anderen beiden Achsen. Was du dann damit in CalculateVolume machst, ist dir überlassen
    1 point
  48. Klar! Einfach bauen und importieren. Unity hat ja bei 3D-Modellen immer ausklappbare Assets, und da steckt, auch wenn da sonst nix sein sollte, immer das Mesh drin. Das kannst du direkt in einen MeshCollider reinziehen.
    1 point
  49. Ja, private sollte es auch nicht sein, aber mach's halt einfach mal public Würde ich auch sagen. Ich meine... dein Raycast sieht ja höchstwahrscheinlich so aus: if (Physics.Raycast( ... )) { blub.FireCollision(hit.gameObject); } Da wirfst du ja ganz eigenständig die Information weg, ob der Raycast überhaupt etwas getroffen hat. Das geht ja mit dem if unter und ist dann in FireCollision verloren gegangen. Du kannst einfach diese Stelle erweitern. Entweder, du erweiterst deine Methode, mit null umgehen zu können ("kein Objekt getroffen")... if (Physics.Raycast( ... )) { blub.FireCollision(hit.gameObject); } else { blub.FireCollision(null); } ...und dann muss FireCollision irgendwie so aussehen... internal void FireCollision(GameObject hitting) { // Hier Bedingung erweitern if (hitting && hitting.Equals(instruction1)) { // ... animator.enabled = true; } else { animator.enabled = false; } } ...oder du baust eine zweite Methode, die dann stattdessen aufgerufen wird: if (Physics.Raycast( ... )) { blub.FireCollision(hit.gameObject); } else { blub.StopCollision(); }
    1 point
  50. 1 point

Announcements

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

Weiterleitung zum Entwickler "daubit"



×
×
  • Create New...