Jump to content
Unity Insider Forum

Sascha

Administrators
  • Content Count

    11,610
  • Joined

  • Last visited

  • Days Won

    579

Everything posted by Sascha

  1. Sascha

    Serialisierung

    Da hab ich was für dich: http://blog.13pixels.de/2019/an-intro-to-serialization-in-unity/ Kurz: Serialisierung heißt prinzipiell "Dinge in eine Reihe [Serie] packen". Da Dinge im Computer in der Basis immer eindimensional sind - seien es Daten auf der Festplatte oder Informationen in einem Netzwerkkabel - müssen komplexe Strukturen wie Objekthierarchien serialisiert werden, um in solche eindimensionale Dinge hineinzupassen. Aber... der Artikel ist da ein ganzes Stück genauer, auch im Unity-Kontext.
  2. Naja, Spielstände sind je nach Spiel unterschiedlich komplex. Das geht von supereinfachen Sachen wie einer einzelnen Zahl ("Bis zu welchem Level wurde freigespielt") über überschaubare Sachen ("Wieviele Sterne hat der Spieler jeweils in jedem Level Angry Birds") bis hin zu krassen Sachen wie einem Spielstand in Skyrim ("Welcher NPC lebt noch und was hält er vom Spieler, wo liegen was für Sachen herum, wie hat der Spieler seine Skillpunkte verteilt, welche Items besitzt er, ..."). PlayerPrefs sind supereinfach zu benutzen, um einzelne Werte abzuspeichern. Beispiel eins und zwei sind damit daher sehr gut zu machen. Komplexe Sachen wie Nummer drei dagegen - da hört der Spaß dann auf und du bist mit mächtigeren Systemen besser beraten. Was Manipulierbarkeit angeht... mach dir mal über Cheater erstmal keinen Kopf. Wer cheaten will, wird cheaten können. Absolute Sicherheit gibt es einfach nicht. Überlege dir daher: Wie schlimm ist es wirklich, wenn ein Spieler schummelt? Ich würde mir niemals den Stress machen, bei einem Singleplayer-Spiel Cheatschutz einzubauen. Soll doch jeder Spieler selbst für seinen Spielspaß verantwortlich sein. Da würde ich erst mit anfangen, wenn jemand anderen Spielern den Spaß verhageln kann. Und wie gesagt, wer cheaten will, wird cheaten. Auch wenn du selber eine Savegame-Datei anlegst, deren Inhalt krass verschlüsselt ist. Wo ein Wille ist, ist auch immer ein Hack. Selbst, wenn du dir die riesige (!) Arbeit machen solltest, ein halbwegs sicheres System zu bauen, ist das Savegame-System nur einer von vielen Angriffspunkten. Im Zweifelsfall kommt der Nutzer mit Low-Level Memory Access daher und dann kann dein Spielstand noch so gut verschlüsselt sein. Also... mach dir da keine Sorgen. Lohnt sich einfach nicht, da Energie reinzustecken.
  3. Du übergibst einen string "_stadtText" (warum auch immer der Parametername mit Unterstrich anfängt...) und machst damit nichts. Ich bin mir recht sicher, dass das so nicht richtig ist
  4. Wer auch immer das sagt, hat keine Ahnung. PlayerPrefs sind genau dafür da. Sie skalieren nicht sehr gut mit einem Projekt mit - du willst also keinen Skyrim-Spielstand über PlayerPrefs speichern - aber um ein Dutzend Bools abzuspeichern ist die Klasse perfekt und angenehm unkompliziert.
  5. Ja hallo, und das wolltest du uns jetzt erstmal vorenthalten oder was?
  6. Benutze mal bitte den <>-Knopf über dem Textfeld, und packe da deinen Code rein, dann kann man den sogar lesen Erstmal: Also, entweder die Variable ist vom Typ string, oder sie ist vom Typ UIText. Beides geht nicht. Bei diesem Code: if (TheTargets.ContainsKey(sceneName)) { stadtText = TheTargets[sceneName]; } kann dieser Fehler unmöglich™ auftreten. Leere einmal deine Konsole (nicht, dass das ein alter Fehler ist, der einfach immer noch in der Liste steht, obwohl er nicht mehr aktuell ist) und schaue danach, in welcher Zeile er wirklich auftritt.
  7. Hallöchen! Gibt's denn schon etwas Feines zu sehen?
  8. Okay, offenbar müssen wir da nochmal durch... Zuerst einmal... sceneName ist nicht dasselbe wie "sceneName" Das erste ist ein Variablenname, das zweite ein Literal. Beispiel: var wort = "Hund"; Debug.Log(wort); // Gibt "Hund" aus. Debug.Log("wort"); // Gibt "wort" aus. Wenn du also TheTargets.ContainsKey("sceneName") schreibst, dann suchst du nach "sceneName" und nicht nach dem String-Wert von der Variable sceneName, der in der Zeile davor gesetzt wird. Was ist Value ? Wo definierst du das? Du musst ja in die eckigen Klammern entweder ein Literal oder einen Variablennamen reinpacken. (Oder sonst irgendeinen Ausdruck, der zu einem Wert evaluiert, so wie du 2+2 statt 4 schreiben kannst). In diesem Fall willst du ja offenbar den Namen der Szene als Schlüssel benutzen und den passenden Wert finden. Also musst du auch TheTargets[sceneName] schreiben.
  9. Ein CharacterController ist nur ein Collider mit Move-Funktion. Das Ding kennt ja keine Geschwindigkeit und keine Kräfte, die ein Rigidbody darauf ausüben könnte. Du kannst mit OnCollisionEnter selbst auf Kollisionen reagieren und dann zum Beispiel den Geschwindigkeitsvektor in deinem Script verändern. Allerdings gibt's da noch eine Menge Dinge zu beachten; wie den kollidierenden Rigidbody - der verhält sich erstmal trotzdem, als hätte er eine unbewegliche Wand getroffen. Von daher ist es eine Überlegung wert, statt eines CCs einfach noch einen Rigidbody zu benutzen.
  10. Warum fragst du "sceneName" ab, steckst dann aber als Key "Value" da rein? Warum ist "sceneName" ein String-Literal? Da stimmen einfach ganz viele Basics nicht.
  11. Kannst einfach den speed-Wert jedes Mal erhöhen.
  12. Alter. N bisschen mehr als zweieinhalb Sekunden darfst du dir schon mit deinen Beiträgen Zeit nehmen. Kann doch keiner ahnen, was du hier gerade willst.
  13. Wenn du irgendwo was von "Methodengruppe" stehen hast, dann heißt das in 98% der Fälle, dass du eine Methode hingeschrieben hast, aber nicht aufrufst. Statt GetInstanceID einfach GetInstanceID() Ja, GetInstanceID ist für so ungefähr alles, was man als Benutzer so machen kann, völlig nutzlos. Wenn du die Szene neu lädst, kriegen alle Objekte eine neue Instance ID - sie ist nicht persistent. Wenn du Dinge in Savegames identifizieren willst, musst du dich selber um eine ID kümmern.
  14. Das ist einfach dein Vektor relativ zum Objekt, in deinem Fall also new Vector3(0, -0.5f, 1.1f)
  15. Das eine Script hat den ganzen Rotationskram drin, das andere ruft bei diesem Script nur die Methode in OnMouseDown auf.
  16. Na, dann kann ich ja zu schreiben aufhören @Kojote Geht auch so: var spawnPosition = transform.position + transform.TransformDirection(localOffset);
  17. @TurTur Tut mir leid, da jetzt so forsch daher zu kommen, aber deine gesamte Erklärung ist leider von vorne bis hinten falsch. Sie stimmt für typschwache Sprachen wie JavaScript oder PHP, aber C# funktioniert so nicht. @Luis Wie du schon richtig erkannt hast, geht das mit Unity-Objekten, aber nicht mit normalen. Das liegt in der Tat daran, dass die wichtigsten Unity-Klassen (GameObject, Component, ScriptableObject) alle von UnityEngine.Object erben, und diese Klasse wurde so geschrieben, dass man sie implizit zu boolean casten kann. Innerhalb dieses Casts, den Unity geschrieben hat, wird dann quasi "!= null" gemacht. "Quasi", weil Unity im Vergleichsoperator bei dieser Klasse auch herumgepfuscht hat, damit bei "meinObjekt != null" "true" heraus kommt, wenn das Objekt zerstört wurde. Das Ganze kann man selber auch nachbauen. Ich erweitere mal deinen Code von oben: class Person { public bool alive = true; public static implicit operator bool(Person p) { return p.alive; } } class Program { static void Main(string[] args) { Person p = null; p.alive = false; if (p) { Debug.Log("Alive!"); } else { Debug.Log("Dead!"); } } }
  18. Zu Occlusion Culling habe ich gerade nichts, aber: Frustum Culling macht Unity sowieso. Da brauchst du dich nicht drum zu kümmern.
  19. Man kann von jeder Komponente alle anderen Komponenten abfragen. Man kann auch von jeder Komponente das GameObject bekommen.
  20. Dachte ich mir schon, dass das eher das ist, was du willst Um einen Winkel zu würfeln, der vom vorherigen abhängig ist, kannst du entweder den aktuellen Winkel erfragen oder dir dein letztes Zufallsergebnis merken. Ich würde, auch wenn in einigen Fällen beides geht, sicherheitshalber immer Letzteres empfehlen. private float currentAngle = 0f; Wenn du dann 90° bis 270° davon weiter willst, einfach draufaddieren: currentAngle += Random.Range(90f, 270f); Damit du immer zwischen 0 und 360 bleibst, knallst du noch ein Mathf.Repeat drauf: currentAngle = Mathf.Repeat(currentAngle, 360f); Dann baust du dir damit dein targetRotation-Quaternion und arbeitest damit wie gehabt.
  21. Dann hast du noch alten Code mit drin, denke ich. Auf dem Pfeil oder auf einem Parent-Objekt des Pfeils. Der Code auf seinem letzten Stand enthält keine Änderung der Rotation abgesehen von der auf "targetRotation" zu. Ganz ehrlich... ich glaube nicht, dass das das ist, was du willst, aber probier's gerne mal aus: private bool lessThan180 = true; float angle; if (lessThan180) { angle = Random.Range(0f, 180f); } else { angle = Random.Range(180f, 360f); } targetRotation = Quaternion.Euler(0, 0, angle); lessThan180 = !lessThan180;
  22. Wenn du nur meinen Code oben benutzt, gibt es keinen unnötigen Reset.
  23. Also... das soll er nicht? Denn aktuell tut er das ja. Soll er immer nach oben flippen und von da aus auf die Zufallsposition drehen? In dem Fall baust du einfach an den Anfang der "Spin"-Methode noch ein transform.rotation = Quaternion.identity; Das wird ein bisschen komplizierter. Mit Vector3.Angle kannst du den Winkel zwischen zwei Richtungsvektoren herausfinden. Einer davon wäre vom Pfeil-Objekt "transform.up" (in der Hoffnung, dass dein Pfeil-Sprite nach oben zeigt). Der andere ist problematischer zu kriegen. Da müsstest du mit Methoden und Eigenschaften aus der Input-Klasse arbeiten - touchCount und GetTouch zum Beispiel. Damit findest du die Position deines Touches auf dem Bildschirm. Diesen musst du noch in eine Position in der Welt umrechnen. Camera.ScreenToWorldPoint sollte dir dabei helfen. Dann hast du die Position deines Touches relativ zur Welt. Diese ziehst du vom Mittelpunkt deines Pfeils bzw. deiner Scheibe ab und hast den Richtungsvektor deines Touches, den du dann mit dem anderen Vektor abgleichen kannst, um den Winkel zu kriegen.
  24. Da würde ich ein Script auf den Pfeil legen, das dreht, und das andere auf dem Collider löst das nur noch aus. Da das Drehverhalten eher zum Dreh-Script gehört als zum Auslöser, würde das da hinwandern. public ArrowRotation arrow; private void OnMouseDown() { arrow.Spin(); } Und hier wäre "ArrowRotation": private Quaternion targetRotation; public float speed = 20f; public void Spin() { var z = Random.Range(0f, 360f); targetRotation = Quaternion.Euler(0, 0, z); } private void Update() { transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, speed * Time.deltaTime); }
  25. Hi! Für den Touch sollte meines Wissens nach OnMouseDown immer noch funktionieren: private void OnMouseDown() { Debug.Log("Ich wurde gedrückt!"); } Wird ausgelöst, wenn du den Collider triffst - dein Kreis muss also mit einem CircleCollider2D gebaut sein, um zu definieren, wo man hindrücken kann. Auf das GameObject mit diesem Collider kommt dann das Script mit OnMouseDown. In OnMouseDown kannst du z.B. mit Random.Range deine Zufallsdrehung bauen: var z = Random.Range(0f, 360f); var rotation = Quaternion.Euler(0, 0, z); arrow.rotation = rotation; "arrow" kannst du dir als öffentliches (bzw. serialisiertes) Feld deklarieren: public Transform arrow; sodass du dein Pfeil-GameObject da im Inspektor reinziehen kannst. Das ganze Script (also der Inhalt der Klasse) sieht dann so aus: public Transform arrow; private void OnMouseDown() { var z = Random.Range(0f, 360f); var rotation = Quaternion.Euler(0, 0, z); arrow.rotation = rotation; }
×
×
  • Create New...