Garzec Geschrieben 8. Oktober 2017 Melden Share Geschrieben 8. Oktober 2017 Ich möchte eine Tür um beispielsweise 90 Grad öffnen, danach soll diese beispielsweise 3 Sekunden warten und sich wieder schließen. Für die Rotation der Tür würde ich einen Pivotpunkt setzen. Für den Beginn der Rotation rufe ich im Spiel die Methode "Interact()" auf. public class RotatingDoor : Door, IInteractable { [SerializeField] private Vector3 targetRotation; // Rotation, wenn offen [SerializeField] private float duration; // Geschwindigkeit [SerializeField] private bool closeAgain; // Tür wieder schließen oder offen lassen? [SerializeField] private float waitInterval; // Wartezeit bis zum Schließen private Vector3 defaultRotation; // Ursprungsrotation bei Start private bool isActive = false; // Tür grade "beschäftigt" ? private void Start() { defaultRotation = transform.eulerAngles; } private IEnumerator DoorRotation() { if (isActive) // Abbrechen, wenn sich die Tür bereits öffnet / schließt yield break; isActive = true; yield return StartCoroutine(RotateDoor(targetRotation)); // Tür öffnen if (!closeAgain) // Script zerstören, falls die Tür nicht geschlossen werden muss Destroy(this); yield return new WaitForSeconds(waitInterval); // X Sekunden warten yield return StartCoroutine(RotateDoor(defaultRotation)); // Tür zur Ursprungsrotation schließen isActive = false; } private IEnumerator RotateDoor(Vector3 newRotation) // Tür rotieren { float counter = 0; newRotation = transform.eulerAngles + newRotation; while (counter < duration) { counter += Time.deltaTime; transform.eulerAngles = Vector3.Lerp(transform.eulerAngles, newRotation, counter / duration); yield return null; } } public void Interact() { StartCoroutine(DoorRotation()); // Tür öffnen und anschließend wieder schließen } } Dabei habe ich zwei Probleme: 1. Setze ich im Inspector eine niedrige Dauer, so rotiert die Tür sehr schnell. Setze ich also einen größeren Wert ein, rotiert sie zwar langsamer aber der Counter innerhalb der Methode benötigt dann eben auch X Sekunden, bis er bei dieser Dauer angekommen ist. Obwohl er bei einer Rotationsdauer von 3 Sekunden nach 3 Sekunden größer als Dauer sein sollte. 2. Die Tür rotiert zwar auf, aber nicht mehr zu. Es wird zwar die Coroutine aufgerufen, wieder zurück zu rotieren, aber die Tür bleibt starr. Rotiere ich die Tür danach noch einmal, rotiert sie natürlich erstmal weiter von 90 bis 180 Grad, da sie ja nicht zurück rotiert ist. Hilfe wäre super Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Sascha Geschrieben 8. Oktober 2017 Melden Share Geschrieben 8. Oktober 2017 Ich muss zugeben, dass ich Frage 1 nicht verstehe. Wenn du 3 Sekunden Dauer eingibst kriegst du 3 Sekunden Dauer. Ist doch richtig? 2 ist allerdings relativ simpel. Deine RotateDoor-Funktion braucht als Parameter einen Offset, also eine Rotation, um die sich gedreht wird - nicht eine Zielrotation. Dein Schließen-Aufruf ist aber yield return StartCoroutine(RotateDoor(defaultRotation)); Das heißt, dass bei defaultRotation = Quaternion.identity die Tür gar nicht gedreht wird. Ändere also am besten deine RotateDoor-Funktion, dass sie eine Zielrotation braucht statt eines offsets. Diese Zeile kommt dann einfach raus: newRotation = transform.eulerAngles + newRotation; und dafür sieht der Öffnen-Aufruf dann so aus: yield return StartCoroutine(RotateDoor(transform.eulerAngles + targetRotation)); // Tür öffnen Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Garzec Geschrieben 8. Oktober 2017 Autor Melden Share Geschrieben 8. Oktober 2017 ok super, Frage 2 gelöst Zu Frage 1: Ich nehme mal als Duration den Wert 5. Die Rotation der Tür ist bereits in unter 2 Sekunden fertig. Die `RotateDoor` Funktion selbst benötigt aber die vollen 5 Sekunden, da der Counter dann erst bei 5 Sekunden ankommt und die while-Schleife verlässt. Ich möchte im Prinzip mit der Duration angeben, wie lange die Rotation dauern soll. Würde ich nämlich beispielsweise bei der Duration 20 setzen, wäre die Rotation nach ca. 3 Sekunden fertig aber der Counter muss ca. 20 Sekunden lang hochzählen, bis es weiter geht. Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Sascha Geschrieben 8. Oktober 2017 Melden Share Geschrieben 8. Oktober 2017 Kann eigentlich nicht sein. vor einer Stunde schrieb Garzec: counter / duration Das hier ist ja kleiner als 1 solange counter < duration ist. Das heißt, dass dein Lerp auch noch läuft solange counter < duration ist. Daher ist dein Code ist richtig, vielleicht hast du nur die falschen Werte drin? Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Garzec Geschrieben 8. Oktober 2017 Autor Melden Share Geschrieben 8. Oktober 2017 Hmm.. also ich habs jetzt mal mit verschiedenen Werten getestet. Nehme ich den Wert 1, ist die Rotation natürlich schon in 1 Sekunde fertig. Nehme ich den Wert 10, dauert es ca. 2 Sek. Bei 50 ca. 4 Sek. usw. Also die Rotation wird schon langsamer, aber sie ist eben sehr viel schneller als die eigentliche Dauer. Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Garzec Geschrieben 8. Oktober 2017 Autor Melden Share Geschrieben 8. Oktober 2017 @Sascha wenn du magst kann ich dir ein Video oder Gif erstellen. Oder du erstellst ein Projekt, nimmst einen Würfel und kopierst den Code drauf. Edit: Speichere ich mir die eulerAngles vor der Schleife zwischen, also private IEnumerator RotateDoor(Vector3 newRotation) { float counter = 0; Vector3 defaultAngles = transform.eulerAngles; // Zwischenspeichern while (counter < duration) { counter += Time.deltaTime; transform.eulerAngles = Vector3.Lerp(defaultAngles, newRotation, counter / duration); yield return null; } } funktioniert das Ganze. Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Sascha Geschrieben 8. Oktober 2017 Melden Share Geschrieben 8. Oktober 2017 Ich bin doof. Hier ist das Problem. Falsch: float counter = 0; while (counter < duration) { counter += Time.deltaTime; transform.eulerAngles = Vector3.Lerp(transform.eulerAngles, newRotation, counter / duration); yield return null; } Richtig: float counter = 0; var oldRotation = transform.eulerAngles; while (counter < duration) { counter += Time.deltaTime; transform.eulerAngles = Vector3.Lerp(oldRotation, newRotation, counter / duration); yield return null; } Du nimmst ja immer die aktuelle Rotation als Ausgangspunkt für dein Lerp. Damit geht dir die exakte Kontrolle über die Zeit flöten und die Interpolation ist auch nicht mehr linear. Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Garzec Geschrieben 8. Oktober 2017 Autor Melden Share Geschrieben 8. Oktober 2017 Hast du jetzt einfach mal meine Lösung genommen und nochmal hingeschrieben? Dann hätte ich eigentlich nur noch die Frage, ob ich den Pivotpunkt der Tür im Script setzen kann, oder ein Empty GO als Vater nehmen muss und dieses dann rotiere. Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Sascha Geschrieben 8. Oktober 2017 Melden Share Geschrieben 8. Oktober 2017 Ja, hab ich. Aber das war, bevor du editiert hast. Zu der neuen Frage: Mit nem Parent ist das am einfachsten. Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Garzec Geschrieben 8. Oktober 2017 Autor Melden Share Geschrieben 8. Oktober 2017 Aber es würde prinzipiell auch per Code gehen? Mit dem GO ist es einfach, aber das wäre wieder extra Zeugs, nur damit die Tür einen Drehpunkt hat :/ Wäre ziemlich cool, wenn die Tür das auch ohne weiteres Objekt machen könnte. Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Sascha Geschrieben 8. Oktober 2017 Melden Share Geschrieben 8. Oktober 2017 Und mehrere Zeilen kyptischen Codes ist kein "extra Zeugs"? Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Garzec Geschrieben 9. Oktober 2017 Autor Melden Share Geschrieben 9. Oktober 2017 da gebe ich dir ja Recht. Ich bin prinzipiell aber ein Freund von "ich nehme nur dieses Objekt, ziehe es rein und alles funktioniert". Die Sache mit dem GO ist in Ordnung, aber 1x im Start den Pivotpunkt zu verschieben fände ich am besten. Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Garzec Geschrieben 10. Oktober 2017 Autor Melden Share Geschrieben 10. Oktober 2017 Hallo, für die Vollständigkeit würde ich mal das finale Script hier lassen, vielleicht kann es ja jemand gebrauchen. Vielleicht findet auch jemand Verbesserungen. Mit dem Script ist es jetzt ebenfalls möglich, die Tür so einzustellen, dass sie immer vom Spieler weg rotiert. Beispielsweise eine Saloon Tür. [SerializeField] private Vector3 targetRotation; [SerializeField] private float duration; [SerializeField] private bool closeAgain; [SerializeField] private float waitInterval; [SerializeField] private Vector3 pivotPosition; [SerializeField] private bool opensAwayFromPlayer; private Vector3 defaultRotation; private bool isActive = false; private Transform doorPivot; private Transform playerTransform; private void Start() { playerTransform = Globals.GetPlayerObject().transform; doorPivot = new GameObject().transform; doorPivot.position = pivotPosition; transform.SetParent(doorPivot); defaultRotation = doorPivot.eulerAngles; } private IEnumerator DoorRotation() { if (isActive) yield break; isActive = true; float counter = 0; Vector3 defaultAngles = doorPivot.eulerAngles; if (PlayerIsBehindDoor()) targetRotation = -targetRotation; Vector3 openRotation = transform.eulerAngles + targetRotation; while (counter < duration) { counter += Time.deltaTime; LerpDoor(defaultAngles, openRotation, counter); yield return null; } if (!closeAgain) Destroy(this); yield return new WaitForSeconds(waitInterval); while (counter > 0) { counter -= Time.deltaTime; LerpDoor(defaultAngles, openRotation, counter); yield return null; } isActive = false; } private void LerpDoor(Vector3 defaultAngles, Vector3 targetRotation, float counter) { doorPivot.eulerAngles = Vector3.Lerp(defaultAngles, targetRotation, counter / duration); } private bool PlayerIsBehindDoor() { Vector3 doorTransformDirection = transform.TransformDirection(Vector3.forward); Vector3 playerTransformDirection = playerTransform.position - transform.position; return Vector3.Dot(doorTransformDirection, playerTransformDirection) < 0; } public void Interact() { StartCoroutine(DoorRotation()); } Die Einstellungen im Inspector sind sehr überschaubar. Zusätzlich muss man die Tür nicht unbedingt um ihre y-Achse drehen. Man kann sie drehen und winden, wie man möchte. 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.