Jump to content
Unity Insider Forum

C# Player Controlller für Space Ship, Maus ruckelt


KaBau

Recommended Posts

Hallo, ich programiere ein Spiel als Top-Down Shooter. Der Player soll entweder über Maus, oder Tastatur gesteuert werden. Die Grenzen des Spielfeld haben ich mit Max und Min Werte eingestellt. Anbei ein Auszug aus dem Script:   

	float plyMoveHorizontal;
    float plyMoveVertical;
    float plyMouseHorizontal;
    float plyMouseVertical;
    public float plyXMin = -9.5f;
    public float plyXMax = 9.5f;
    public float plyZMin = -6.0f;
    public float plyZMax = 23.5f;
    public float plyMoveSpeed = 0.35f;
    public float plyMouseSpeedVertical = 1.5f

    void FixedUpdate()
    {
        // Eingabeabfrage Maus, ansonsten Tastatur. Anmerkung: Maus ruckelt noch.
        if (Input.GetAxis("Mouse X") != 0 || Input.GetAxis("Mouse Y") != 0)
        {
            plyMoveHorizontal = Input.GetAxis("Mouse X");
            plyMoveVertical = Input.GetAxis("Mouse Y") * plyMouseSpeedVertical;
        }
        else
        {
            plyMoveHorizontal = Input.GetAxis("Horizontal");
            plyMoveVertical = Input.GetAxis("Vertical");
        }

         // Abfrage Bewegungsrichtung und ob Lage Player kleine/größer als Max/Min Werte, dann Bewegung.
        if (plyMoveHorizontal > 0 && transform.position.x <= plyXMax)
        {
            transform.Translate(Vector3.right * plyMoveSpeed);
        }

.... die anderen Achsen / Grenzen werden entsprechend der letzten if Abfrage behandelt.

Mein Problem: bei der Mausbewegung haben ich gegenüber der Tastaturbewegung ein Ruckeln. Wie kann ich das unterbindnen?

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Alle Input-Abfragen in die Update-Methode verschieben. Die FixedUpdate-Methode wird nur im "Physikzyklus" aufgerufen (50 FPS). Daher wird die Mausposition azyklisch zu der tatsächlichen FPS (dynamisch oder 60) ausgewertet und dies kann zu Rucklern führen. Wenn dein Spieler keinen Rigidbody hat, dann kannst du die Verschiebung des Spielers auch in die Update- legen, ansonsten in die FixedUpdate-Methode.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Wow, superschnelle Antwort. Danke.

Ich habe die Abfragen in die Update-Methode geschoben. Es ruckelt noch immer.

Inzwischen ist mir foldender Gedanke gekommen: Maus und Vector3.right ... verträgt sich eventuell nicht, weil dabei nur das Versetzten um eine Einheit erfolgt, aber nicht das Erreichen einen neuen Ziel, welches in der FixedUpdate-Methode mit Zwischenschritten ermittelt wird (weis ich nicht, rate ich aber mal). Somit habe ich die eigendliche Bewegung etwas umgeschrieben.

Zusammenfassung:

- Variablen wie bisher

- Abfrage Eingabe Maus oder Tastatur wie von Zer0Cool geschrieben in die Update-Methode

- Abfrage Bewegungsrichtung und Lage Player wie bisher

- Bewegung in zwei eigene Methoden ausgelagert: 1x für Horizontal, 1x für Vertical

- die eigendliche Bewegung nicht mehr mit "Vector3.right ...", sondern durch Angabe eines Vector3 Zielpunkt.

Script (ohne Variblen, die sind geblieben):

private void Update()
    {
        // Eingabeabfrage Maus, ansonsten Tastatur.
        if (Input.GetAxis("Mouse X") != 0 || Input.GetAxis("Mouse Y") != 0)
        {
            plyMoveHorizontal = Input.GetAxis("Mouse X");
            plyMoveVertical = Input.GetAxis("Mouse Y") * plyMouseSpeedVertical;
        }
        else
        {
            plyMoveHorizontal = Input.GetAxis("Horizontal");
            plyMoveVertical = Input.GetAxis("Vertical");
        }
    }

    void FixedUpdate()
    {
        // Abfrage Bewegungsrichtung und ob Lage Player kleine/größer als Max/Min Werte, dann Bewegung.
        if (plyMoveHorizontal > 0 && transform.position.x <= plyXMax)
        {
            PlyTransformHorizontal();
            return;
         }

        if (plyMoveHorizontal < 0 && transform.position.x >= plyXMin)
        {
            PlyTransformHorizontal();
            return; ;
         }

        if (plyMoveVertical > 0 && transform.position.z <= plyZMax)
        {
            PlyTransformVerical();
            return;
            // transform.Translate(Vector3.forward * plyMoveSpeed);
        }

        if (plyMoveVertical < 0 && transform.position.z >= plyZMin)
        {
            PlyTransformVerical();
            return;
         }
    }

    void PlyTransformHorizontal()
    {
        Vector3 plyMovement = new Vector3(plyMoveHorizontal, 0.0f, 0.0f);
        transform.Translate(plyMovement * plyMoveSpeed);
    }

    void PlyTransformVerical()
    {
        Vector3 plyMovement = new Vector3(0.0f, 0.0f, plyMoveVertical);
        transform.Translate(plyMovement * plyMoveSpeed);
    }

Ich musste die Horizontale und Verticale Bewegung trennen, weil ansonsten der Player doch aus dem Bild verschwindet, wenn beide Richtungen gleichzeitig eingegeben werden.

Ob das "return;" notwendig ist, weis ich nicht.

Grundsätzlich bewegt sich der Player nun wie von mir gewünscht, ich muss nur noch die Mausgeschwindigkeit erhöhen.

Danke.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Dein Code sieht auch noch nicht Frameratenunabhängig aus, du solltest noch "Time.deltaTime" einbauen. Ich habe deinen Code nur flüchtig überfolgen, daher kann ich nicht sagen, ob deine Vorgehensweise generell korrekt ist, aber dies würde ich einbauen (obwohl evtl. nicht notwendig, da du bereits in der FixedUpdate-Methode bist). 

 void PlyTransformHorizontal()
    {
        Vector3 plyMovement = new Vector3(plyMoveHorizontal, 0.0f, 0.0f);
        transform.Translate(plyMovement * plyMoveSpeed * Time.deltaTime);
    }

    void PlyTransformVerical()
    {
        Vector3 plyMovement = new Vector3(0.0f, 0.0f, plyMoveVertical);
        transform.Translate(plyMovement * plyMoveSpeed * Time.deltaTime);
    }

Das Ruckeln kann auch von der Kamera kommen, aktuell sehe ich nur den Code für die Bewegung des Spielers, wenn deine Kamera direkt am Spieler hängt, könnte dies auch Problematisch sein, da du den Spieler ja im Physikzyklus bewegst, die Kamera aber im normalen Updatezyklus agiert!

Besser wäre es du entkoppelst die Kamera vom Spieler und verpasst ihr ein "Follow"-Skript. 
Siehe hier:

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ich hatte eben zu schnell  geantwortet:

"return;" muss raus, da ansonsten bei der kleinsten Bewegung Horizontal die Vertikalbewegung gar nicht mehr erfasst wird.

Die Mausgeschwindigkeit habe ich nun wie folgt umgesetzt:

plyMoveHorizontal = Input.GetAxis("Mouse X") * plyMouseSpeed;
plyMoveVertical = Input.GetAxis("Mouse Y") * plyMouseSpeed *1.5f;

Mit einem Wert der Variable "plyMouseSpeed" von 2f ist die Bewegung für mich gut.

Zur Antwort von Zer0Cool:

Mit "Time.deltatime" ist die Bewegung ersteinmal irre langsam. Ich habe die Variable "plyMoveSpeed" von 0.35f auf 17f erhöht. Dann läuft es wieder flüssig.

Grundsätzlich an alle die hier mitmachen (ist mein erstes eigenes Thema): DANKE. Toll wie ihr so einem Anfänger wie mich unterstützt.

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 34 Minuten schrieb Zer0Cool:

Das Ruckeln kann auch von der Kamera kommen, aktuell sehe ich nur den Code für die Bewegung des Spielers, wenn deine Kamera direkt am Spieler hängt, könnte dies auch Problematisch sein, da du den Spieler ja im Physikzyklus bewegst, die Kamera aber im normalen Updatezyklus agiert!

Besser wäre es du entkoppelst die Kamera vom Spieler und verpasst ihr ein "Follow"-Skript.

Die Kamera hat ein komplett eigenes Script, welches genauso aufgebaut ist wie das Player Script. Nur habe ich die Vertikalbewegung weggelassen und die Grenzen und Bewegungsgeschwindigkeiten etwas geringer gesetzt. Die Kamera bewegt sich nicht vertikal, da der Hintergrund sich bewegt.

Dadurch habe ich ein leichtes Hin- und Herwandern der Kamera und den Player, welcher sich in dem Sichtfeld bewegt. Im 3D ergeben sich somit schöne Effekte durch die Objekte im Hintergrund, welche verschieden weit von der Kamera weg sind.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ich habe deinen Controller mal komplett zerlegt, vereinfacht und neu zusammengebaut, ich vermute du möchtest nur vertikale oder horizontale Bewegungen zulassen. Hier das Ergebnis. Ein Problem des alten Controllers war, das die horizontale Bewegung gegenüber der vertikalen Bewegung bevorzugt wurde.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ControllerTopDown : MonoBehaviour {

    float plyMoveHorizontal;
    float plyMoveVertical;
    float plyMouseHorizontal;
    float plyMouseVertical;
    public float plyXMin = -9.5f;
    public float plyXMax = 9.5f;
    public float plyZMin = -6.0f;
    public float plyZMax = 23.5f;
    public float plyMoveSpeed = 17.0f;

  void Update()
    {
        // Eingabeabfrage Maus, ansonsten Tastatur.
        if (Input.GetAxis("Mouse X") != 0 || Input.GetAxis("Mouse Y") != 0)
        {
            plyMoveHorizontal = Input.GetAxis("Mouse X");
            plyMoveVertical = Input.GetAxis("Mouse Y");
        }
        else
        {
            plyMoveHorizontal = Input.GetAxis("Horizontal");
            plyMoveVertical = Input.GetAxis("Vertical");
        }
    }

    void FixedUpdate()
    {
        if (Mathf.Abs(plyMoveHorizontal) > Mathf.Abs(plyMoveVertical)) PlyTransformHorizontal();
        else PlyTransformVerical();
    }

    void PlyTransformHorizontal()
    {
        if ((transform.position.x >= plyXMin) && (transform.position.x <= plyXMax))
        {
            Vector3 plyMovement = new Vector3(plyMoveHorizontal, 0.0f, 0.0f);
            transform.Translate(plyMovement * plyMoveSpeed * Time.deltaTime);
        }
    }

    void PlyTransformVerical()
    {
        if ((transform.position.z >= plyZMin) && (transform.position.z <= plyZMax))
        {
            Vector3 plyMovement = new Vector3(0.0f, 0.0f, plyMoveVertical);
            transform.Translate(plyMovement * plyMoveSpeed * Time.deltaTime);
        }
    }

}

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor einer Stunde schrieb Zer0Cool:

ich vermute du möchtest nur vertikale oder horizontale Bewegungen zulassen.

Es darf auch gerne eine gleichzeitige schräge Bewegung erfolgen.
Ich habe dein Script ausprobiert (sorry das ich mich wiederhole: ich finde deinen Einsatz klasse): dabei gibt es bei einer gleichzeitigen Bewegung nach schräg oben (als Beispiel) eine Art "Treppeneffekt". Der Player macht immer eine mini Bewegung nach links und dann eine mini Bewegung nach oben kurz hintereinander.
Ich kenne mich übrigends noch nicht mit den "Mathf" Funkionen aus.

Zu

vor einer Stunde schrieb Zer0Cool:

void PlyTransformHorizontal()

{

if ((transform.position.x >= plyXMin) && (transform.position.x <= plyXMax))

}

Dabei passiert folgendes: der Player bewegt sich immer etwas über die Min / Max Werte hinaus. Nun bleibt der Player hier stecken, weil er nicht mehr zwischen dem im Script genannten Min / Max Bereich ist. Ich habe es ausprobiert, wer selber eine solche Lösung für sich nutzen möchte sollte folgendes eingeben:

void PlyTransformHorizontal()
    {
        if ((plyMoveHorizontal > 0 && transform.position.x <= plyXMax) || (plyMoveHorizontal < 0 && transform.position.x >= plyXMin))
    {

Dabei kann der Player etwas ausserhalb der Min Max Grenze kommen und kann dann doch wieder zurück bewegt werden.
 

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

So, und zum Abschluss mein gesamtes Script, falls jemand seinen Player so ähnlich bewegen möchte:
 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlyMove : MonoBehaviour
{
    float plyMoveHorizontal;
    float plyMoveVertical;
    float plyXMin = -9f;
    float plyXMax = 9f;
    float plyZMin = -6.0f;
    float plyZMax = 23.5f;
    float plyMoveSpeed = 17f;
    float plyMouseSpeed = 1.2f;
    float plyMouseSpeedVertical = 1.5f; // damit bei einen hochkant liegenden Spielbereich die Maus sich noch schneller bewegt.

    private void Update()
    {
        // Eingabeabfrage Maus, ansonsten Tastatur.
        if (Input.GetAxis("Mouse X") != 0 || Input.GetAxis("Mouse Y") != 0)
        {
            plyMoveHorizontal = Input.GetAxis("Mouse X") * plyMouseSpeed;
            plyMoveVertical = Input.GetAxis("Mouse Y") * plyMouseSpeed * plyMouseSpeedVertical;
        }
        else
        {
            plyMoveHorizontal = Input.GetAxis("Horizontal");
            plyMoveVertical = Input.GetAxis("Vertical");
        }
    }

    void FixedUpdate()
    {
        // Abfrage Bewegungsrichtung und ob Lage Player kleine/größer als Max/Min Werte, dann Bewegung in eigener Methode.
        if ((plyMoveHorizontal > 0 && transform.position.x <= plyXMax) || (plyMoveHorizontal < 0 && transform.position.x >= plyXMin))
        {
            PlyTransformHorizontal();
        }

        if ((plyMoveVertical > 0 && transform.position.z <= plyZMax) || (plyMoveVertical < 0 && transform.position.z >= plyZMin))
        {
            PlyTransformVerical();
        }
    }

    void PlyTransformHorizontal()
    {
        Vector3 plyMovement = new Vector3(plyMoveHorizontal, 0.0f, 0.0f);
        transform.Translate(plyMovement * plyMoveSpeed * Time.deltaTime);
    }

    void PlyTransformVerical()
    {
        Vector3 plyMovement = new Vector3(0.0f, 0.0f, plyMoveVertical);
        transform.Translate(plyMovement * plyMoveSpeed * Time.deltaTime);
    }
}

Im Anhang ein kleiner Eindruck, wie es nun aussieht. Das zu sehende Ruckeln kommt wohl von der 24er Bildrate beim Aufnehmen. Das Rotieren des Schiff ist in einem eigenen Script ausgelagert, ebenso wie die Bewegung der Kamera. Zuerst die Bewegung mit Tasten, danach die Bewegung mit der Maus.

Später werde ich mich noch mit der Touchbewegung auseinandersetzten. Aber ersteinmal kommt das Leveldesign dran.

PlayerBewegung.mp4

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ja, die IF-Abfrage mit der unteren Bedingung kann raus (hast du ja schon gemacht), wenn du auch eine seitliche Bewegung zulassen möchtest, ich dachte der Spieler soll sich nicht diagonal bewegen können:

if (Mathf.Abs(plyMoveHorizontal) > Mathf.Abs(plyMoveVertical) // Kann raus

Mich wundert nur noch, warum du "plyMouseSpeedVertical" brauchst, sollte eigentlich nicht notwendig sein, da die Bewegung in H und V gleich sein sollte auch ohne diesen Faktor.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ich habe für die vertikale Richtung die Variable "plyMouseSpeedVertical" eingesetzt um bei meinem hochkant angeordneten Spiel die Bewegung der Maus auf dem Untergrund kleiner zu halten. Eine Bewegung nach Links bzw. Rechts kann vom Spieler einfacher getätigt werden als nach Oben bzw. Unten. Somit wollte ich für Oben und Unten die Playerbewegung erhöhen.

Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 1 month later...
Am 4.1.2018 um 18:46 schrieb KaBau:

Später werde ich mich noch mit der Touchbewegung auseinandersetzten

So, habe ich nun gemacht. Nach vielen Versuchen bin ich kurz zur Lean Touch Steuerung gekommen, hatte dabei aber das Problem, dass ich nicht wusste, wie ich die Scripte anpassen musste, damit z.B. mein Raumschiff in den Grenzen des Bildschirm blieb. Zudem benötigte ich eine Steuerung nur in x Richtung für die Camera und wusste nicht, wie ich diese einzelne Richtung aus den vorgegebenen Scripten rausfiltern sollte.
Als Grundlage zur Anpassung meiner Touch Steuerung habe ich folgendes genommen:

https://docs.unity3d.com/ScriptReference/Input.GetTouch.html

Für den Fall, dass jemand selber ein solches Bewegungsscript benötigt anbei mein Script hierfür. Ich habe mein ursprüngliches Script wie folgt abgeändert:

public class PlyMoveTouch : MonoBehaviour
{
    float plyMoveHorizontal;
    float plyMoveVertical;
    float plyXMin = -8.0f;
    float plyXMax = 8.0f;
    float plyZMin = -4.4f;
    float plyZMax = 21f;
    public float plyMoveSpeed = 1.0f;

    private void Start()
    {
        plyMoveHorizontal = 0.0f;
        plyMoveVertical = 0.0f;
    }

    void Update()
    {
        if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved)
        {
            plyMoveHorizontal = Input.GetTouch(0).deltaPosition.x;
            plyMoveVertical = Input.GetTouch(0).deltaPosition.y;

            if ((plyMoveHorizontal > 0 && transform.position.x <= plyXMax) || (plyMoveHorizontal < 0 && transform.position.x >= plyXMin))
            {
                PlyTransformHorizontal();
            }

            if ((plyMoveVertical > 0 && transform.position.z <= plyZMax) || (plyMoveVertical < 0 && transform.position.z >= plyZMin))
            {
                PlyTransformVerical();
            }
        }
    }
    
    void PlyTransformHorizontal()
    {
        Vector3 plyMovement = new Vector3(plyMoveHorizontal, 0.0f, 0.0f);
        transform.Translate(plyMovement * plyMoveSpeed * Time.deltaTime);
    }

    void PlyTransformVerical()
    {
        Vector3 plyMovement = new Vector3(0.0f, 0.0f, plyMoveVertical);
        transform.Translate(plyMovement * plyMoveSpeed * Time.deltaTime);
    }
}

Ob ich die Start Metode überhaupt benötige weis ich nicht (habe es auch nicht ohne versucht). Es erschien mir aber logisch, ersteinmal die Werte auf 0.0 zu setzen.

Die Bewegung des Schiff habe ich aus der FixedUpdate Metode rausgenommen, damit die Bewegung noch innerhalb der ersten If Abfrage liegt (wird gerade der Bildschirm berührt?). Ansonsten wurde das Schiff auch nach dem Loslassen des Bildschirm weiter bewegt.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Zitat

Ob ich die Start Metode überhaupt benötige weis ich nicht (habe es auch nicht ohne versucht). Es erschien mir aber logisch, ersteinmal die Werte auf 0.0 zu setzen.

Brauchst du nicht, du kannst sie einfach weglassen (dann sind sie auch auf 0) oder für einen guten Stil:

public class PlyMoveTouch : MonoBehaviour
{
    float plyMoveHorizontal = 0.0f;
    float plyMoveVertical = 0.0f;
Zitat

Die Bewegung des Schiff habe ich aus der FixedUpdate Metode rausgenommen, damit die Bewegung noch innerhalb der ersten If Abfrage liegt (wird gerade der Bildschirm berührt?). Ansonsten wurde das Schiff auch nach dem Loslassen des Bildschirm weiter bewegt.

Die FixedUpdate-Methode musst du nur verwenden, wenn dein Raumschiff einen RB oder Collider hat und damit auf Physik reagieren soll.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Das "Nachbewegen" kannst du ganz leicht unterbinden, wenn du FixedUpdate weiterhin verwenden möchtest:

    private void Update()
    {
        plyMoveHorizontal = 0f;
        plyMoveVertical = 0f;
        // Eingabeabfrage Maus, ansonsten Tastatur.
        if (Input.GetAxis("Mouse X") != 0 || Input.GetAxis("Mouse Y") != 0)
        {
            plyMoveHorizontal = Input.GetAxis("Mouse X") * plyMouseSpeed;
            plyMoveVertical = Input.GetAxis("Mouse Y") * plyMouseSpeed * plyMouseSpeedVertical;
        }
        else
        {
            plyMoveHorizontal = Input.GetAxis("Horizontal");
            plyMoveVertical = Input.GetAxis("Vertical");
        }
    }

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 2 weeks later...
Am 4.3.2018 um 16:26 schrieb Zer0Cool:

Die FixedUpdate-Methode musst du nur verwenden, wenn dein Raumschiff einen RB oder Collider hat

Ja, hat es. Somit habe ich nun in der Update-Methode ein bool touchYes Variable gesetzt, welche ich in der FixedUpdate-Methode abfrage. Klappt jetzt.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Am 4.3.2018 um 16:26 schrieb Zer0Cool:

Die FixedUpdate-Methode musst du nur verwenden, wenn dein Raumschiff einen RB oder Collider hat und damit auf Physik reagieren soll.

Diese Sache mit "FixedUpdate nur wenn Rigidbody im Spiel" ist ein Aberglaube, den Leute wirklich nicht weiter verbreiten sollten.

FixedUpdate simuliert einen Zyklus mit konstanter Framerate. Es ist immer dann praktisch, wenn etwas auf jedem Rechner gleichermaßen laufen soll. Der Nutzen davon geht weit über Physikberechnungen hinaus.

Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 2 years later...

Archiviert

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

×
×
  • Neu erstellen...