Garzec Geschrieben 16. Oktober 2017 Melden Share Geschrieben 16. Oktober 2017 Hallo, aktuell baue ich Scripte für verschiedene Türen zusammen. Dabei habe ich noch ein Problem mit einer rotierenden Tür, die vom Spieler geöffnet / geschlossen wird. Der Spieler kann also mit der Tür interagieren und diese öffnet / schließt sich. Falls eingestellt, öffnet diese sich immer vom Spieler weg, je nachdem, ob er nun vor oder hinter ihr steht. Wie eine Saloon-Tür quasi. [SerializeField] Vector3 targetRotation; // Die Zielrotation beim geöffneten Zustand [SerializeField] float duration; // Rotationsdauer [SerializeField] bool isClosable; // kann man die Tür wieder schließen? [SerializeField] Vector3 pivotPosition; // Position des Pivotpunktes [SerializeField] bool opensAwayFromPlayer; // Saloon Tür? bool isActive = false; // Tür momentan "beschäftigt"? Transform doorPivot; Transform playerTransform; bool isOpen = false; // Tür Status void Start() // Pivotpunkt setzen { playerTransform = Globals.GetPlayerObject().transform; doorPivot = new GameObject().transform; doorPivot.position = pivotPosition; transform.SetParent(doorPivot); } IEnumerator DoorRotation() // Tür öffnen oder schließen { if (isActive) // Solange die Tür sich öffnet oder schließt nichts machen yield break; isActive = true; float counter = 0; // aktueller Rotationstimer Vector3 defaultAngles = doorPivot.eulerAngles; // die Rotation im geschlossenen Zustand Vector3 desiredRotation = targetRotation; // Ziel Rotation geöffnet if (opensAwayFromPlayer && PlayerIsBehindDoor(transform, playerTransform)) // Rotation umdrehen, falls der Spieler hinter der Tür steht desiredRotation = -desiredRotation; Vector3 openRotation = transform.eulerAngles + desiredRotation; // Die tatsächliche Rotation if (!isOpen) // Tür öffnen, falls geschlossen { while (counter < duration) { counter += Time.deltaTime; LerpDoorRotation(doorPivot, defaultAngles, openRotation, counter, duration); yield return null; } if (!isClosable) // Script zerstören, da es nicht mehr benötigt wird -> Tür ist nicht verschließbar Destroy(this); } else // Tür schließen { while (counter > 0) { counter -= Time.deltaTime; LerpDoorRotation(doorPivot, defaultAngles, openRotation, counter, duration); yield return null; } } isOpen = !isOpen; // Tür Status umschalten isActive = false; } bool PlayerIsBehindDoor(Transform door, Transform player) // Prüfen, ob der Spieler hinter der Tür steht { Vector3 doorTransformDirection = door.forward.normalized; Vector3 playerTransformDirection = (player.position - door.position).normalized; return Vector3.Dot(doorTransformDirection, playerTransformDirection) < 0; } void LerpDoorRotation(Transform doorPivot, Vector3 defaultAngles, Vector3 targetRotation, float counter, float duration) // Rotationsbewegung { doorPivot.eulerAngles = Vector3.Lerp(defaultAngles, targetRotation, counter / duration); } Aufrufen tue ich das Ganze über eine Methode namens `Interact()`. Diese startet eine Coroutine mit `DoorRotation()`. Steht der Spieler nun vor der Tür, so rotiert diese nach vorne, also +90 Grad. Möchte ich die Türe wieder schließen, so passiert beim nächsten Aufruf von `Interact()` nichts. Danach rotiert die Tür nicht zurück, sondern weiter, also auf 180 Grad. Danach passiert wieder nichts und danach weiter zu 270 Grad usw. Hat jemand eine Idee? Ich schätze es hat etwas mit der Zeile if (opensAwayFromPlayer && PlayerIsBehindDoor(transform, playerTransform)) desiredRotation = -desiredRotation; zu tun, aber ich brauche diese, damit die Rotation richtig berechnet wird, falls der Spieler hinter der Türe steht. Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Zer0Cool Geschrieben 16. Oktober 2017 Melden Share Geschrieben 16. Oktober 2017 Nur mal kurz überflogen, aber beim Tür schließen fehlt mir was und zwar "counter" auf "duration" zu setzen: float counter; if (isOpen) counter = duration; // aktueller Rotationstimer bei geöffneter Tür else counter = 0; // aktueller Rotationstimer bei geschlossener Tür Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Garzec Geschrieben 16. Oktober 2017 Autor Melden Share Geschrieben 16. Oktober 2017 Achso, ja könnte man auch schreiben. Aktuell zähle ich diesen ja einfach beim Öffnen hoch und beim Schließen wieder runter. Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Zer0Cool Geschrieben 16. Oktober 2017 Melden Share Geschrieben 16. Oktober 2017 vor 20 Minuten schrieb Garzec: Achso, ja könnte man auch schreiben. Aktuell zähle ich diesen ja einfach beim Öffnen hoch und beim Schließen wieder runter. Eben nicht, wenn du die Tür schließen möchtest, wird der counter auf 0 gesetzt und damit wird sich die Tür beim Schließen nicht bewegen und daß hast du oben ja auch als dein aktuelles Problem beschrieben: - möchte ich die Türe wieder schließen, so passiert beim nächsten Aufruf von `Interact()` nichts => ja weil "duration" auf 0 gesetzt wird (im alten Quellcode) und damit nur die Tür auf "isOpen = false" gesetzt wird. - danach rotiert die Tür nicht zurück, sondern weiter, also auf 180 Grad => ja weil "duration" auf 0 gesetzt wird und "isOpen" auf "false" steht. Damit öffnet sich die Tür wieder. ... Zudem wird "doorPivot.eulerAngles" nie zurückgesetzt und damit addiert sich der Rotationswinkel der Tür immer weiter auf. Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Garzec Geschrieben 16. Oktober 2017 Autor Melden Share Geschrieben 16. Oktober 2017 Stimmt. Habe deinen Weg getestet. Jetzt macht die Tür bei jeder Interaktion etwas. Das Öffnen funktioniert korrekt, das Schließen noch nicht. Öffnet sich die Tür auf 90 Grad, so schließt sie sich von 180 Grad auf 90 Grad. Danach öffnet sie sich von 90 auf 180 Grad und schließt sich von 270 auf 180. usw. Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Zer0Cool Geschrieben 16. Oktober 2017 Melden Share Geschrieben 16. Oktober 2017 Speichere dir mal in einer Variable "doorPivot.eulerAngles", d.h. den Winkel der geschlossenen Tür. private Vector3 closedDoorAngles; void Start() // Pivotpunkt setzen { playerTransform = Globals.GetPlayerObject().transform; doorPivot = new GameObject().transform; doorPivot.position = pivotPosition; transform.SetParent(doorPivot); closedDoorAngles = doorPivot.eulerAngles; } IEnumerator DoorRotation() // Tür öffnen oder schließen { ... Vector3 defaultAngles = closedDoorAngles; // die Pivot-Rotation im geschlossenen Zustand ... } Kann sein, daß das nicht ausreicht. "desiredRotation" und "openRotation" müsste man auch noch einmal überprüfen. PS: Insgesamt finde ich die gesamte Logik ziemlich komplex für so eine einfache Sache wie das Öffnen einer Tür. Ich würde das Ganze über eine Animation an der Tür lösen. Hier hat man volle Kontrolle und die Animation kann man auch sehr einfach rückwärts ablaufen lassen. Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Garzec Geschrieben 16. Oktober 2017 Autor Melden Share Geschrieben 16. Oktober 2017 Wenn ich das mache, rotiert er auf 90 Grad und rotiert dann von 180 Grad zurück auf 0. Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Zer0Cool Geschrieben 16. Oktober 2017 Melden Share Geschrieben 16. Oktober 2017 Dann stimmt "openRotation" vermutlich nicht. Da musst du nun mal selber schauen, ich müsste nun auch anfangen zu "debuggen" und das Skript zu zerlegen. Schnelllösung, aber wie gesagt, so langsam müsste man das komplette Skript mal neu überarbeiten: Vector3 openRotation = desiredRotation; // Die tatsächliche Rotation Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Garzec Geschrieben 17. Oktober 2017 Autor Melden Share Geschrieben 17. Oktober 2017 @Zer0Cool was möchtest du denn alles überarbeiten Kommt dir das gesamte Script völlig falsch vor? Deine ersten Vorschläge konnte ich problemlos anpassen. Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Zer0Cool Geschrieben 17. Oktober 2017 Melden Share Geschrieben 17. Oktober 2017 Naja, wenn nun alles wie gewollt klappt, dann ist ja gut. Oft zeigen Fehler an, daß ein Code zu "unaufgeräumt" oder schlecht strukturiert ist. Der obige Code ist mir auch zu "umständlich" für seine eigentliche Funktion, aber es ist noch "im Rahmen". Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
q3max Geschrieben 19. Oktober 2017 Melden Share Geschrieben 19. Oktober 2017 using UnityEngine; using System.Collections; public class theDoor : MonoBehaviour { public Transform door; public Vector3 doorAngle; public Transform player; bool toPlayer; void Start () { } bool open = false; void Update () { if(Input.GetKeyDown(KeyCode.Space)) { CheckPlayer (); OpenClose(); open = !open; } } void CheckPlayer() { if (Vector3.Dot (door.forward, player.forward) < -0.5f) toPlayer = true; else if (Vector3.Dot (door.forward, player.forward) > 0.5f) { toPlayer = false; } } void OpenClose() { if(open) { if(toPlayer) { door.rotation *= Quaternion.Euler(-doorAngle); } else{ door.rotation *= Quaternion.Euler(doorAngle); } } else { if(toPlayer) { door.rotation *=Quaternion.Euler(doorAngle); } else { door.rotation *= Quaternion.Euler(-doorAngle); } } } } vlt als Anregung Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Garzec Geschrieben 31. Oktober 2017 Autor Melden Share Geschrieben 31. Oktober 2017 Danke für deine Hilfe, die Rotationen etc. habe ich bereits fertig gehabt, da kann ich die Scripte hinterher auch mal zeigen. Ich hänge "nur" noch an der Erzeugung des Pivotpunktes (ja, den könnte man auch schon in der Szene setzen, aber ich möchte den Pivot per Code erzeugen). [SerializeField] Vector3 pivotPosition; // relative Position zur Tür // steht die Tür auf x bei 0, ist 6 Breit, muss der Pivot auf -3 stehen Transform doorPivot; // Der erzeugte Pivotpunkt private void Start() { doorPivot = new GameObject().transform; // Pivot erzeugen doorPivot.position = transform.localPosition + doorPivot.InverseTransformPoint(pivotPosition); // Pivotpunkt setzen transform.SetParent(doorPivot); // Tür zum Kind des Pivots machen } private void OnDrawGizmos() // Test Malroutine { Gizmos.color = Color.red; if (doorPivot != null) Gizmos.DrawWireSphere(doorPivot.position, 0.5f); Gizmos.DrawWireSphere(transform.position, 0.5f); } Laut den eingezeichneten Kugeln passt das, WENN die Tür in der Szene eine Rotation von 0,0,0 hat. Rotiere ich die Tür beispielsweise um -30 auf der Y Achse, so sieht das Ganze wie folgt aus Mit rotation und localRotation kam ich nicht weit. Kann mir jemand bei dem Rotationsproblem helfen? Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Garzec Geschrieben 31. Oktober 2017 Autor Melden Share Geschrieben 31. Oktober 2017 Dank der freundlichen Hilfe von @Life Is Good sieht die Erzeugung des Pivots so aus protected void CreateDoorPivot(Transform doorTransform, Vector3 pivotPosition) { doorPivot = new GameObject().transform; Quaternion desiredRotation = transform.rotation; transform.rotation = Quaternion.identity; doorPivot.SetParent(transform); doorPivot.position = transform.localPosition + pivotPosition; transform.rotation = desiredRotation; doorPivot.SetParent(null); transform.SetParent(doorPivot); } Da bei den Türen mittlerweile eine große Logik mit Basisklassen vorhanden ist, hier mal das Repository für alle 4 verschiedenen Türen https://github.com/Garzec/Platformer/tree/master/Assets/Scripts/Environment/Objects/Doors 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.