Jump to content
Unity Insider Forum

Spielergesteuerte rotierende Tür


Garzec

Recommended Posts

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

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

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

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

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

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

  • 2 weeks later...

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.

000.thumb.png.d4435da87741e2502e61901f1c2148cf.png

Rotiere ich die Tür beispielsweise um -30 auf der Y Achse, so sieht das Ganze wie folgt aus

-30.thumb.png.81171964033a617a8df43aa5bf9f50e7.png

Mit rotation und localRotation kam ich nicht weit. Kann mir jemand bei dem Rotationsproblem helfen?

Link zu diesem Kommentar
Auf anderen Seiten teilen

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

Archiviert

Dieses Thema ist jetzt archiviert und für weitere Antworten gesperrt.

×
×
  • Neu erstellen...