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

Wechseln zwischen Lerp und Instant Movement

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 

Share this post


Link to post
Share on other sites

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.

  • Thanks 1

Share this post


Link to post
Share on other sites

So wie ich deinen Code grade lese, müsste ich nur noch 

if (Input.GetKeyDown(KeyCode.D))
        {
             MoveButtonPressed(true);
        }

angeben?

Bzw. für Key "A" dann "MoveButtonPressed(false)"

Share this post


Link to post
Share on other sites

Ja, kommt hin. Dann halt noch die Berechnung für die Zielposition rein und eine Implementation für TeleportToDestination (wobei man da auch einfach direkt transform.position = x schreiben kann).

Share this post


Link to post
Share on other sites

jup, das hab ich schon alles :) der erste Code war einfach mal Pseudo, weil ich hier grad das Repo nicht hatte.

Ich probiere es heut abend mal aus. Vielen Dank schonmal!

Share this post


Link to post
Share on other sites

@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.. ?

Share this post


Link to post
Share on other sites

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?

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites

@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 ..

Share this post


Link to post
Share on other sites

Tjoa... ein paar prints reinschmeißen und gucken was so anders ist. Hat du irgendwelchen Singleton-Kram und/oder DontDestroyOnLoad am Laufen?

Share this post


Link to post
Share on other sites

Ne, genau das wundert mich, die Szene ist ja komplett unabhängig von allem. Das heißt ihr müsste es ja eigentlich egal sein, von wo sie geladen wird.

 

Ich muss das nochmal debuggen ..

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×