Chronicle Geschrieben 13. Mai 2021 Melden Share Geschrieben 13. Mai 2021 Moin, ich bins mal wieder und versuch gerade mir wieder etwas C# beizubringen. Derzeit möchte ich in einem definierten Bereich (grün) gelbe Quadrate spawnen lassen. Dabei soll der rote Bereich ausgelassen werden und sich keine der gelben Quadrate berühren. Wenn Sie sich berühren, soll eine neue Position gesucht werden. Hierfür mal ein kleines Bild zum Verständnis: Das die gelbvben Quadrate manchmal etwas außerhalb der grünen Fläche landen liegt am "Centerpoint" des Objektes vermute ich mal. Der Code des Programms sieht bisher so aus: public class ObjectSpawnInArea : MonoBehaviour { public GameObject GameObjectprefab; public Vector3 centerPositionSpawnArea; public Vector3 sizeSpawnArea; public Vector3 sizeNonSpawnArea; public Vector3 centerPositionNonSpawnArea; private Vector3 PositionForSpawn; private Vector3 PositionForNonSpawn; private Vector3 FinalSpawnPosition; // Start is called before the first frame update void Start() { for (int i = 0; i <= 10; i++) SpawnGameObject(); //Funktion zum spawnen wird aufgerufen. Bei Start wird GameObject 10-Mal gespawnt. } // Update is called once per frame void Update() { } // Diese Funktion färbt die Fläche ein, in der das GameObject Spawnen soll ... private void OnDrawGizmosSelected() { Gizmos.color = new Color(0, 1, 0, 0.5f); //Farbeinstellungen Gizmos.DrawCube(centerPositionSpawnArea, sizeSpawnArea); //Position der Fläche 2D bzw. des Würfels 3D Gizmos.color = new Color(1, 0, 0, 0.5f); Gizmos.DrawCube(centerPositionNonSpawnArea, sizeNonSpawnArea); } //Diese Funktion ermittelt die Position des Spawnpunktes für ein GameObject in der eingefärbten Fläche über die Variable sizeSpawnArea private void SpawnGameObject() { PositionForSpawn = centerPositionSpawnArea + new Vector3(Random.Range(-sizeSpawnArea.x / 2, sizeSpawnArea.x / 2), Random.Range(-sizeSpawnArea.y / 2, sizeSpawnArea.y / 2), 0); //z=0 wegen 2D Instantiate(GameObjectprefab, PositionForSpawn, Quaternion.identity); //Sorgt für die Auswahl des GameObjectes Prefab, also welches Object (Puzzleteil, Gegner, Spieler). Quaternion ist die Rotation des Objects. Quaternion.identity = keine Rotation. } } Wo brauche ich nun eure Hilfe. Ich verstehe nicht wie ich die Collision detekten kann und dann dem Programm sag, such nach detektierter Collision eine neue Position. Ich hab da was mit dieser funktion OnCollisionEnter2D() gearbeitet, aber irgendwie komme ich da nicht weiter. Der zweite Punkt ist, wie kann ich bei der Ermittlung der "Random Position" sagen, lass die rote Fläche aus? Bin wirklich für jede Hilfe dankbar. Grüße Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Chronicle Geschrieben 13. Mai 2021 Autor Melden Share Geschrieben 13. Mai 2021 Kleines Update. Das Problem mit der Area in der nicht gespawnt werden soll, konnte ich lösen ... der Code dazu sieht nun so aus: public class ObjectSpawnInArea : MonoBehaviour { public GameObject GameObjectprefab; public Vector3 centerPositionSpawnArea; public Vector3 sizeSpawnArea; public Vector3 sizeNonSpawnArea; public Vector3 centerPositionNonSpawnArea; private Vector3 PositionForSpawn; // Start is called before the first frame update void Start() { for (int i = 0; i < 10; i++) { SpawnGameObject(); //Funktion zum spawnen wird aufgerufen. Bei Start wird GameObject 10-Mal gespawnt } } // Update is called once per frame void Update() { } // Diese Funktion färbt die Fläche ein, in der das GameObject Spawnen soll ... private void OnDrawGizmosSelected() { Gizmos.color = new Color(0, 1, 0, 0.5f); //Farbeinstellungen Gizmos.DrawCube(centerPositionSpawnArea, sizeSpawnArea); //Position der Fläche 2D bzw. des Würfels 3D Gizmos.color = new Color(1, 0, 0, 0.5f); Gizmos.DrawCube(centerPositionNonSpawnArea, sizeNonSpawnArea); } //Diese Funktion ermittelt die Position des Spawnpunktes für ein GameObject in der eingefärbten Fläche über die Variable sizeSpawnArea private void SpawnGameObject() { PositionForSpawn = centerPositionSpawnArea + new Vector3(Random_Value(sizeNonSpawnArea.x, sizeSpawnArea.x)/2, Random_Value(sizeNonSpawnArea.y, sizeSpawnArea.y)/2, 0); //z=0 wegen 2D Instantiate(GameObjectprefab, PositionForSpawn, Quaternion.identity); //Sorgt für die Auswahl des GameObjectes Prefab, also welches Object (Puzzleteil, Gegner, Spieler). Quaternion ist die Rotation des Objects. Quaternion.identity = keine Rotation. } //Diese Funktion generiert positive oder negative zufallszahlen mit wechselndem Vorzeichen private float Random_Value(float Minimum, float Maximum) { float value = Random.Range(Minimum, Maximum); // Zahl zwischen Minimum und Maximum float sign = Random.value < 0.5f ? -1f : 1f; // Generiert + oder - return value * sign; } } Nun fehlt nur noch das nicht kollidieren ... Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Sascha Geschrieben 13. Mai 2021 Melden Share Geschrieben 13. Mai 2021 vor 4 Stunden schrieb Chroncile: such nach detektierter Collision eine neue Position. Moin! Naja, die Grundidee ist einfach: do { position = FindRandomPosition(); } while(IsBlocked(position)); SpawnAt(position); Bin kein großer Fan davon, weil ich es nicht mag, dass hier die Laufzeit theoretisch unbestimmt lang werden kann, aber solange du nur ein paar Dinger baust und nicht 90% der Fläche voll machst, sollte es zu verkraften sein. Vor allem, weil Alternativen schwierig zu implementieren sind. Ich kann mir vorstellen, dass die Frage auch nach IsBlocked ist; wie man das implementieren würde. Wenn du auf deinen Objekten Collider2D drauf hast, dann kannst du mit Physics2D.OverlapBox schauen, ob ein Collider mit der angegebenen Box überschneidet. Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Chronicle Geschrieben 13. Mai 2021 Autor Melden Share Geschrieben 13. Mai 2021 Moin, danke für die Antwort! Ich bin auch schon über diese Overlapdinger gestolpert, komme aber nicht mit der offiziellen Doku klar. Bin da noch irgendwie zu blöd für um das ganze kauderwelsch zu verstehen, bzw finde es schade das dort selten beispiele sind die man verfolgen kann 😕 ... ich möchte ja einfach nur abfragen mit if("Overlap detected") dann suche neue Position ... Ich weiß auch nicht wieso da aufeinmal Vektoren für die Box angegeben werden müssen .... ich kenne die Vektorposition der Box doch gar nicht, weil ich die Position des Colliders nicht kenne ... oder ist das die Box in der ein Overlap detektiert werden soll? ich heul fast ... den ganzen Herrentag verschwendet und kein Stück weiter 😕 ... ^^ Grüße Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Chronicle Geschrieben 13. Mai 2021 Autor Melden Share Geschrieben 13. Mai 2021 Ich hab es hinbekommen!! .... Der Fehler lag daran, das auf dem Prefab kein Collider war ... der Code war gut! Vielen Dank bis hierher für die Hilfe! Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Chronicle Geschrieben 14. Mai 2021 Autor Melden Share Geschrieben 14. Mai 2021 Moin, meine Funktion für das Spawnen sieht derzeit so aus: private void SpawnGameObject(int amountOfSpwans) { for (int i = 0; i < amountOfSpwans; i++) { PositionForSpawn = centerPositionSpawnArea + new Vector3(Random_Value(sizeNonSpawnArea.x, sizeSpawnArea.x)/2, Random_Value(sizeNonSpawnArea.y, sizeSpawnArea.y)/2, 0); //z=0 wegen 2D CollisionDetected = Physics2D.OverlapCircle(PositionForSpawn, radius); //Prüft ob das aktuelle GameObject mit einem anderen kollidiert. Wichtig. Das Prefab braucht einen Collider. if (CollisionDetected == false) Instantiate(GameObjectprefab, PositionForSpawn, Quaternion.identity); //Sorgt für die Platzierung des GameObjectes Prefab, also welches Object (Puzzleteil, Gegner, Spieler). Quaternion ist die Rotation des Objects. Quaternion.identity = keine Rotation else if (CollisionDetected == true) i--; } } Das Problem ist, das mein programm nun abstürzt, da ich vermutlich eine Endlosschleife gebaut habe. Wie kann ich ihm denn nun sagen, hey, wenn du eine Collision Detected hast, dann such weiter nach einem Platz! Mein problem ist, ohne das else if, hält das Programm die Anzahl der Spawns nicht ein. Geht das vielleicht mit While? Keine Ahnung 😕 ... Grüße Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Chronicle Geschrieben 14. Mai 2021 Autor Melden Share Geschrieben 14. Mai 2021 Meiner meinung nach müsste das so aussehen .... funktioniert leider nicht ... private void SpawnGameObject(int amountOfSpwans) { for (int i = 0; i < amountOfSpwans; i++) { PositionForSpawn = centerPositionSpawnArea + new Vector3(Random_Value(sizeNonSpawnArea.x, sizeSpawnArea.x)/2, Random_Value(sizeNonSpawnArea.y, sizeSpawnArea.y)/2, 0); //z=0 wegen 2D CollisionDetected = Physics2D.OverlapCircle(PositionForSpawn, radius); //Prüft ob das aktuelle GameObject mit einem anderen kollidiert. Wichtig. Das Prefab braucht einen Collider. if (CollisionDetected == false) Instantiate(GameObjectprefab, PositionForSpawn, Quaternion.identity); //Sorgt für die Platzierung des GameObjectes Prefab, also welches Object (Puzzleteil, Gegner, Spieler). Quaternion ist die Rotation des Objects. Quaternion.identity = keine Rotation else amountOfSpwans++; } } Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Sascha Geschrieben 14. Mai 2021 Melden Share Geschrieben 14. Mai 2021 Du hast ja schon eine for-Schleife, und dein Ansatz würde für sich genommen funktionieren. Auch wenn du das if hinter dem else weglassen kannst, weil das ja schon der "sonst"-Fall ist. CollisionDetected kann in dem Moment sowieso nur true sein, brauchst du also nicht noch einmal zu überprüfen. Über die Lesbarkeit des Codes kann man streiten (und das meine ich ganz wörtlich - ist echt Gechmackssache). Ansonsten sieht das schon ganz gut aus. Ein Problem kann ich im Code selbst nicht erkennen. Daher wäre meine Vermutung, dass da doch zu viele Collider in der Szene sind und er einfach keinen freien Platz mehr findet. Genau diese Problematik, die ich zuvor geschildert habe. Wenn du amountOfSpawns auf 1 setzt, geht es vermutlich, oder? Edit: Hehe, da haste direkt noch ein Update gepostet während ich geschrieben habe. Nur so als Nebeninfo: Es ist unüblich, die Zählervariable oder das Limit einer for-Schleife in dessen Rumpf zu ändern. Leute erwarten, dass die Schleife "amountOfSpawns-oft" durchläuft, stimmt dann am Ende aber gar nicht. Ansonsten die neue Variante genauso brauchbar wie die davor. Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Chronicle Geschrieben 14. Mai 2021 Autor Melden Share Geschrieben 14. Mai 2021 Hast recht, lag am Radius der Collision Detection ... wie würde man sowas denn eigentlich programmieren? Könntest du in "Pseude-Sprache" das einmal mit einer If-Schleife aufschreiben? Dann würde ich das in meinen Code übersetzen. Grüße Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Sascha Geschrieben 14. Mai 2021 Melden Share Geschrieben 14. Mai 2021 Wenn du die Durchläufe der for-Schleife nicht anfassen willst, muss in ihrem Rumpf eine zweite Schleife her: private void SpawnGameObject(int amountOfSpwans) { for (int i = 0; i < amountOfSpwans; i++) { do { PositionForSpawn = ... } while(IsBlocked(PositionForSpawn)); SpawnAt(PositionForSpawn); } } Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Chronicle Geschrieben 14. Mai 2021 Autor Melden Share Geschrieben 14. Mai 2021 Danke, wie genau funktioniert so ene while Schleife eigentlich? und was meinst du mit folgender Aussage? Zitat Leute erwarten, dass die Schleife "amountOfSpawns-oft" durchläuft, stimmt dann am Ende aber gar nicht. Also ich dachte immer das eine for-Schleife so lange durchläuft, bis amountOfSpawns erreicht ist ... Grüße Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Sascha Geschrieben 14. Mai 2021 Melden Share Geschrieben 14. Mai 2021 Ja, technisch sind deine beiden Codes halt unbedenklich. Aber guten Code zu schreiben heißt nicht, dass er läuft - es heißt, dass man Code schreibt, der gewisse Qualitätskriterien erfüllt. So sollte dein Code z.B. "wartbar" sein. Das heißt z.B., dass wenn du eine einzelne Sache ändern willst, du am besten nicht mehrere Codestellen anfassen musst, von denen du dann vielleicht eine vergisst. So als Beispiel: if (something) { ... } else if (!something) { ... } Funktioniert 1a, aber wenn die "..."-Blöcke etwas länger sind, und du möchtest "something" ändern (kann ja auch etwas komplexeres sein, so wie "a + b > c + d"), dann besteht halt die Gefahr, dass du das oben änderst und unten vergisst. Der Code ist also nicht sehr wartbar, und das zweite if wegzulassen ist sinnvoll. Eine weitere Sache ist Lesbarkeit. Wenn jemand anders deinen Code liest, oder du ihn selber nach einem Monat das erste Mal wieder anschaust, dann sollte er schnell zu verstehen sein und möglichst schwer zu missverstehen. for-Schleifen sind dabei, wenn sie diesem Standardmuster mit (i = 0; i < max; i++) entsprechen, ein sehr weit verbreitetes Ding, das quasi jeder sofort erkennt. Und es wird eben erwartet, dass der Rumpf der Schleife "max"-Mal durchläuft - nicht öfter oder seltener. Wenn sich im Rumpf aber eine kleine Zeile versteckt, die das ändert, dann kann man da schonmal beim Debuggen von der Spur des Bugs abgelenkt werden, den man gerade zu beheben versucht. Ist also kein Weltuntergang, aber halt der Unterschied zwischen funktionierendem Code und qualitativem Code. vor 3 Stunden schrieb Chroncile: Danke, wie genau funktioniert so ene while Schleife eigentlich? C# kennt vier Arten von Schleifen: while, do-while, for und foreach. (if ist übrigend keine Schleife, weil ein if-Statement keine Wiederholung verursacht). while: while (bedingung) { Zeug } Checkt die Bedingung, wenn sie zutrifft, wird Zeug ausgeführt und dann das ganze von vorne. do-while: do { Zeug } while (bedingung); Ist quasi dasselbe, aber hier wird zuerst einmal Zeug gemacht und dann gecheckt, ob die Bedingung zutrifft und Zeug entsprechend wiederholt werden soll. Das benutze ich hier, weil ich natürlich erstmal eine Zufallsposition würfeln will und dann schauen will, ob sie geblockt ist. for... naja, die kennst du ja for (Initialisierung; bedingung; Update) { Zeug } Initialisierung, dann Bedingung checken, wenn ja, dann Zeug, dann Update, und dann zurück zum Bedingungs-Check. Ist eine hübschere Schreibweise, aber ansonsten äquivalent, für Initialisierung while (bedingung) { Zeug update } Und dann gibt's noch foreach, womit du über alle Elemente einer Aufzählung iterieren kannst: foreach (var auto in meineGarage) { Debug.Log(auto); } Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Chronicle Geschrieben 14. Mai 2021 Autor Melden Share Geschrieben 14. Mai 2021 danke danke danke! Aber wo genau liegt der unterschied zwischen foreach und while? Ich verstehe den pseudocode bei foreach so wenn auto in Garage dann zeige Garage an ... genau wie bei dem While oder nicht? Grüße Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Sascha Geschrieben 15. Mai 2021 Melden Share Geschrieben 15. Mai 2021 Nein, bei foreach gibt es kein "wenn". Da wird über eine Sammlung von Elementen (z.B. eine Liste) drübergegangen, für jedes Element ein Durchlauf. Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Chronicle Geschrieben 15. Mai 2021 Autor Melden Share Geschrieben 15. Mai 2021 Danke Danke für all deine Hilfe! Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Chronicle Geschrieben 15. Mai 2021 Autor Melden Share Geschrieben 15. Mai 2021 vor 6 Stunden schrieb Sascha: Nein, bei foreach gibt es kein "wenn". Da wird über eine Sammlung von Elementen (z.B. eine Liste) drübergegangen, für jedes Element ein Durchlauf. ich hätte da noch eine Frage. Transform.Position ... kann es sein das hier keine Collider betrachtet werden wenn man darüber Gegenstände verschiebt? Muss ich das quasi wie beamen betrachten? dann muss ich sicherlich mit .MoveTowarrds arbeiten oder? Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Sascha Geschrieben 15. Mai 2021 Melden Share Geschrieben 15. Mai 2021 vor 1 Stunde schrieb Chroncile: ich hätte da noch eine Frage. Transform.Position ... kann es sein das hier keine Collider betrachtet werden wenn man darüber Gegenstände verschiebt? Muss ich das quasi wie beamen betrachten? dann muss ich sicherlich mit .MoveTowarrds arbeiten oder? Ja, das ist korrekt. Du setzt da direkt die Position eines Objekts, und bist damit sozusagen ganz unten in der Hierarchie. Physik und Kollisionen sind darauf aufbauen implementiert. MoveTowards hilft da nicht, da das nur eine vektormathematische Funktion ist. Wenn du Kollisionen haben willst, brauchst du entweder eine eigene Kollisionsabfrage mit den Methoden der Physics-Klasse oder, was erstmal einfacher wäre, Collider und einen Rigidbody. Rigidbody ist die Komponente, die ein Objekt bewegt und dabei eben auf Kollisionen achtet. Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Chronicle Geschrieben 15. Mai 2021 Autor Melden Share Geschrieben 15. Mai 2021 gelöscht Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Chronicle Geschrieben 15. Mai 2021 Autor Melden Share Geschrieben 15. Mai 2021 gelöscht Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Chronicle Geschrieben 15. Mai 2021 Autor Melden Share Geschrieben 15. Mai 2021 vergiss bitte meine beiden Posts zuvor ... ich konnte fast alles lösen ... nur eines nicht. Beim Moven ignorieren die Gameobjekte ihre eigenen Collider, nicht aber von Gegenständen die von Anfang an in der Szene sind. Der Hund auf folgendem Bild hat einen Box Collider und die Kisten spawnen niemals auf ihm. Alle Kisten haben ebenfalls BoxCollider und sollen im Radis (rot) eigentlich nach anderen Collidern scannen ... Hier ein Beispiel: dann habe ich mir gedacht, das liegt bestimmt da dran, das der Code die Dinger gleichzeitg plaziert. Also habe ich eine for-Schleife gebaut und lege dort die GameObjecte in einem array an sodass die nach und nach gespawnt werden, aber auch so werden die collider ignoriert. Wieso? Hier mein Code: [SerializeField] private Vector3 centerPositionMoveArea; [SerializeField] private Vector3 sizeMoveArea; [SerializeField] private float radius; private Vector3 PositionForMove; private Collider2D CollisionDetected; [SerializeField] private GameObject[] prefabs; private int tries; [SerializeField] private int maxMoveTries; void Update() { if (Input.GetButtonDown("Fire1")) for (int i = 0; i < prefabs.Length; i++) prefabs[i].transform.position = MoveGameObject(maxMoveTries); } private Vector3 MoveGameObject(int maxMoveTries) { int MoveTries = 0; while (MoveTries < maxMoveTries) { PositionForMove = centerPositionMoveArea + new Vector3(Random_Value(0, sizeMoveArea.x) / 2, Random_Value(0, sizeMoveArea.y) / 2, 0); //z=0 da 2D if(!IsBlocked(PositionForMove, radius)) { Debug.Log("Gebiet frei"); Debug.Log("I tried to place " + MoveTries); transform.position = PositionForMove; break; } if (IsBlocked(PositionForMove, radius)) { Debug.Log("BLOCKIERT!!!"); MoveTries++; } if (MoveTries==maxMoveTries) { Debug.Log("ABGEBROCHEN, da blockiert!!!"); Debug.Log("I tried to place " + MoveTries); break; } } return transform.position; } Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Sascha Geschrieben 16. Mai 2021 Melden Share Geschrieben 16. Mai 2021 Der erste Verdacht ist dabei immer: Mixt du vielleicht 2D- und 3D-Collider? Die können sich gegenseitig nicht sehen, weil sie zu verschiedenen Physik-Engines gehören. Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Chronicle Geschrieben 16. Mai 2021 Autor Melden Share Geschrieben 16. Mai 2021 geprüft. Nein sind beides 2D-Collider. hilft es eventuell wenn ich das Projekt hochlade? Bin leider echt ratlos 😕 ... Puzzle training.zip Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Sascha Geschrieben 16. Mai 2021 Melden Share Geschrieben 16. Mai 2021 vor 21 Stunden schrieb Chroncile: dann habe ich mir gedacht, das liegt bestimmt da dran, das der Code die Dinger gleichzeitg plaziert. Das könnte übrigens stimmen. Also... die werden schon nacheinander Positioniert, aber es kann sein, dass die Physik-Engine zwischendurch nicht automatisch mitkriegt, dass da jetzt neue Objekte sind. Ruf mal nach jedem Spawnen Physics2D.SyncTransforms auf. vor 21 Stunden schrieb Chroncile: Also habe ich eine for-Schleife gebaut und lege dort die GameObjecte in einem array an sodass die nach und nach gespawnt werden So ein Array brauchst du nicht Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Chronicle Geschrieben 16. Mai 2021 Autor Melden Share Geschrieben 16. Mai 2021 Danke das wars! Nun geht es! Wie geil ist das denn!! ich sehe übrigens du bist Admin. Magst du mein Namen hier in Chronicle ändern? Da ist nen Fehler beim registrieren passiert ^^ ... Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Sascha Geschrieben 17. Mai 2021 Melden Share Geschrieben 17. Mai 2021 Das ist doch schön. Ist auch für mich gut, dass mir das mal wieder in Erinnerung gerufen wurde Der Name ist geändert. Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Recommended Posts
Archiviert
Dieses Thema ist jetzt archiviert und für weitere Antworten gesperrt.