Jump to content
Unity Insider Forum

Steuerungsprobleme


Kojote

Recommended Posts

Grüße!

Hab mir jetzt mal vorgenommen mein Zweitprojekt zu Ende zu bringen, da ich bei meinem Hauptprjekt gerade warten muss, bis ich weiter komme. Ich habe hier ein kleines Problem mit einer Steuerung. Es geht um ein kleines, Spiel, was man sich wie ein Schachbrett vorstellen kann. Der Spieler kann Figuren auf dem Spielfeld positionieren, die je nach Felduntergrund dann andere Dinge machen sollen. Kommt eine Spielfigur z.B. auf Feld D4 soll die Spielfigur gerade aus laufen. Kommt die Figur dann auf Feld D5, soll sie abbiegen, ect.

Problem ist nun, dass meiner bisherigen Steuerung ich immer abfragen muss, wo der Spieler gerade ist. Gibt es eine Möglichkeit genau festzulegen, wie weit eine Spielfigur laufen soll?

Nehmen wir mal an, er soll 50 Unityeinheiten laufen. Bräuchte also eine Möglichkeit, wo ich eine Methode starte, die sagt laufe 50 Unityeinheiten, wenn du dies geschafft hast, gib einen Rückgabewert und kontrolliere nun, auf welchem Feld du stehst. Je nach Feld, starte eine andere Methode.

Dieser Rückgabewert bereitet mir gerade Probleme, wann weiß ich, wann er mit dem laufen oder der Drehung fertig ist?

Bisher mache ich das in der Update Methode und die sieht ziemlich vollgepackt und vor allem unübersichlich aus. Gern harkts auch mal, weil sich Prozesse überschneiden.

Habt ihr da eine Idee für mich?

Grüße Kojote

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hallo,

Hab mal so was ähnliches gemacht, habe auf die Felder Trigger gesetzt und und diese in einem switch Block abgefragt und von dort in die entsprechenden Routinen oder Coroutinen gesprungen.

Mit einem switch Block geht das sehr elegant ist nicht so unübersichtlich wie verschachtelte if() Blöcke.

Weiß nicht ob du so was gemeint hast aber das wäre mal meine Idee.

 

Gruß Jog

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hallo,

Ich habe in den Routinen mit Temporeren  Variablen die Positions und Rotations Werte verglichen wenn diese die gewünschten werte erreicht hatten bin ich dann aus der Routine wieder raus gesprungen und einen bool wert übergeben. 

 

 

Gruß Jog

Link zu diesem Kommentar
Auf anderen Seiten teilen

Wäre auch eine gute Anwendungsmöglichkeit für eine Coroutine:

using UnityEngine;
using System.Collections;

public class UnitMover : MonoBehaviour
{
    public  float speed = 2.0f;

    private IEnumerator coroutine;
    private bool ActionRunning = false;

    void Update()
    {
        if (ActionRunning)
        {
            transform.Translate(Vector3.forward * Time.deltaTime * speed); // Bewegt das transform vorwärts
        }
        else if (Input.GetMouseButtonDown(0)) // Keine Coroutine oder Aktion aktiv
        {
            coroutine = RunUnits(5); // Einheit 50 nach vorn bewegen
            StartCoroutine(coroutine); // Starten
        }
    }

    // Prüft alle 0.1 Sekunden den Zustand
    private IEnumerator RunUnits(int distance)
    {
        ActionRunning = true;
        Vector3 startPosition = this.transform.position;
        bool finished = false;
        do
        {
            //transform.Translate(Vector3.forward * Time.deltaTime); // In die Updatemethode verschoben für eine flüssigere Bewegung
            finished = DistanceCheck(startPosition, distance);
            yield return new WaitForSeconds(.1f);
        } while (!finished);
        ActionRunning = false;
    }

    // Prüft die aktuell zurückgelegte Entfernung
    private bool DistanceCheck(Vector3 startPosition, int distance)
    {
        if (Vector3.Distance(startPosition, transform.position) < distance) return false;
        else return true;
    }
}

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ja, ist halt nur ein Beispiel um die Technik zu zeigen.
Das gute an der Technik ist, man belastet die Update-Methode nicht unnötig und spart so Performance.
Die Update-Methode führt nur die reine Bewegung aus und sonst nichts (damit diese flüssig ist).

Aber "MoveTowards" wäre gut wenn man schon ein Ziel hat.

Man kann dies nun Erweitern für verschiedene Richtungen oder auch um eine bestimmte Rotation zu erreichen.
Dabei wird dann keine Translation ausgeführt, sondern eine Drehung:
https://docs.unity3d.com/ScriptReference/Quaternion.RotateTowards.html

So kann man bspw. auf eine bestimmte Rotation prüfen:

 Quaternion targetAngle = Quaternion.Euler(0, 90, 0);
 float precision = 0.9999f;
 if (Mathf.Abs(Quaternion.Dot(this.transform.rotation, targetAngle)) > precision)
 {
     // do something
 }

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ja, er prüft ja nur jede 1/10 Sekunde und kann da schon etwas übers Ziel hinausschießen xD
Aber wenn du MoveTowards nimmst und die Strecke vorher abmisst, dann kann er nicht über's Ziel hinaus.

 float step = speed * Time.deltaTime;
 Vector3 target = transform.position + Vector3.forward * 50;
 transform.position = Vector3.MoveTowards(transform.position, target, step);
Link zu diesem Kommentar
Auf anderen Seiten teilen

So, ich habs mal mit MoveTowards umgeschrieben:

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

public class Charakter_Steuerung : MonoBehaviour {

    private IEnumerator coroutine;

    private Vector3 startPosition;
    private Vector3 zielPosition;

    public float laufgeschwindigkeit = 1.0f;

    private bool aktionLaufen = false;

    void Update() {
        if (aktionLaufen) {
            transform.Translate(Vector3.MoveTowards(startPosition, zielPosition, Time.deltaTime * laufgeschwindigkeit));
        } else if (Input.GetMouseButtonDown(0)) {
            zielPosition = new Vector3(startPosition.x, startPosition.y, startPosition.z + 2);
            coroutine = LaufenCoroutine(); 
            StartCoroutine(coroutine);
        }
    }

    // ------------------------------------------------------------------------------------
    // LAUFEN: UEBERPRUEFUNG ALLER 0.1 SEKUNDEN OB DIE ZIELPOSITION ERREICHT WURDE
    // ------------------------------------------------------------------------------------
    private IEnumerator LaufenCoroutine() {
        aktionLaufen = true;
        startPosition = this.transform.position;
        bool laufenBeenden = false;
        do {
            laufenBeenden = DistanceCheck(startPosition, zielPosition);
            yield return new WaitForSeconds(0.1f);
        } while (!laufenBeenden);
        aktionLaufen = false;
    }

    // ------------------------------------------------------------------------------------
    // LAUFEN: PRUEFUNG DER DISTANZ ZWISCHEN START UND ZIELPUNKT BEIM LAUFEN
    // ------------------------------------------------------------------------------------
    private bool DistanceCheck(Vector3 startPosition, Vector3 zielPosition) {
        if (Vector3.Distance(zielPosition, transform.position) < 0) {
            return false;
        } else {
            this.transform.position = zielPosition;
            return true;
        }
    }
}

Bin mal gespannt ob es so klappt. Kanns nur noch nicht heraus finden, da Unity heutee nen schlechten Tag hat und dauerhängt. -,-

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 12 Stunden schrieb Zer0Cool:

Ja, er prüft ja nur jede 1/10 Sekunde und kann da schon etwas übers Ziel hinausschießen xD
Aber wenn du MoveTowards nimmst und die Strecke vorher abmisst, dann kann er nicht über's Ziel hinaus.


 float step = speed * Time.deltaTime;
 Vector3 target = transform.position + Vector3.forward * 50;
 transform.position = Vector3.MoveTowards(transform.position, target, step);

Noch mal eine Frage dazu. Mit meiner Version müsste ich ja immer erst abfragen in welche Richtung er schaut um dann je nach dem den Zielpunkt zu ermitteln. Wie ist das bei deinem Forward? Müsste nicht Forward immer für die Richtung gelten, in die er schaut, unabhängig von seiner Ausrichtung? Sprich egal wie er steht, immer der Nase nach?

Dann könnte ich mir schon wieder ein paar Abfragen sparen.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ja, tut es, aber war noch ein kleiner Fehler drin, so wäre es richtig:

float step = speed * Time.deltaTime;
Vector3 target = transform.position + transform.forward * 50;
transform.position = Vector3.MoveTowards(transform.position, target, step);

"target" sind dann 50 Einheiten in Richtung lokaler Vorwärtsachse des transforms (also dahin wohin geschaut wird).

Link zu diesem Kommentar
Auf anderen Seiten teilen

Was heißt eine Distanz? Über die Updatemethode läuft er ja kontinuierlich bis seine Wegstrecke erreicht ist. Kann natürlich sein, daß wenn er eine neue Einheit startet, daß er dann kurz verzögert. Er gelangt ja an sein Ziel und startet dann wieder neu, was natürlich eine kleine Verzögerung am Ziel verursacht. Aber ruckeln sollte es eigentlich nicht. Aber Miniruckler hatte ich auch schon einmal mit einem anderen Skript und da kam es vom Editor, bei einem Build war es dann verschwunden.

Ansonsten poste mal dein(e) aktuelles Skript(e), wo der Ruckler auftritt.

Link zu diesem Kommentar
Auf anderen Seiten teilen

An sich funktioniert das Script sehr gut und macht was es soll. Springen wird gerade bearbeitet und bekommt gerade die Feineinstellung. Es wird bei jeder Bodenplatte erneut abgefragt, was es, über die Trigger Methode, je nach dem führt er eine Aktion aus. Problem ist immer ein Harken, nach dem eine Aktion beendet wurde. Zwischen jeden Laufaktion kommt ein kurzer Stop, genau so beim Drehen und beim Springen. Gerade eben da wo er die alte Aktion beendet und die neue anfängt.

Hier mal das aktuelle Script:

using System.Collections;
using UnityEngine;

public class Charakter_Steuerung : MonoBehaviour {

    public enum wegeTyp : short {
        Unbekannt,
        Drehfeld_Laufrichtung_Positiv_X,
        Drehfeld_Laufrichtung_Negativ_X,
        Drehfeld_Laufrichtung_Positiv_Z,
        Drehfeld_Laufrichtung_Negativ_Z,
        Standardlaufen,
        Sprung_Standard,
        Sprung_Schalter,
        Schwebeplattform,
        Teleporter,
        STOP
    }
    public wegeTyp aktion;

    private IEnumerator coroutine;

    private Rigidbody rigi;

    private Vector3 zielPosition;

    private Quaternion zielRotation;

    public int sprungEntfernung = 0;

    public float abstandFelder = 2.0f;   
    public float laufgeschwindigkeit = 1.0f;
    public float drehgeschwindigkeit = 10.0f;

    public bool aktionLaufen = false;
    private bool aktionDrehen = false;
    private bool aktionSprungStandard = false;
    public bool aktionSprungSchalter = false;


    private void Awake() {
        rigi = this.gameObject.GetComponent<Rigidbody>();
    }

    private void Start() {
        aktionStarten();
    }

    void Update() {
        // Bewegungen fuer die einzelnen Aktionen
        if (aktionLaufen) {
            transform.position = Vector3.MoveTowards(transform.position, zielPosition, laufgeschwindigkeit * Time.deltaTime);
        } else if (aktionDrehen) {
            transform.rotation = Quaternion.RotateTowards(transform.rotation, zielRotation, drehgeschwindigkeit * Time.deltaTime);
        } else if (aktionSprungStandard) {

        } else if (aktionSprungSchalter) {
            float sprungHoehe = 0.85f;
            Vector3 sprungVector = new Vector3(0, sprungHoehe, 0);
            float sprungRichtungskraft = 0.08f;
            Vector3 sprungRichtung = transform.forward * sprungRichtungskraft;
            rigi.velocity = sprungVector + sprungRichtung;
            transform.position = Vector3.MoveTowards(transform.position, zielPosition, laufgeschwindigkeit * Time.deltaTime);
        } else {
            aktionStarten();
        }
    }

    // ------------------------------------------------------------------------------------
    // AKTIONSTARTER
    // ------------------------------------------------------------------------------------

    private void aktionStarten() {
        if(aktion == wegeTyp.Standardlaufen) {
            zielPosition = this.transform.position + Vector3.forward * abstandFelder;
            coroutine = LaufenCoroutine();
            StartCoroutine(coroutine);
        } else if (aktion == wegeTyp.Drehfeld_Laufrichtung_Negativ_X) {
            zielRotation = Quaternion.Euler(0, -90, 0);
            coroutine = DrehenCoroutine();
            StartCoroutine(coroutine);
        } else if (aktion == wegeTyp.Drehfeld_Laufrichtung_Negativ_Z) {
            zielRotation = Quaternion.Euler(0, 180, 0);
            coroutine = DrehenCoroutine();
            StartCoroutine(coroutine);
        } else if (aktion == wegeTyp.Drehfeld_Laufrichtung_Positiv_X) {
            zielRotation = Quaternion.Euler(0, 90, 0);
            coroutine = DrehenCoroutine();
            StartCoroutine(coroutine);
        } else if (aktion == wegeTyp.Drehfeld_Laufrichtung_Positiv_Z) {
            zielRotation = Quaternion.Euler(0, 0, 0);
            coroutine = DrehenCoroutine();
            StartCoroutine(coroutine);
        } else if (aktion == wegeTyp.Schwebeplattform) {
            // Warten bis die Schwebelpattform ihre Aktionen beendet hat
        } else if (aktion == wegeTyp.Sprung_Schalter) {
            zielPosition = this.transform.position + Vector3.forward * 2;
            coroutine = SprungSchalterCoroutine();
            StartCoroutine(coroutine);
        } else if (aktion == wegeTyp.Sprung_Standard) {
            zielPosition = this.transform.position + Vector3.forward * sprungEntfernung;
            coroutine = SprungStandardCoroutine();
            StartCoroutine(coroutine);
        }
    }

    // ------------------------------------------------------------------------------------
    // LAUFEN
    // ------------------------------------------------------------------------------------

    // Ueberpruefung aller 0.1 Sekunden ob die Zielposition erreicht wurde
    private IEnumerator LaufenCoroutine() {
        aktionLaufen = true;
        bool laufenBeenden = false;
        do {
            laufenBeenden = DistanzCheck();
            yield return new WaitForSeconds(0.1f);
        } while (!laufenBeenden);
        aktionLaufen = false;
    }                                                     

    // Pruefen ob das Ziel erreicht wurde
    private bool DistanzCheck() {
        if(transform.position == zielPosition) {
            return true;
        } else {
            return false;
        }
    }

    // ------------------------------------------------------------------------------------
    // DREHEN
    // ------------------------------------------------------------------------------------

    // Ueberpruefung aller 0.1 Sekunden, ob die Zielrotation erreicht wurde
    private IEnumerator DrehenCoroutine() {
        aktionDrehen = true;
        bool drehenBeenden = false;
        do {
            drehenBeenden = DrehenCheck();
            yield return new WaitForSeconds(0.1f);
        } while (!drehenBeenden);
        aktionDrehen = false;
    }

    // Pruefen ob die Zielrotation erreicht wurde
    private bool DrehenCheck() {
        if (Vector3.Distance(transform.position, zielPosition) > 0.05f) {
            transform.position = zielPosition;
            return true;
        } else {
            return false;
        }
    }

    // ------------------------------------------------------------------------------------
    // SPRUNG STANDARD
    // ------------------------------------------------------------------------------------

    // Ueberpruefung aller 0.1 Sekunden ob die Zielposition erreicht wurde
    private IEnumerator SprungStandardCoroutine() {
        aktionSprungStandard = true;
        bool sprungStandardBeenden = false;
        do {
            sprungStandardBeenden = SprungStandardCheck();
            yield return new WaitForSeconds(0.1f);
        } while (!sprungStandardBeenden);
        aktionSprungStandard = false;
    }

    // Pruefen ob das Ziel erreicht wurde
    private bool SprungStandardCheck() {
        if (Vector3.Distance(transform.position, zielPosition) < 0.1f) {
            transform.position = zielPosition;
            return true;
        } else {
            return false;
        }
    }

    // ------------------------------------------------------------------------------------
    // SPRUNG SCHALTER
    // ------------------------------------------------------------------------------------

    // Ueberpruefung aller 0.1 Sekunden ob die Zielposition erreicht wurde
    private IEnumerator SprungSchalterCoroutine() {
        aktionSprungSchalter = true;
        bool sprungSchalterBeenden = false;
        yield return new WaitForSeconds(1.0f);
        do {
            sprungSchalterBeenden = SprungSchalterCheck();
            yield return new WaitForSeconds(0.1f);
        } while (!sprungSchalterBeenden);
        aktionSprungSchalter = false;
    }

    // Pruefen ob das Ziel erreicht wurde
    private bool SprungSchalterCheck() {
        if (Vector3.Distance(transform.position, zielPosition) < 0.1f) {
            //transform.position = zielPosition;
            return true;
        } else {
            return false;
        }
    }

    // ------------------------------------------------------------------------------------
    // AKTION AUSLESEN
    // ------------------------------------------------------------------------------------

    public void OnTriggerEnter(Collider other) {
        if (other.tag == "Standardlaufen") {
            aktion = wegeTyp.Standardlaufen;
        } else if (other.tag == "Drehfeld_Laufrichtung_Positiv_X") {
            aktion = wegeTyp.Drehfeld_Laufrichtung_Positiv_X;
        } else if (other.tag == "Drehfeld_Laufrichtung_Negativ_X") {
            aktion = wegeTyp.Drehfeld_Laufrichtung_Negativ_X;
        } else if (other.tag == "Drehfeld_Laufrichtung_Positiv_Z") {
            aktion = wegeTyp.Drehfeld_Laufrichtung_Positiv_Z;
        } else if (other.tag == "Drehfeld_Laufrichtung_Negativ_Z") {
            aktion = wegeTyp.Drehfeld_Laufrichtung_Negativ_Z;
        } else if (other.tag == "Schwebeplattform") {
            aktion = wegeTyp.Schwebeplattform;
        } else if (other.tag == "Sprung_Schalter") {
            aktion = wegeTyp.Sprung_Schalter;
        } else if (other.tag == "Sprung_Standard") {
            aktion = wegeTyp.Sprung_Standard;
        }
    }
}

EDIT: In der Build Version gibt es auch Ruckler.

Link zu diesem Kommentar
Auf anderen Seiten teilen

War wieder nicht so einfach, da ja auch noch ein Rigidbody dazwischenfunkt und dadurch werden absolute Positionen des Transforms immer leicht verschoben.
Hier die Änderungen, damit es nicht mehr "ruckelt":
- nicht Update() verwenden, sondern FixedUpdate() (weil wir ja einen RB am Spieler hängen haben)
- MoveTowards funktioniert auch nicht, da über diese Funktion eine Verzögerung bei der Bewegung hineinkommt und sie damit nicht mehr "flüssig" ist
- zudem musste ich die Coroutine anpassen und sie nun doch häufiger aufrufen, da ansonsten nicht erkannt wird, wenn der Spieler bereits sein Ziel erreicht hatte
siehe yield return new WaitForFixedUpdate();

Die Coroutine läuft nun im gleichen Zeitintervall wie auch FixedUpdate und dadurch kann es nicht mehr passieren, daß die Coroutine die Zielposition "überspringt" (ist so ähnlich wie wenn ein Geschoss zu schnell fliegt und die Physikengine eine Kollision nicht erkennt).

Ich habe mich nur auf das Laufen konzentriert, kann sein daß für die Drehung ähnliche Sachen umgestellt werden müssen.
Zudem habe ich noch ein Stop-Trigger eingebaut, somit hält der Spieler einfach an...(man kann damit gut überprüfen, ob die vorherige Couroutine auch "sauber" gearbeitet hat)

using System.Collections;
using UnityEngine;

public class Charakter_Steuerung : MonoBehaviour
{

    public enum wegeTyp : short
    {
        Unbekannt,
        Drehfeld_Laufrichtung_Positiv_X,
        Drehfeld_Laufrichtung_Negativ_X,
        Drehfeld_Laufrichtung_Positiv_Z,
        Drehfeld_Laufrichtung_Negativ_Z,
        Standardlaufen,
        Sprung_Standard,
        Sprung_Schalter,
        Schwebeplattform,
        Teleporter,
        STOP
    }
    public wegeTyp aktion;

    private IEnumerator coroutine;

    private Rigidbody rigi;

    private Vector3 zielPosition;

    private Quaternion zielRotation;

    public int sprungEntfernung = 0;

    public float abstandFelder = 2.0f;
    public float laufgeschwindigkeit = 1.0f;
    public float drehgeschwindigkeit = 10.0f;

    public bool aktionLaufen = false;
    private bool aktionDrehen = false;
    private bool aktionSprungStandard = false;
    public bool aktionSprungSchalter = false;


    private void Awake()
    {
        rigi = this.gameObject.GetComponent<Rigidbody>();
    }

    private void Start()
    {
        aktionStarten();
    }

    void FixedUpdate()
    {
        // Bewegungen fuer die einzelnen Aktionen
        if (aktionLaufen)
        {
            //transform.position = Vector3.MoveTowards(transform.position, zielPosition, laufgeschwindigkeit * Time.deltaTime);
            transform.position = transform.position + Vector3.forward * laufgeschwindigkeit * Time.deltaTime;
        }
        else if (aktionDrehen)
        {
            transform.rotation = Quaternion.RotateTowards(transform.rotation, zielRotation, drehgeschwindigkeit * Time.deltaTime);
        }
        else if (aktionSprungStandard)
        {

        }
        else if (aktionSprungSchalter)
        {
            float sprungHoehe = 0.85f;
            Vector3 sprungVector = new Vector3(0, sprungHoehe, 0);
            float sprungRichtungskraft = 0.08f;
            Vector3 sprungRichtung = transform.forward * sprungRichtungskraft;
            rigi.velocity = sprungVector + sprungRichtung;
            transform.position = Vector3.MoveTowards(transform.position, zielPosition, laufgeschwindigkeit * Time.deltaTime);
        }
        else
        {
            aktionStarten();
        }
    }

    // ------------------------------------------------------------------------------------
    // AKTIONSTARTER
    // ------------------------------------------------------------------------------------

    private void aktionStarten()
    {
        if (aktion == wegeTyp.Standardlaufen)
        {
            zielPosition = this.transform.position + Vector3.forward * abstandFelder;
            coroutine = LaufenCoroutine();
            StartCoroutine(coroutine);
        }
        else if (aktion == wegeTyp.Drehfeld_Laufrichtung_Negativ_X)
        {
            zielRotation = Quaternion.Euler(0, -90, 0);
            coroutine = DrehenCoroutine();
            StartCoroutine(coroutine);
        }
        else if (aktion == wegeTyp.Drehfeld_Laufrichtung_Negativ_Z)
        {
            zielRotation = Quaternion.Euler(0, 180, 0);
            coroutine = DrehenCoroutine();
            StartCoroutine(coroutine);
        }
        else if (aktion == wegeTyp.Drehfeld_Laufrichtung_Positiv_X)
        {
            zielRotation = Quaternion.Euler(0, 90, 0);
            coroutine = DrehenCoroutine();
            StartCoroutine(coroutine);
        }
        else if (aktion == wegeTyp.Drehfeld_Laufrichtung_Positiv_Z)
        {
            zielRotation = Quaternion.Euler(0, 0, 0);
            coroutine = DrehenCoroutine();
            StartCoroutine(coroutine);
        }
        else if (aktion == wegeTyp.Schwebeplattform)
        {
            // Warten bis die Schwebelpattform ihre Aktionen beendet hat
        }
        else if (aktion == wegeTyp.Sprung_Schalter)
        {
            zielPosition = this.transform.position + Vector3.forward * 2;
            coroutine = SprungSchalterCoroutine();
            StartCoroutine(coroutine);
        }
        else if (aktion == wegeTyp.Sprung_Standard)
        {
            zielPosition = this.transform.position + Vector3.forward * sprungEntfernung;
            coroutine = SprungStandardCoroutine();
            StartCoroutine(coroutine);
        }
        else if (aktion == wegeTyp.STOP)
        {
            // Tue nix
        }

    }

    // ------------------------------------------------------------------------------------
    // LAUFEN
    // ------------------------------------------------------------------------------------

    // Ueberpruefung aller 0.1 Sekunden ob die Zielposition erreicht wurde
    private IEnumerator LaufenCoroutine()
    {
        aktionLaufen = true;
        bool laufenBeenden = false;
        do
        {
            laufenBeenden = DistanzCheck();
            //yield return new WaitForSeconds(0.05f);
            yield return new WaitForFixedUpdate();
        } while (!laufenBeenden);
        aktionLaufen = false;
    }


    // ------------------------------------------------------------------------------------
    // LAUFEN: PRUEFUNG DER DISTANZ ZWISCHEN START UND ZIELPUNKT BEIM LAUFEN
    // ------------------------------------------------------------------------------------
    private bool DistanzCheck()
    {
        if (Vector3.Distance(zielPosition, transform.position) > 0.01f)
        {
            return false;
        }
        else
        {
            this.transform.position = zielPosition;
            return true;
        }
    }

    // Pruefen ob das Ziel erreicht wurde
    /*
    private bool DistanzCheck()
    {
        if (transform.position == zielPosition)
        {
            return true;
        }
        else
        {
            return false;
        }
    }*/

    // ------------------------------------------------------------------------------------
    // DREHEN
    // ------------------------------------------------------------------------------------

    // Ueberpruefung aller 0.1 Sekunden, ob die Zielrotation erreicht wurde
    private IEnumerator DrehenCoroutine()
    {
        aktionDrehen = true;
        bool drehenBeenden = false;
        do
        {
            drehenBeenden = DrehenCheck();
            yield return new WaitForSeconds(0.1f);
        } while (!drehenBeenden);
        aktionDrehen = false;
    }

    // Pruefen ob die Zielrotation erreicht wurde
    private bool DrehenCheck()
    {
        if (Vector3.Distance(transform.position, zielPosition) > 0.05f)
        {
            transform.position = zielPosition;
            return true;
        }
        else
        {
            return false;
        }
    }

    // ------------------------------------------------------------------------------------
    // SPRUNG STANDARD
    // ------------------------------------------------------------------------------------

    // Ueberpruefung aller 0.1 Sekunden ob die Zielposition erreicht wurde
    private IEnumerator SprungStandardCoroutine()
    {
        aktionSprungStandard = true;
        bool sprungStandardBeenden = false;
        do
        {
            sprungStandardBeenden = SprungStandardCheck();
            yield return new WaitForSeconds(0.1f);
        } while (!sprungStandardBeenden);
        aktionSprungStandard = false;
    }

    // Pruefen ob das Ziel erreicht wurde
    private bool SprungStandardCheck()
    {
        if (Vector3.Distance(transform.position, zielPosition) < 0.1f)
        {
            transform.position = zielPosition;
            return true;
        }
        else
        {
            return false;
        }
    }

    // ------------------------------------------------------------------------------------
    // SPRUNG SCHALTER
    // ------------------------------------------------------------------------------------

    // Ueberpruefung aller 0.1 Sekunden ob die Zielposition erreicht wurde
    private IEnumerator SprungSchalterCoroutine()
    {
        aktionSprungSchalter = true;
        bool sprungSchalterBeenden = false;
        yield return new WaitForSeconds(1.0f);
        do
        {
            sprungSchalterBeenden = SprungSchalterCheck();
            yield return new WaitForSeconds(0.1f);
        } while (!sprungSchalterBeenden);
        aktionSprungSchalter = false;
    }

    // Pruefen ob das Ziel erreicht wurde
    private bool SprungSchalterCheck()
    {
        if (Vector3.Distance(transform.position, zielPosition) < 0.1f)
        {
            //transform.position = zielPosition;
            return true;
        }
        else
        {
            return false;
        }
    }

    // ------------------------------------------------------------------------------------
    // AKTION AUSLESEN
    // ------------------------------------------------------------------------------------

    public void OnTriggerEnter(Collider other)
    {
        if (other.tag == "Standardlaufen")
        {
            aktion = wegeTyp.Standardlaufen;
        }
        else if (other.tag == "Drehfeld_Laufrichtung_Positiv_X")
        {
            aktion = wegeTyp.Drehfeld_Laufrichtung_Positiv_X;
        }
        else if (other.tag == "Drehfeld_Laufrichtung_Negativ_X")
        {
            aktion = wegeTyp.Drehfeld_Laufrichtung_Negativ_X;
        }
        else if (other.tag == "Drehfeld_Laufrichtung_Positiv_Z")
        {
            aktion = wegeTyp.Drehfeld_Laufrichtung_Positiv_Z;
        }
        else if (other.tag == "Drehfeld_Laufrichtung_Negativ_Z")
        {
            aktion = wegeTyp.Drehfeld_Laufrichtung_Negativ_Z;
        }
        else if (other.tag == "Schwebeplattform")
        {
            aktion = wegeTyp.Schwebeplattform;
        }
        else if (other.tag == "Sprung_Schalter")
        {
            aktion = wegeTyp.Sprung_Schalter;
        }
        else if (other.tag == "Sprung_Standard")
        {
            aktion = wegeTyp.Sprung_Standard;
        }
        else if (other.tag == "Stop")
        {
            print("stop");
            aktion = wegeTyp.STOP;
        }

    }
}

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Erste Sahne, ich bin begeistert!  Kann dir gar nicht genug danken! :)

EDIT: Funktioniert leider doch nicht, sorry, wenn ich dich noch ma befragen muss. Egal wie hoch ich den Sicherheitsbereich setze, er schießt ständig übers Ziel hinaus. Bei Standardlaufen wird einfach kein Halt gemacht. Er kommt einfach nicht an den Punkt wo er genau 2 Einheiten hinter sich gebracht hat oder übergeht sie einfach.

Hier mal der aktuelle Code:

using System.Collections;
using UnityEngine;

public class MOTR_Charakter_Steuerung : MonoBehaviour {

    public enum wegeTyp : short {
        Unbekannt,
        Drehfeld_Laufrichtung_Positiv_X,
        Drehfeld_Laufrichtung_Negativ_X,
        Drehfeld_Laufrichtung_Positiv_Z,
        Drehfeld_Laufrichtung_Negativ_Z,
        Standardlaufen,
        Sprung_Standard,
        Sprung_Schalter,
        Schwebeplattform,
        Teleporter,
        STOP
    }
    public wegeTyp aktion;

    private IEnumerator coroutine;

    private Rigidbody rigi;

    private Vector3 zielPosition;

    private Quaternion aktuelleRotation;
    private Quaternion zielRotation;

    public int sprungEntfernung = 0;

    public float abstandFelder = 2.0f;
    public float laufgeschwindigkeit = 1.0f;
    public float drehgeschwindigkeit = 0.5f;

    public bool aktionLaufen = false;
    private bool aktionDrehen = false;
    private bool aktionSprungStandard = false;
    public bool aktionSprungSchalter = false;


    private void Awake() {
        rigi = this.gameObject.GetComponent<Rigidbody>();
    }

    private void Start() {
        aktionStarten();
    }

    void FixedUpdate() {
        // Bewegungen fuer die einzelnen Aktionen
        if (aktionLaufen) {
            transform.position = transform.position + transform.forward * laufgeschwindigkeit * Time.deltaTime;
        } else if (aktionDrehen) {
            transform.rotation = Quaternion.RotateTowards(transform.rotation, zielRotation, drehgeschwindigkeit * Time.deltaTime);
        } else if (aktionSprungStandard) {
            // UNDONE: Sprung einbauen
        } else if (aktionSprungSchalter) {
            float sprungHoehe = 0.85f;
            Vector3 sprungVector = new Vector3(0, sprungHoehe, 0);
            float sprungRichtungskraft = 0.08f;
            Vector3 sprungRichtung = transform.forward * sprungRichtungskraft;
            rigi.velocity = sprungVector + sprungRichtung;
            transform.position = Vector3.MoveTowards(transform.position, zielPosition, laufgeschwindigkeit * Time.deltaTime);
        } else {
            aktionStarten();
        }
    }

    // ------------------------------------------------------------------------------------
    // AKTIONSTARTER
    // ------------------------------------------------------------------------------------

    private void aktionStarten() {
        if (aktion == wegeTyp.Standardlaufen) {
            zielPosition = this.transform.position + Vector3.forward * abstandFelder;
            coroutine = LaufenCoroutine();
            StartCoroutine(coroutine);
        } else if (aktion == wegeTyp.Drehfeld_Laufrichtung_Negativ_X) {
            zielRotation = Quaternion.Euler(0, -90, 0);
            coroutine = DrehenCoroutine();
            StartCoroutine(coroutine);
        } else if (aktion == wegeTyp.Drehfeld_Laufrichtung_Negativ_Z) {
            zielRotation = Quaternion.Euler(0, 180, 0);
            coroutine = DrehenCoroutine();
            StartCoroutine(coroutine);
        } else if (aktion == wegeTyp.Drehfeld_Laufrichtung_Positiv_X) {
            zielRotation = Quaternion.Euler(0, 90, 0);
            coroutine = DrehenCoroutine();
            StartCoroutine(coroutine);
        } else if (aktion == wegeTyp.Drehfeld_Laufrichtung_Positiv_Z) {
            zielRotation = Quaternion.Euler(0, 0, 0);
            coroutine = DrehenCoroutine();
            StartCoroutine(coroutine);
        } else if (aktion == wegeTyp.Schwebeplattform) {
            // Warten bis die Schwebelpattform ihre Aktionen beendet hat
        } else if (aktion == wegeTyp.Sprung_Schalter) {
            zielPosition = this.transform.position + Vector3.forward * 2;
            coroutine = SprungSchalterCoroutine();
            StartCoroutine(coroutine);
        } else if (aktion == wegeTyp.Sprung_Standard) {
            zielPosition = this.transform.position + Vector3.forward * sprungEntfernung;
            coroutine = SprungStandardCoroutine();
            StartCoroutine(coroutine);
        } else if (aktion == wegeTyp.STOP) {
            // Tue nix
        }
    }

    // ------------------------------------------------------------------------------------
    // LAUFEN
    // ------------------------------------------------------------------------------------

    // Ueberpruefung aller 0.1 Sekunden ob die Zielposition erreicht wurde
    private IEnumerator LaufenCoroutine() {
        aktionLaufen = true;
        bool laufenBeenden = false;
        do {
            laufenBeenden = DistanzCheck();
            yield return new WaitForFixedUpdate();
        } while (!laufenBeenden);
        aktionLaufen = false;
    }

    // Prüfen der Distanz zwischen Start und Zielpunkt beim Laufen
    private bool DistanzCheck() {
        if (Vector3.Distance(transform.position, zielPosition) > 0.01f) {
            return false;
        } else {
            Debug.Log(zielPosition);
            this.transform.position = zielPosition;
            return true;
        }
    }

    // ------------------------------------------------------------------------------------
    // DREHEN
    // ------------------------------------------------------------------------------------

    // Ueberpruefung aller 0.1 Sekunden, ob die Zielrotation erreicht wurde
    private IEnumerator DrehenCoroutine() {
        aktionDrehen = true;
        bool drehenBeenden = false;
        do {
            drehenBeenden = DrehenCheck();
            yield return new WaitForFixedUpdate();
        } while (!drehenBeenden);
        aktionDrehen = false;
    }

    // Pruefen ob die Zielrotation erreicht wurde
    private bool DrehenCheck() {
        aktuelleRotation = Quaternion.Euler(0f, this.transform.rotation.eulerAngles.y, 0f);
        float winkel = Quaternion.Angle(aktuelleRotation, zielRotation);
        bool gleicheRotation = Mathf.Abs(winkel) < 1f;
        if (gleicheRotation) {
            return true;
        } else {
            transform.rotation = zielRotation;
            aktion = wegeTyp.Standardlaufen;
            return false;
        }
    }

    // ------------------------------------------------------------------------------------
    // SPRUNG STANDARD
    // ------------------------------------------------------------------------------------

    // Ueberpruefung aller 0.1 Sekunden ob die Zielposition erreicht wurde
    private IEnumerator SprungStandardCoroutine() {
        aktionSprungStandard = true;
        bool sprungStandardBeenden = false;
        do {
            sprungStandardBeenden = SprungStandardCheck();
            yield return new WaitForSeconds(0.1f);
        } while (!sprungStandardBeenden);
        aktionSprungStandard = false;
    }

    // Pruefen ob das Ziel erreicht wurde
    private bool SprungStandardCheck() {
        if (Vector3.Distance(transform.position, zielPosition) > 0.1f) {
            return false;
        } else {
            transform.position = zielPosition;
            return true; 
        }
    }

    // ------------------------------------------------------------------------------------
    // SPRUNG SCHALTER
    // ------------------------------------------------------------------------------------

    // Ueberpruefung aller 0.1 Sekunden ob die Zielposition erreicht wurde
    private IEnumerator SprungSchalterCoroutine() {
        aktionSprungSchalter = true;
        bool sprungSchalterBeenden = false;
        yield return new WaitForSeconds(1.0f);
        do {
            sprungSchalterBeenden = SprungSchalterCheck();
            yield return new WaitForSeconds(0.1f);
        } while (!sprungSchalterBeenden);
        aktionSprungSchalter = false;
    }

    // Pruefen ob das Ziel erreicht wurde
    private bool SprungSchalterCheck() {
        if (Vector3.Distance(transform.position, zielPosition) > 0.1f) {
            return false;
        } else {
            transform.position = zielPosition;
            return true;
        }
    }

    // ------------------------------------------------------------------------------------
    // AKTION AUSLESEN
    // ------------------------------------------------------------------------------------

    public void OnTriggerEnter(Collider other) {
        if (other.tag == "Standardlaufen") {
            aktion = wegeTyp.Standardlaufen;
        } else if (other.tag == "Drehfeld_Laufrichtung_Positiv_X") {
            aktion = wegeTyp.Drehfeld_Laufrichtung_Positiv_X;
        } else if (other.tag == "Drehfeld_Laufrichtung_Negativ_X") {
            aktion = wegeTyp.Drehfeld_Laufrichtung_Negativ_X;
        } else if (other.tag == "Drehfeld_Laufrichtung_Positiv_Z") {
            aktion = wegeTyp.Drehfeld_Laufrichtung_Positiv_Z;
        } else if (other.tag == "Drehfeld_Laufrichtung_Negativ_Z") {
            aktion = wegeTyp.Drehfeld_Laufrichtung_Negativ_Z;
        } else if (other.tag == "Schwebeplattform") {
            aktion = wegeTyp.Schwebeplattform;
        } else if (other.tag == "Sprung_Schalter") {
            aktion = wegeTyp.Sprung_Schalter;
        } else if (other.tag == "Sprung_Standard") {
            aktion = wegeTyp.Sprung_Standard;
        } else if (other.tag == "Stop") {
            aktion = wegeTyp.STOP;
        }
    }
}

Hab mal hier noch mal getestet:

// Prüfen der Distanz zwischen Start und Zielpunkt beim Laufen
    private bool DistanzCheck() {
        if (Vector3.Distance(transform.position, zielPosition) > 0.01f) {
            return false;
        } else {
            Debug.Log("Ziel erreicht!");
            this.transform.position = zielPosition;
            return true;
        }
    }

Das das Ziel erreicht wurde, erreicht er nur ein oder zwei mal. Obwohl er ja nach je 2 Einheiten das liefern müsste. Vermute mal hier sind die Rundungsungenauigkeiten Schuld. Towards funktionierte besser, jedoch leider mit harken. :(


EDIT 2: Ich glaub ich kenne den Fehler, wie er entsteht kann ich noch nicht nachvollziehen. Mit dem Stückchen wird das Ziel des laufens ermittelt:

transform.position = transform.position + transform.forward * laufgeschwindigkeit * Time.deltaTime;

Start: (0.0, 2.0, -4.0) Ziel (0.0, 2.0, -2.0)

Irgendwann erreicht er auch sein Ziel:

Start (0.0, 2.0, -2.0) Ziel (0.0, 2.0, -2.0)

"Ziel erreicht!" wird ausgegeben.

Nun sollte neu berechnet werden, nach dem er nach Positiv X abgebogen ist. Und es kommt das:

Start (0.0, 2.0, -2.0) Ziel (0.0, 2.0, 0.0)

Der Start ist richtig, er befindet sich jetzt bei z = -2. Das Ziel wird aber nun berechnet auf z = 0. Demnach kommt er nie an sein Ziel.

EDIT 3:

Im Endeffekt lag es wirklich an den Ungenauigkeiten, dies habe ich zwar versucht zu umgehen, in dem ich die zeilPosition auf die tranformPosition setzte, aber ganz passte es nie. Habe jetzt heraus bekommen warum:

Vorher:

// ------------------------------------------------------------------------------------
    // LAUFEN
    // ------------------------------------------------------------------------------------

    // Ueberpruefung aller 0.1 Sekunden ob die Zielposition erreicht wurde
    private IEnumerator LaufenCoroutine() {
        aktionLaufen = true;
        bool laufenBeenden = false;
        do {
            laufenBeenden = DistanzCheck();
            yield return new WaitForFixedUpdate();
        } while (!laufenBeenden);
        aktionLaufen = false;
    }

    // Prüfen der Distanz zwischen Start und Zielpunkt beim Laufen
    private bool DistanzCheck() {
        if (Vector3.Distance(transform.position, zielPosition) > 0.01f) {
            return false;
        } else {
         	this.transform.position = zielPosition;
            return true;
        }
    }

Nachher:

// ------------------------------------------------------------------------------------
    // LAUFEN
    // ------------------------------------------------------------------------------------

    // Ueberpruefung aller 0.1 Sekunden ob die Zielposition erreicht wurde
    private IEnumerator LaufenCoroutine() {
        aktionLaufen = true;
        bool laufenBeenden = false;
        do {
            laufenBeenden = DistanzCheck();
            yield return new WaitForFixedUpdate();
        } while (!laufenBeenden);
        aktionLaufen = false;
        this.transform.position = zielPosition;
    }

    // Prüfen der Distanz zwischen Start und Zielpunkt beim Laufen
    private bool DistanzCheck() {
        if (Vector3.Distance(transform.position, zielPosition) > 0.01f) {
            return false;
        } else {
            return true;
        }
    }

Wie man sieht, habe ich in der DistanzCheck-Methode die zielPosition auf die transformPosition gesetzt und danch die Rückmeldung gegeben, dass das Ziel erreicht wurde. Es scheint aber so, dass in dieser kleinen Zeit, in der die Rückmeldung passiert, die Update Methode noch einmal kurz arbeitet und sich noch ein Stück bewegt, ehe mit dem Boolean aktionLaufen das Laufen deaktiviert wird. Darum habe ich nun die Setzung der Position nach dem deaktivieren des laufens, ans Ende der Enumeration gesetzt. Jetzt sind die Werte extrem genau und er reagiert auch wieder richtig.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Archiviert

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

×
×
  • Neu erstellen...