Jump to content
Unity Insider Forum
Sign in to follow this  
vreezer

Spielfigur nach vorne und zurück lehnen (transform.eulerAngles)

Recommended Posts

Heute bin ich über ein altes Projekt gestolpert und probiere mich mal wieder in meinen nicht vorhandenen Programmierfähigkeiten. 😁

Es handelt sich um eine Art Hover-Fahrzeug, dass sich beim Lenken bereits nach links und rechts neigen lässt. Jetzt wollte ich es zusätzlich noch gerne vor- und zurück neigen lassen, aber irgendwie scheint es nicht zu funktionieren, wenn ich die Achsen einfach austausche.

Hier ist das Script und wie weit ich gekommen bin:

using UnityEngine;
using System.Collections;

public class Hover_LeanF : MonoBehaviour {

    public float MaxTiltAngle = 20.0f;    // The maximum angle the board can tilt
    public float tiltSpeed = 30.0f;       // tilting speed in degrees/second
    Vector3 curRotF;
    float maxX;
    float minX;

    //void Start()

    void Update()
    {
        {
            // Get initial rotation
            curRotF = this.transform.eulerAngles;
            // calculate limit angles:
            maxX = curRot.x + MaxTiltAngle;
            minX = curRot.x - MaxTiltAngle;
        }
    }

    void FixedUpdate()
    {
        // "rotate" the angles mathematically:
        curRot.x += -Input.GetAxis("lean_fb") * Time.deltaTime * tiltSpeed;
        // Restrict rotation along x axes to the limit angles:
        curRot.x = Mathf.Clamp(curRot.x, minX, maxX);

        // Set the object rotation
        this.transform.eulerAngles = curRotF;
    }
}

Ehrlich gesagt habe ich nur eine grobe Ahnung, was die einzelnen Zeilen bewirken könnten...

Das vollständige Script vom Fahrzeug liegt im Anhang. Dort funktionert das seitliche Lehnen (in die Kurve) auf ähnliche Weise.

Vielleicht hat jemand Erbarmen und hilft mir dabei das Fahrzeug auch nach vorne und zurück lehnen zu lassen ?

HoverCarControl.cs

Share this post


Link to post
Share on other sites

Ich will's dir mal erklären, denn du hast da 2 große Fehler drin.

Um festzulegen, wie weit dein Ding sich neigen darf, muss einmalig ein Grundwinkel ermittelt werden. Das ist der Winkel, der anliegt, wenn sich noch nichts neigt.
Dafür wird eine Variable vom Tpy Vector3 gebraucht und die wird curRot genannt. Die momentanen 3 Winkel deines Dings, werden nun in dieser Variable gespeichert.

curRot = this.transform.eulerAngles;
            


Die beiden maximalen Neigungswinkel werden jetzt auch einmalig ermittelt und dafür wird maxTiltAngle genutzt.

maxX = curRot.x + MaxTiltAngle;
minX = curRot.x - MaxTiltAngle;
        

Dafür wird nur der gespeicherte Wert der X Achse, aus deiner Vector3 Variable curRot genutzt.  Dieser Wert plus dem Maximalwert wird der Variable maxX übergeben und der Wert minus dem Maximalwert wird maxY übergeben.

Damit sich etwas ändert, muss natürlich von irgendwo ein Wert her kommen. Bei dir kommt der Wert von 

Input.GetAxis("lean_fb")

Der Werteumfang bei GetAxis geht von -1 über die 0 zu +1. Wenn du nur leicht nach rechts lenkst, wird es irgendein Wert zwischen 0 und +1 sein, z.B. 0.3f.

Diesen Wert mutliplizierst du mit der deltaTime ( was soviel wie Wert pro Sekunde bedeutet, aber in Wirklichkeit die Verstrichene Zeit zwischen 2 Frames ist) und multiplizierst ihn nocheinmal mit dem tiltSpeed. Es ist also sowas: 0.3f *0.1f*30f und das wäre 0.9f.
Das bedeutet, in diesem Zyklus soll sich das Ding um 0.9° neigen.

Damit es das tut, muss der ermittelte Wert natürlich auch deinem Ding übergeben werden. Das wird aber am Schluß erst gemacht. Denn wir wollen mit diesem Wert ja den momentanen Wert verändern. Aber das auch nur, wenn wir nicht schon unseren maximalen Neigungswinkel rechts oder links erreicht haben.

Dafür müssen diesen Wert dem curRot.x hinzufügen bzw. abziehen, kurz überprüfen, ob dieser Winkel noch im Rahmen ist und ihn dann komplett mit allen anderen vorher gespeicherten Achsen übergeben.
Damit der Neigungswinkel nicht unsere Maximalwinkel über- oder unterschreitet, gibt es die Mahtf.Clamp Funktion. Clamp ist englisch für einklemmen und Mathf.Clamp überprüft jetzt den curRot.x Wert und schaut ob er zwischen maxX und minX liegt. tut er es, wird nichts geändert. Liegt er über maxX, wird er zu maxX, liegt er unter minX wird er zu minX.
Das ist alles.
Jetzt, am Schluß, der Berechnung werden alle Winkel von deinem Ding mit den Werten von curRot überschreiben. Dein Ding ist also jetzt sofort etwas geneigt.
Verändert wurde jetzt aber nur der Wert der x Achse, die andern beiden Achsen haben wir ja nicht verändert.

Jetzt zu deinem Fehler:

Du hast versucht ein vorhandenes Script umzuschreiben und hast dafür den Variablennamen curRot in curRotF umbenannt.
Diesem curRotF übergibst du zwar die Werte von deinem Transform, aber im weiteren Verlauf nutzt du curRot ohne das F ! Da es in dem Script, was ich hier sehe, aber keine Deklaration von curRot gibt, müsstest du eigentlich Fehlermendungen bekommen, denn man kann nichts beschreiben, was nicht bekannt ist.
Aber vielleicht hast du auch nicht alle Zeilen gepostet und es gibt in deinem Script noch auch ein curRot. Dann wäre aber das Problem, dass du den x Wert von curRot änderst, aber eben nicht von curRotF! curRotF verändert sich somit nicht und somit siehst du auch keine Änderung.

Ein weiteres Problem sehe ich darin, dass du in jeder Update die Winkel dem curRotF übergibst und die Maximalwinkel neu ermittelst. Das würde bedeuten, dass sich nach einer Neigung auch der Maximalwinkel verschiebt und somit dein Ding eben nicht aufhört zu rotieren.
In dem angehangenen Script ist das auch so ähnlich und meiner Meinung nach wird das nicht funktionieren.

Wenn du deine Fehler beseitigt hast, könntest du eigentlich auch 2 Winkel gleichzeitig bearbeiten. curRot ist ja ein Vector3, wo alle deine 3 Winkel drin sind. Du kannst also mittels deiner InputAxis curRot.x und curRot.z direkt hintereinander verändern. Brauchst da natürlich Variablen für die Maximale von x und von z.
Beides wird verändert, beides wird eingeklemmt und dann zusammen wieder der Transform Komponente übergeben.

 

Share this post


Link to post
Share on other sites

Vielen Dank für die ausführliche Beschreibung. 🙂👍

Ich habe es durch Deine Erklärung nun zwar hinbekommen: Das Bike lehnt sich in die Kurve und man kann gleichzeitig auch die Nase hochziehen oder senken. Ruckelfreier wurde es komischer Weise erst, als ich den Rigidbody auf "Extrapolate" gesetzt habe. Jedenfalls fällt das Ergebnis insgesamt leider etwas mäßig aus. Wie Malzbie schon vermutet hat, wird der Neigungswinkel recht ruckelig ausgegeben bzw. scheint das Rotieren durch neue Abfragen kontinuierlich auf neue Werte zu kommen. Allerdings sind die maximal Werte trotzdem fixiert, denn das Bike rotiert nicht komplett um die eigene Achse, sondern macht nur permanent einen "Hochstarter"...

Jetzt bin ich etwas klüger, aber stehe eigentlich wieder am Anfang, wo ich mich gefragt habe, wie ich das Neigen im RaycastHit-Script (Hoverpoints) integriert bekomme. Eigentlich bin ich vom Script und dem aktuellen Ergebnis schon begeistert, wenn es sich nur etwas sauberer umsetzen lassen würde. Kennt jemand vielleicht eine andere Herangehensweise ? Bin für jede Anregungen dankbar.

 

Den aktuellen Stand vom Script leg ich mal in den Anhang.

HoverCarControl.cs

Share this post


Link to post
Share on other sites

Kleines Update: Wie es aussieht, scheint nur noch eine Gamepad-Achse Probleme zu machen. Mit der Tastur ist die Steuerung schon relativ akzeptabel. Beim Gamepad haben auch höhere Deadzone-Werte nichts daran geändert, dass die Steuerung Aussetzer hat. Es ist nur komisch, dass die Steurung per Tastatur keine Probleme macht. Ich werde da wohl noch weiter tüftel und probieren müssen. Ich kann auch verstehen, das hier niemand die Zeit und Laune hat seine Nase in das Kuddelmuddel zu stecken 🙂 Hier ein Video, erst mit Tastatur gespielt, dann ab 0:58 mit Gamepad.

 

Share this post


Link to post
Share on other sites

Na, das ist doch schon mal was. Das mit dem Gamepad findest du auch noch raus. Kannst dir ja auch da mal die Controller-Werte ausgeben lassen um zu sehen, wann und warum es da aussetzer gibt.

Zeit ist immer so eine Sache und ich finde gut, dass du Verständniss dafür hast. Ich habe nämlich momentan kaum Zeit. :)
 

Share this post


Link to post
Share on other sites

Hab es tatsächlich noch rausgefunden: In den Input-Einstellungen war die Feinheit (Sensitivity) der Achse mit einen Wert von 960 versehen. Das erklärt, warum die Lenkung sich wie ein aufgeschrecktes Huhn mit einer Kanne Kaffe Intus verhielt. 🙂 Nochmals danke für die Hilfe.

Share this post


Link to post
Share on other sites

Kaum funktioniert eine Sache, steht man vor dem nächsten Rätzel:

Nun möchte ich ignore raycast für die Wände verwenden, damit das Fahrzeug nicht an Wänden hochklettert.

Der Unitylayermanager hat bereits eine (build-in) Ebene namens "Ignore Rasycast". Ich würde jetzt erwarte, dass damit einfach erledigt ist, aber anscheinend muss man zusätzlich noch ein Script auf die Wände legen. Dazu findet man reichlich Anleitungen im Internet, die alle beschreiben, wie man die Ebene wählt:

using UnityEngine;
using System.Collections;

public class walls : MonoBehaviour
{
  	public GameObject[] hoverPoints;
//int layerMask = 1 << 9;
        
void start ()
{
//gameObject.layer = LayerMask.NameToLayer ("Ignore Raycast");
gameObject.layer = LayerMask.NameToLayer ("walls");
}

Leider geht niemand darauf ein, was im 2. Teil des Scriptes passiert. Werden hioer die Raycast abgeschaltet ?

void Update ()
{
    // Bit shift the index of the layer (8) to get a bit mask
    int layerMask = 1 << 9;   //ebenen auswahl(9)
	//layerMask = ~layerMask; //ebene inventrieren
    
	if (Physics.Raycast(hoverPoint.transform.position, -Vector3.up, out hit,hoverHeight, layerMask))
			{
				//body.AddForceAtPosition(Vector3.up * hoverForce* (1.0f - (hit.distance / hoverHeight)), hoverPoint.transform.position);
				//grounded = true;
			}
}
}

Das war mein halbfertiger Ansatz. Muss nun noch die 4 Hoverpoints vom Fahrzeug hinzufügen ? Oder wie werden die Raycast der Wände ignoriert ?

Share this post


Link to post
Share on other sites

Hier ist erstmal eine Erklärung zu NameToLayer, und warum man für LayerMasks lieber GetMask verwenden will. Am allerliebsten sollte man aber meistens einfach eine LayerMask deklarieren und sie im Editor einstellen.

Zur eigentlichen Frage: Die Raycast-Methode hat einen Haufen "Überladungen", das sind unterschiedliche Konfigurationen von Parametern. Wenn du auf der Seite zum Raycast schaust, siehst du dort diese unterschiedlichen Konfigurationen. Einige davon haben eben einen "layerMask"-Parameter und wenn du eine dieser Überladungen benutzt, dann ignoriert der Raycast alle Objekte auf allen Layern, die nicht Teil der LayerMask sind.

Share this post


Link to post
Share on other sites
vor 18 Stunden schrieb Sascha:

Am allerliebsten sollte man aber meistens einfach eine LayerMask deklarieren und sie im Editor einstellen.

Also, lege ich alle Wände in ein GameObjekt, dem ich den Layer "Ignore Raycast" vergebe und gut ?

Share this post


Link to post
Share on other sites

LayerMask im EditorDas ist nicht, was ich meine. Eine LayerMask ist nicht dasselbe wie ein Layer. Ein Layer ist eine einzelne Nummer, und jedes Objekt hat eine solche Nummer uns ist damit auf einem Layer. Eine LayerMask ist ein 32-Bit-Integer, das sind 32 Bits, die entweder 0 oder 1 als Wert haben. Damit kannst du dann für alle (bis zu 32) Layer, die dein Projekt hat, angeben, ob er ignoriert werden soll oder nicht.

Habe aber mal gerade nachgeschaut und wenn man dem Raycast-Aufruf keine LayerMask mitgibt, dann werden standardmäßig alle Layer beachtet außer dem "Ignore Raycast"-Layer. Du kannst also tatsächlich deine Wände darauf einstellen, darauf achten, dass dein Methodenaufruf keine LayerMask mitkriegt und dann werden die Wände ignoriert. Denke aber daran, dass es egal ist, was irgendein übergeordnetes Objekt für einen Layer hat - Das GameObject mit dem Collider muss selbst auf dem richtigen Layer sein.

Share this post


Link to post
Share on other sites

Hm, danke. Falls ich es richtig verstehe könnte das der Grund sein, warum ich an den Wänden hochfahren kann, obwohl "Ignore Raycast gewählt ist". Denn mein Script verwendet eine LayerMask, damit es sich nicht selbst Raycasted. Das ist ganz schön verwirrend und geht leider bereits weit über meine Programmierkenntnisse... ich denke ich muss da noch ein paar Nachhilfestunden nehmen, bis eine Wand Raycast ignoriert.

Im Anhang ist der aktuelle Stand vom Fahrzeug-Script.

HoverBikeControl.cs

Share this post


Link to post
Share on other sites

Ich hab es jetzt ganz einfach gelöst: Das Script ignoriert bereits den Layer "Vehicle". Darauf habe ich nun auch die Wände eingestellt und gut. Irgendwann sollte ich die Wände wohl auf einen seperaten Layer setzen, aber momentan langt mir das zum Testen. Nochmal danke für die Tipps!

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
Sign in to follow this  

×
×
  • Create New...