Jump to content
Unity Insider Forum

Wechseln zwischen Lerp und Instant Movement


Garzec

Recommended Posts

Hallo,

ich habe eine Karte mit mehreren Leveln. Der Spieler kann sich auf dieser Karte von Level zu Level bewegen und dann das Level auswählen, auf dem er grade steht. Kann man sich vorstellen wie die Karte von Super Mario

http://s1.dmcdn.net/TU6VI/1280x720-oPd.jpg

Nun ist es so, dass ich mich mit zwei Tasten vorwärts (rechts) und zurück (links) bewegen kann. Drücke ich eine Taste 1x fängt der Spieler über Lerp an, sich von Level A zu Level B zu bewegen. Drücke ich die Taste nochmal bewegt er sich direkt zum Level, also instant.

Nun bin ich das schonmal durchgegangen,

    private bool btnPressed;
    private bool btnPressedAgain;

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.A))
        {
            if (!btnPressed)
            {
                Move(false, false); // smooth links
                btnPressed = true;
            }
            else if (btnPressed && !btnPressedAgain)
            {
                Move(false, true); // instant links
                btnPressedAgain = true;
            }
        }

        if (Input.GetKeyDown(KeyCode.E))
        {
            if (!btnPressed)
            {
                Move(true, false); // smooth rechts
                btnPressed = true;
            }
            else if (btnPressed && !btnPressedAgain)
            {
                Move(true, true); // instant rechts
                btnPressedAgain = true;
            }
        }
    }

    private void Move(bool moveForwards, bool moveInstant)
    {
        // mit moveForwards die Zielposition (targetPosition) bestimmen

        if (moveInstant)
        {
            StopCoroutine(SmoothMovement(targetPosition)); // Lerp stoppen
            InstantMovement(targetPosition); // Direkt positionieren
            btnPressed = false;
            btnPressedAgain = false;
        }
        else
        {
            StartCoroutine(SmoothMovement(targetPosition)); // Lerp Bewegung
            btnPressed = false;
        }
    }

Und habe 2 Probleme:

1. Starte ich in Move die Coroutine, darf 

btnPressed = false

natürlich erst gesetzt werden, wenn diese fertig ist.

2. Während der Bewegung nach links, muss die Bewegung nach rechts blockiert werden. Würde ich nach links drücken und dann nach rechts, würde der Spieler sich instant nach links bewegen. Ebenso würde er durch die beiden unterschiedlichen Bewegungsrichtungen durcheinander kommen.

Die Problematik scheint simpel aber irgendwie gerate ich immer mit der Logik durcheinander 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hab's gerade nochmal getestet, um sicher zu sein.

StopCoroutine(SmoothMovement(targetPosition));

macht exakt gar nichts. SmoothMovement gibt einen neuen IEnumerator zurück, wenn du es aufrufst. Damit kannst du eine zweite Coroutine starten. Aber du kannst nicht die andere Coroutine beenden, die gerade läuft. Dafür musst du dir den Rückgabewert vom letzten StartCoroutine-Aufruf merken. Diese Referenz auf ein Coroutine-Objekt kannst du dann in StopCoroutine schmeißen.

Hier ein Beispielcode, der alles machen dürfte, was du brauchst:

private Coroutine currentSmoothMovement;
private bool directionRight;

public void MoveButtonPressed(bool inputRight)
{
  if(currentSmoothMovement == null) // wenn gerade keine Bewegung stattfindet
  {
    currentSmoothMovement = StartCoroutine( ... );
    directionRight = inputRight;
  }
  else // wenn gerade doch schon Bewegung ist
  {
    if(inputRight == directionRight) // nur wenn "vorwärts"
    {
      StopCoroutine(currentSmoothMovement);
      currentSmoothMovement = null;
      TeleportToDestination();
    }
  }
}

Ich benutze hier "currentSmoothMovement != null" wie einen boolean, den man auch extra bauen könnte. Damit das funktioniert, muss am Ende deiner Coroutine-Methode (SmoothMovement) "currentSmoothMovement = null;" stehen. Ist Geschmackssache, ob man das haben will.

Link zu diesem Kommentar
Auf anderen Seiten teilen

@Sascha

Also ich bewege mich innerhalb eines Arrays von Index zu Index. Mit dem Index komme ich an das Objekt und somit auch an die Position des Objektes. Nun ist es so, dass dein Code fast funktioniert. Ich kann mich hin und her bewegen. Trotzdem gibt es ein paar Fehler, die Ausgangssituation ist, dass ich mich am letzten Element befinde, also der höchste Index ist aktiv.

Bewege ich mich zurück und drücke schnell nochmal vorwärts, kann ich für einige Tastendrücke lang den Spieler gar nicht mehr bewegen. Ich habe deinen Code mal bei mir umgesetzt

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.A)) // nach links bewegen
        {
            MovePlayer(false);
        }

        if (Input.GetKeyDown(KeyCode.D)) // nach rechts bewegen
        {
            MovePlayer(true);
        }
    }

    private void MovePlayer(bool moveForward)
    {
        if (currentSmoothMovement == null) // kein SmoothMovement aktiv (1x)
        {
            bool validMovement = false; // kann sich der Spieler mit dem nächsten Index noch weiter bewegen?

            if (moveForward) // nächsten Index prüfen
            {
                if (currentPlaceIndex + 1 < places.Length)
                {
                    currentPlaceIndex++;
                    validMovement = true;
                }
            }
            else // vorherigen Index prüfen
            {
                if (currentPlaceIndex - 1 >= 0)
                {
                    currentPlaceIndex--;
                    validMovement = true;
                }
            }

            if (validMovement) // der Spieler darf sich noch bewegen
            {
                targetPlacePosition = places[currentPlaceIndex].PlacePosition; // die aktuelle Zielposition festlegen
                player.CurrentSmoothMovement = StartCoroutine(player.MoveSmoothlyToLevel(targetPlacePosition)); // Smooth Movement aktivieren
                forwardMovement = moveForward;
            }
        }
        else // SmoothMovement aktiv (2x)
        {
            if (moveForward == forwardMovement)
            {
                StopCoroutine(player.CurrentSmoothMovement);
                player.CurrentSmoothMovement = null; // SmoothMovement stoppen
                player.MoveInstantToLevel(targetPlacePosition); // "Teleport"
            }
        }
    }

Ich vermute, ich habe 

forwardMovement = moveForward;

noch nicht so ganz verstanden bzw. ich wende es falsch an.. ?

Link zu diesem Kommentar
Auf anderen Seiten teilen

forwardMovement merkt sich einfach nur, in welche Richtung du zuletzt gegangen bist. webb dann bei der if-Abfrage im else-Fall die aktuelle Bewegungsrichtung gleich der Bewegungsrichtung ist, die beim Losgehen benutzt wurde, wird halt teleportiert.

Man könnte stattdessen auch den Index nochmal neu ausrechnen beim drücken - und dann schauen ob man wieder bei demselben Ziel rauskommen würde. Irgendwie sowas. Scheint so aber jedenfalls zu passen.

Hast du das "CurrentSmoothMovement = null" am Ende der Coroutine eingebaut?

Und so nebenbei: Warum steuert dieses Script den Player fern, anstatt selber auf dem Player-Objekt zu sitzen?

Link zu diesem Kommentar
Auf anderen Seiten teilen

Zu deiner letzten Frage:

Weil dieses Script die Karte ist. Die Karte verwaltet die ganzen Punkte und sagt dem Spieler nur "beweg dich da hin". Der Spieler selbst hat dann das ganze Movement Zeug und soll später auch seine Animationen verwalten. Aber was die Punkte betrifft, liegt das bei der Karte. 

Natürlich müsste man den Input eigentlich bei dem Spieler abfragen, ja.

 

Und zu deiner vorletzten Frage:

Nein, ich war dumm :)

 

Dankeschön.

Link zu diesem Kommentar
Auf anderen Seiten teilen

@Sascha

Ich habe noch ein interessantes Problem entdeckt ..

Ich habe eine Levelauswahl und eine Weltenauswahl. Da beide bei mir technisch gesehen identisch sind, nutzen sie den gleichen Code.

Starte ich das Spiel vom Hauptmenü aus, kann ich problemlos auf die Karte der Welten, dort eine Welt auswählen und dann zur Levelauswahl der Welt. Dort funktioniert die Steuerung problemlos.

Starte ich das Spiel innerhalb eines Levels, gehe ins Ingame Menü, wähle "zurück zur Map", dann gelange ich zur Levelauswahl, aber der Spieler kann nicht mehr sliden, sondern bewegt sich gar nicht und beim zweiten Key dann instant.

Gehe ich von dort zur Weltenauswahl, ist der Fehler auch dort anzutreffen.

Gehe ich von dort zum Hauptmenü und dann wieder zur Weltenauswahl, bleibt der Fehler bestehen.

 

Also starte ich das Spiel ordentlich vom Hauptmenü aus funktioniert es aber starte ich aus einem Level heraus und lade die "Weltenauswahl"-Szene, funktioniert das Sliden nicht mehr. Der restliche Code funktioniert aber. Nur die Coroutine möchte nicht ..

Link zu diesem Kommentar
Auf anderen Seiten teilen

Archiviert

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

×
×
  • Neu erstellen...