Jump to content
Unity Insider Forum

Objekt soll steigen und nach bestimmter Zeit fallen


ShV

Recommended Posts

Die Erkennung, ob das Objekt nicht mehr auf dem Boden ist, kannst Du mit OnCollisionExit machen, wie @chrische5 schon schreibt. Wenn dieses Ereignis eintritt, kannst Du in eine Variable die aktuelle Zeit schreiben und im Update dann prüfen ob die aktuelle Zeit - die gespeicherte Zeit 2 Sekunden ergibt bzw. darunter liegt. Solange eben das Objekt bewegen.

Beispiel Pseudo Code

private float groundExitTime;
private const float moveUpDuration = 2f;

void OnCollisionExit(Collision collisionInfo)
{
  groundExitTime = Time.timeSinceLevelLoad;
}

void Update()
{
  if(Time.timeSinceLevelLoad - groundExitTime <= moveUpDuration)
  {
    //move up
  }
}

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

mit dem OnCollisionExit stimme ich zu allerdings kommt das auf deinen Anwendungsfall an, da gibt es sicher noch andere / leichtere lösungen für

von der Lösung die @devandart vorgeschlagen hat würde ich jedoch abraten ... bei diesem Code wird das objekt sobald das level geladen ist erstmal direkt 2 sekunden steigen wenn nicht gleich OnCollisionExit aufgerufen wird. Besser ist es eine bool variable z.b. isGrounded = true und eine timerVariable zu haben. Wenn OnCollisionEnter eintritt setzt du die timerVariable auf 2f und isGrounded auf false. In der Update() funktion machste dann

private bool isGrounded = true;
private float moveUpTimer;
private const float moveUpDuration = 2f;

void OnCollisionEnter(Collision collisionInfo)
{
  // Wenn collision mit ground
  isGrounded = true;
}

void OnCollisionExit(Collision collisionInfo)
{
  // wenn keine collision mehr mit ground
  moveUpTimer = moveUpDuration;
  isGrounded = false;
}

public void Update()
{
 if(isGrounded)
      return;
  
  	moveUpTimer -= Time.deltaTime;
    if(moveUpTimer > 0f)
    {
      // move up
    }
  
}

gruß Cxyda

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hatte dieses Mal initial keine Lust, den "das geht auch soundso"-Typen rauszuholen, aber da jetzt hier lauter Varianten aufgezählt werden, mach ich's halt doch :D

Man kann in Update hoch- oder runterzählen oder auch Timestamps vergleichen. Man kann aber auch eine Coroutine benutzen:

private void OnCollisionExit()
{
  StopAllCoroutines();
  StartCoroutine(MoveUp(2f));
}

private IEnumerator MoveUp(float duration)
{
  for (var time = 0f; time < duration; time += Time.deltaTime)
  {
    transform.Translate(Vector3.up * speed * Time.deltaTime);
    yield return null;
  }
}

Man kann auch so etwas machen:

private bool moving;

private void OnCollisionExit()
{
  StartCoroutine(MoveUp(2f));
}

private IEnumerator MoveUp(float duration)
{
  moving = true;
  yield return new WaitForSeconds(duration);
  moving = false;
}

private void Update()
{
  if (moving)
  {
    transform.Translate(Vector3.up * speed * Time.deltaTime);
  }
}

Oder man nutzt Invoke für diese Variante. Invoke ist aber doof, lieber meinen Invoker benutzen :D:

private bool moving;

private void OnCollisionExit()
{
  StopAllCoroutines();
  moving = true;
  StartCoroutine(Invoker.Invoke(() => moving = false, 2f));
}

private void Update()
{
  if (moving)
  {
    transform.Translate(Vector3.up * speed * Time.deltaTime);
  }
}

Oder du nimmst die eine Tween-Bibliothek. Tweens sind genau für so etwas ("mach mal etwas X Sekunden lang") und mehr da. Auch dafür hab ich ne kleine Klasse, aber Tween-Frameworks gibt's lauter verschiedene, kannst du dir ja mal ansehen. Mit meiner Klasse würde das so aussehen:

private void OnCollisionExit()
{
  // Hier wird distance statt speed benutzt, das eine kann man aber durch das andere ausrechenen
  var targetPosition = transform.position + Vector3.up * distance;
  StartCoroutine(CorouTweens.Interpolate(transform.position, // von wo
                                         targetPosition, // nach wo
                                         duration, // wie lange
                                         CorouTweens.linear, // welche Kurve (z.B. erst schneller, dann langsamer, hier aber gleichbleibend)
                                         pos => transform.position = pos));
}

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 5 Stunden schrieb Cxyda83:

... und in deiner ersten coroutine fehlt ein "yield return" 🤓

Na, das stimmt. Hab's korrigiert., danke!

vor 5 Stunden schrieb Cxyda83:

Invoke(nameOf(MyStopFunction), 2f);

Oha.... auf die Idee bin ich nicht gekommen. Empfehle immer, Invoke wegen des String-Parameters nicht zu benutzen, aber so ist's ja wieder sicher.

Die Doku sagt allerdings selbst

Zitat

For better performance and maintability, use Coroutines instead.

Ich nehme an, dass da Reflection passiert ist nicht so prickelnd. Hab's mal durch den Benchmark laufen lassen: MonoBehaviour.Invoke braucht bei mir 230ns beim Aufruf, die Coroutine mit dem Invoker nur 2µs.

Mit "maintability" (maintainability...) meinen die vermutlich genau das String-Problem, das man mit nameof ja umgeht. Reicht also in der Tat, aber ich werde weiterhin den Invoker empfehlen :D

Oh, und Nachtrag: Beim Invoker muss man keine Methode definieren, sondern kann einfach einen Lambda-Ausdruck reinknallen. Finde ich jetzt auch nicht unwichtig :)

Link zu diesem Kommentar
Auf anderen Seiten teilen

Archiviert

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

×
×
  • Neu erstellen...