Jump to content
Unity Insider Forum

Thariel

Members
  • Content Count

    452
  • Joined

  • Last visited

  • Days Won

    14

Everything posted by Thariel

  1. Achso, stimmt. Ich packe meine immer in den Streaming Assets Ordner, damit sie offen liegen
  2. Doch, aber das ist ein grosser Vorteil. So kann die Community selbst Übersetzungen erstellen und das Spiel wird so modifizierbar. Du kannst auch viel einfacher Fehler korrigieren ohne gleich das Spiel neu zu builden (wie @MaZy oben erwähnt hat).
  3. Nunja, im Endeffekt macht sein script nichts anderes als einfach linear Text auszugeben. Da kann ich auch einfach ein Textfile erstellen und abwechselnd in einem Fenster anzeigen. Mein System kann verschiedene Positionen im Gespräch zwischenspeichern, Optionen nach Bedingungen anzeigen und ein völlig freier Gesprächsverlauf ausgeben. Ist nur mühsam das File zu schreiben. Wenn du mal dem Gesprächsverlauf folgst, dann siehst du, dass es ein ganzer Dialog mit einer Quest ist, die man abschliessen kann. Genau so könnte es auch in einem RPG wie Gothic ablaufen. In den nächsten Tagen wird das Tema für mich sehr aktuell, sobald ich die NPC AI fertig habe. Dann werde ich schauen, wie ich es diesmal angehen werde. Die Herausforderung ist vor allem: Die Gespräche laufen nicht linear ab, sondern in Schlaufen mit verschiedenen "Levels". Das geht fast nur mit einem Node-Basiertem System. Aber ich brauche die Dialoge eigentlich nur für die Intro Sequenz, deshalb werde ich da was einfaches bauen. Es gibt auch Dialog Editore. Vielleicht findest du ja einen guten und man könnte das exportierte XML File einfach in Unity interpretieren
  4. Thariel

    Fight!

    Ob ein Angriff statt findet, weiss das Enemy erst, wenn Schaden ausgeteilt wird. Der Spieler könnte sich ja kurz vor dem Hit noch wegdrehen. Aber du könntest auch ein "Kampfmodus" machen: Der Spieler wechselt in den Kampfmodus mit [TAB] und kann mit Maustasten angreifen. Andere Tiere erkennen von weitem, dass eine Bedrohung auftaucht. Der Spieler (ist ja ein Tier), bewegt sich vielleicht anders und knurrt bisschen. Der Vorteil ist, dass der Spieler wieder den Kampfmodus verlassen kann und die Maustasten kannst du dann für andere Aktionen brauchen wie Sammeln, Buddeln, Looten etc...
  5. Thariel

    Fight!

    Ich mache das immer mit Raycasts. Wenn ein Angriff gestartet wird, starte ich ein Timer, der den Schadens-Raycast genau dann startet, wenn die Hit Animation ihren Höhepunkt hat. Ich sorge immer dafür, dass die Angriffs-Animationen (First Person) immer direkt durch die Mitte des Bildschirms (Fadenkreuz) gehen und auch der Raycast geht einfach von der Kamera richtung Vector3.forward. Die glaube die Collider-Idee ist etwas umständlicher. Da musst du auf viel mehr achten. Beim Raycast machst einfach eine simple, Zeit verzögerte abfrage. Ich hab dann ein Damage-Interface gemacht. Wenn der Hit Collider ein GetCompont<IDamage>() hat, einfach Damage austeilen. PS: Da hat Sascha recht, meistens wird da von Anfänger völlig übertrieben mit "Realismus". Der Spieler erwartet kein echter Realismus und wirklich realistische Spiele wären total Langweilig.
  6. Jetzt hab ichs raus gefunden! Type[] arguments = prop.GetValue(obj).GetType().GetGenericArguments(); Type keyType = arguments[0]; Type valueType = arguments[1]; Type dictType = typeof(Dictionary<,>).MakeGenericType(keyType, valueType); var dict = Activator.CreateInstance(dictType);
  7. Bei mir hat das immer funktioniert. Ich schätze mal, dass etwas in deinem Script oder so nicht funktioniert. Ich rate dir mal ein ganz neues Projekt zu erstellen und es einfach zu testen. Hilfreich wäre es, wenn du etwas mehr Infos gibst, zum Beispiel bisschen Code. Lädst du kurz vorher die Szene neu?
  8. Hi Ich entwickle gerade eine Klasse, um beliebige Objekte in XML und wieder zurück zu konvertieren. Ist alles ziemlich schwierig 😮 Jetzt versuche ich gerade, aus dem XML das Dictionary "stats" wiederherzustellen. <?xml version="1.0" encoding="utf-8"?> <XmlTest> <health>10</health> <speed>3.5</speed> <isDeath>false</isDeath> <stats> <!--Dictionary--> <row> <key>strength</key> <value>5</value> </row> <row> <key>armor</key> <value>0</value> </row> </stats> </XmlTest> Das XElement "stats" übergebe ich also meiner Funktion: public static void GetDictionaryFromXElement(XElement elDictionary, object obj, PropertyInfo prop) { var dict = (IDictionary)Activator.CreateInstance(prop.GetType()); foreach (XElement elRow in elDictionary.Elements()) { object key; if (dict.Keys.GetType() == typeof(int)) { string sValue = elRow.Element("key").Value; int i = 0; int.TryParse(sValue, out i); key = i; } else Debug.LogError("Variable type not handled: " + prop.PropertyType); /// hier ein teil ausgeschnitten um das script kürzer zu halten dict.Add(key, value); } prop.SetValue(obj, dict); } Jetzt habe ich das Problem, dass dict.Keys.GetType() nicht den typ des "Keys" zurück gibt, sondern "System.Collections.Generic.Dictionary`2[System.String,System.String]". Trotz Suche habe nicht nicht herausgefunden, wie ich das Dictionary füllen kann, ohne vorher den Datentyp zu kennen. Ich müsste einfach den Datentyp des "Key" und des "Value" Wertes wissen, damit ich das ganze abarbeiten kann. Wer kann mir da helfen?
  9. Hi Ich kenne mich mit ScriptableObjects nicht aus, aber ich habe ein einfaches Dialog System entwickelt. Dazu habe ich einfach ein LUA File (XML würde auch gehen) verwendet. Darin habe ich verschiedene "Stages" definiert. Jede stage enthält entweder Informationen, was der Npc sagt oder Auswahlmöglichkeiten, die der Spieler Antworten kann. Die Variable "nextStage" gibt an, welche Stage als nächstes kommt (wieder NPC sagt was oder Spieler antwortet was). Dazu habe ich noch eine "requirements" Variable bei den Antwortmöglichkeiten gemacht. Die Antwort erscheint also nur, wenn der Spieler die "requirements" erfüllt... zum Beispiel ein bestimmter Gegenstand im Inventar hat. Ist leider ziemlich kompliziert die Datei zu schreiben. Wenn du ein System entwickeln willst, um die Dialoge auf komfortable Art zu designen, wäre ich sehr interessiert 🙂 So sieht so eine Datei aus: defineDialog { id = "sailorfrank", name = "Frank", startStageId = "s0", autoStartRadius = 0, stages = { s0 = { say = { speaker = "npc", text = "Warum nur immer ich?", audio = "", actions = nil, nextStage = "s1" }, options = nil }, s1 = { say = nil, options = { option1 = { text = "Was ist los?", requirements = nil, actions = nil, nextStage = "s2" }, option2 = { text = "Ich muss weiter.", requirements = nil, actions = nil, nextStage = "" } } }, s2 = { say = { speaker = "npc", text = "Jemand hat meine Schuhe geklaut! Gestern hatte ich sie noch.", audio = "", actions = nil, nextStage = "s3" }, options = nil }, s3 = { say = { speaker = "npc", text = "Es sind ganz normale Schiffsstiefel.", audio = "", actions = nil, nextStage = "s4" }, options = nil }, s4 = { say = nil, options = { option1 = { text = "Wenn ich sie sehe, werde ich bescheid geben.", requirements = nil, actions = { SetStage = "s6" }, nextStage = "s5" }, option2 = { text = "Viel Glück!", requirements = nil, actions = nil, nextStage = "" } } }, s5 = { say = { speaker = "npc", text = "Das wäre super!", audio = "", actions = nil, nextStage = "" }, options = nil }, s6 = { say = nil, options = { option1 = { text = "Wegen deinen Stiefeln...", requirements = nil, actions = nil, nextStage = "s7" }, option2 = { text = "Ich gehe jetzt.", requirements = nil, actions = nil, nextStage = "" } } }, s7 = { say = { speaker = "npc", text = "Ja?", audio = "", actions = nil, nextStage = "s8" }, options = nil }, s8 = { say = nil, options = { option1 = { text = "Ich habe sie gefunden. Hier sind sie.", requirements = { InventoryContainsItem = "BOOTS=1" }, actions = nil, nextStage = "s10" }, option2 = { text = "Noch nichts neues.", requirements = { InventoryNotContainsItem = "BOOTS=1" }, actions = nil, nextStage = "s9" } } }, s9 = { say = { speaker = "npc", text = "Dann such weiter, ok?", audio = "", actions = nil, nextStage = "s6" }, options = nil }, s10 = { say = { speaker = "npc", text = "Das war echt nett von dir! Vielen Dank!", audio = "", actions = { SetStage = "s11" }, nextStage = "" }, options = nil }, s11 = { say = { speaker = "npc", text = "Hey! Danke nochmals, dass du meine Stiefel gefunden hast!", audio = "", actions = nil, nextStage = "" }, options = nil } } }
  10. Indem du die Ausgabe formatierst. Zum Beispiel so: string datum = dateTime.ToString("dd.MM.yyyy"); Da gibt es sehr viele Möglichkeiten.
  11. Thariel

    Iso Cammera.

    Ich würde es so machen: using UnityEngine; using System.Collections; public class CameraController : MonoBehaviour { public Transform player; public float speed = 5.0F; public Vector3 offset = new Vector3(0, 5, 0); void Update () { transform.position = Vector3.Lerp(transform.position, player.transform.position, speed * Time.deltaTime) + offset; } } Jetzt das Script auf die Kamera legen und den Player auf den Slot ziehen. Jetzt verfolgt die Kamera den Player in einer flüssigen Bewegung.
  12. Kannst du nicht das Datum als DateTime speichern und erst in ein string umwandeln, wenn das gefordert wird? Dies hat dann viele Vorteile. Falls das Datum nur als string vorliegt, würde ich beim einlesen die strings in DateTime umwandeln.
  13. Ich würde pro Gebiet ein GameObject (Spawner) erstellen und alle Npcs unterordnen (als childs). Dann immer bei Mitternacht (falls du Tag/Nacht Zyklus hast) der Spawnvorgang starten. Du kannst einfach im Spawner mit transform.childCount die aktuell vorhandenen Tiere zählen. //alle 300 sekunden spawnen float spawnTimer = 300; void Update() { if(spawnTimer > 0) { spawnTimer -= Time.deltaTime; if(spawnTimer <= 0) { Spawn(); spawnTimer = 300; } } } int desiredAnimalCount = 20; void Spawn() { int left = desiredAnimalCount-transform.childCount; for(int i=0;i<left;i++) { //Instantiate } } Du könntest auch anstatt tote Tiere zu Destroy'en, sie nur deaktivieren. Und wenn der Spawnvorgang läuft, suchst du für die deaktivierten Tiere ein neuer Spawnpoint und belebst sie wieder.
  14. Wäre cool, wenn es eine Software gäbe um aus 3d Models, Artworks zu generieren! :)

  15. Cool, vielen Dank! Ich überlege mir noch, wie ich es dann genau löse 😃
  16. Also ich gehe davon aus, dass in Update() den Code der Reihe nach in allen Objekten ausgeführt wird und in "Internal physics update" Kollision und so weiter berechnet wird. https://docs.unity3d.com/Manual/ExecutionOrder.html
  17. Genau so mache ich das auch! Das Problem ist aber: 1. Frame: Beide NPC's warten darauf, dass das Feld frei wird. 2. Frame: Das Feld wird frei. 3. Frame: -> Npc 1 macht Raycast. Feld ist frei. Bewegt sein Collider auf das neue Feld (Physik wird aber erst im nächsten 4. Frame vor Update() ausgeführt). -> Npc 2 macht Raycast. Feld ist frei (Collider von Npc 1 noch nicht eingetroffen). Bewegt sein Collider auf das angeblich freie Feld. 4. Frame: Noch vor Update() werden die Collider bewegt, mit dem Ergebnis, dass jetzt beide auf dem selben Feld sind. So verstehe ich das zumindest... oder funktioniert es anders? 🤔
  18. Hi Ich habe folgendes Problem: Auf jedem Feld des Schachbrettartigen Spielfeldes darf immer nur ein Npc stehen. Wenn 2 Npc darauf warten, das selbe Feld zu betreten und das Feld frei wird, dann testen beide Npc's gleichzeitig im selben Frame mit einem Raycast, ob es frei ist. Es ist auch frei und beide ziehen auf das selbe Feld, doch jetzt stehen 2 Npc's auf dem selben Feld, weil die zwei Raycasts und die Bewegung der Collider jeweils Parallel ablaufen (Execution Order). Die Bewegung findet mit transform.Translate statt. Wie könnte ich das Problem lösen? Danke schon mal 😅
  19. Hi In meiner Map hab ich ein Fog of War, damit man nur Bereiche sieht, die der Spieler schon besucht hat. Dazu habe ich über die Map einfach eine Maske gelegt und ändere die Pixel an der Position vom Player. Aber nur, wenn der Spieler sich bewegt hat und das ganze befindet sich auch noch in einer Coroutine. Hab mir gedacht, dass dies sicher Preformant genug ist, doch ich habe starke Ruckler. Anscheinend ist SetPixels extrem langsam bei grossen Bilder, selbst wenn man nur ein kleiner Bereich ändert (64x64). Habe die Idee, ein echter eigener Prozess zu machen oder die zu ändernden Pixels in eine Datenbank zu schreiben, die dann einzeln abgearbeitet werden. Ist aber beides irgendwie Quatsch. Hat jemand eine gute Idee?
  20. Der Wert ist schon aktuell, es ist die direkte Position vom Player und diese siehst du auch auf der Karte (gelber Pfeil). Habe das Problem aber jetzt gelöst: Hab einfach das ganze umgebaut und verwende jetzt kein ScrollView mehr, sondern einfach ein Image mit Maske. Sieht jetzt immer noch alles genau gleich aus, aber kein ScrollView, das rein pfuscht. Danke
  21. Macht leider keinen Unterschied! Komisch ist auch, dass manchmal X korrekt aktualisiert wird und machnmal Y, aber nie beide auf Anhieb korrekt... Hast du noch eine andere Idee?
  22. Hi Ich hab in der Update() Funktion einfach ein SetActive() Toggle eingebaut: if(Input.GetKeyDown(KeyCode.M)) { goWindow.SetActive(!goWindow.activeInHierarchy); CmdCenterPlayer(); }
  23. Hi Wenn der Spieler die Karte öffnet, soll er immer schön zentriert sein. Dazu hab ich eine Funktion gemacht. Diese wird beim öffnen der Karte aufgerufen und ist auch über einen Schaltfläche aufrufbar. Jedoch funktioniert es nie auf Anhieb, sondern immer erst beim zweiten Versuch. Ich muss also die Karte 2x hintereinander öffnen, damit die Position korrekt gesetzt wird. Wie ihr seht ist bei der Position im RectTransform immer etwas merkwürdig, entweder bei X oder Y. Hab schon Canvas.ForceUpdateCanvases() und LayoutRebuilder.ForceRebuildLayoutImmediate() ausprobiert. public void CmdCenterPlayer() { float x = Mathf.Floor(PlayerController.singleton.transform.position.x / 4.0F); float y = Mathf.Floor(PlayerController.singleton.transform.position.z / 4.0F); rectContent.anchoredPosition = new Vector2(-x * 50, -y * 50); //50=map tile size } Wer weis warum das so ist? Solche unlogischen Dinge machen mich echt nervös! 😡 PS: Das ganze befindet sich in einem ScrollView und das GameObjekt im Inspector ist das Content-Objekt vom ScrollView.
  24. Hey! Eine komische Frage, was? Es geht um Patreon, eine Webseite um Spenden für sein Projekt zu sammeln und die Spender dafür zu belohnen. Ich frage mich, ob man einer limitierten Anzahl von Let's Players früheren Zugang zum Spiel geben könnte und nur diese das Spiel Streamen dürften. Sie hätten den Vorteil, dass sie exklusiven Content erstellen dürften und ihr Kanal damit wächst und würden dafür zu den Entwicklungskosten beitragen. Win-Win für beide. Aber könnte ich so ein exklusives Recht auf YT durchsetzen und Videos löschen lassen, die jemand hoch lädt, ohne dafür berechtigt zu sein?
×
×
  • Create New...