DevLog - Hagal - Plataformas 2D

n3krO

#30 WaitForFrames no lo veo en la documentacion de Unity ._.

aparece:

WaitForEndOfFrame
WaitForFixedUpdate
WaitForSeconds
WaitForSecondsRealTime

1 respuesta
AikonCWD

#21 No controlo de Unity pero me extraña esto que habéis comentado... FixedUpdate corre a 50 frames/segundo... pero qué pasa si el PC recibe un lag-spike y baja a 10fps aunque solo sea un momento? Creo que deberías recurrir a la variable de sistema "delta", cuyo valor es el tiempo en milisegundos desde el último frame, y usar ese valor para multiplicar cualquier velocidad. Así si tienes lag-spike, ese movimiento será más grande y por tanto más consistente.

2 respuestas
B

#30 El problema que le veo a eso es que no sé cómo se contarán esos 50 frames, es decir, no sé si tendría el mismo problema que tenía al contar los coyote frames en el Update, teniendo en cuenta que esa corrutina la llamaría en el evento ontriggerexit (que es donde cambio la variable isGrounded)

Luego lo que dice Nekro, no encuentro esa función :S

#32 Sí lo había pensado, en un escenario como el que cuentas (fps por debajo de 50) podría ser inconsistente y creo que usar Time.deltaTime sería lo suyo, le tendré que dar otra vuelta al tema.

2 respuestas
AikonCWD

#33 Espera, estoy leyendo... si no lo he entendido mal. FixedUpdate es llamado en función de los fps actuales. Así que creo que no debes hacer nada más.

Por ponerte un ejemplo: Si el juego te va a 100fps, FixedUpdate se llama cada 2 segundos. Si el juego te baja a 25fps, se llama 2 veces por segundo. Y así todo el rato. Pero que te lo confirme alguien que entienda de Unity mejor, por ejemplo @debug (a saber qué nick está usando hoy)

2 respuestas
n3krO

#32 https://docs.unity3d.com/ScriptReference/MonoBehaviour.FixedUpdate.html

The FixedUpdate frequency is more or less than Update. If the application runs at 25 frames per second (fps), Unity calls it approximately twice per frame

Si te da un lag a 10 fps, el motor llamará fixedupdate 5 veces por frame.

2 respuestas
AikonCWD

#35 Vale, lo acabo de leer. Pues mete ahí cualquier movimiento y pista. Lo que no entiendo por qué te dan el DeltaTime si no lo tienes que usar nunca ¿?

B

#34 De hecho lo probe forzando los fps (o como dice tote semi-forzando) a 20 y parecía funcionar bien, esto del Update/FixedUpdate me trae de cabeza...

Había pensado en quotear a d-bug también, pero ya le perdí la pista del nick actual xDD

#35 Entonces salvo que alguien nos corrija, de momento podemos decir que lo tengo de forma correcta. ¡Y sin demasiado código!

1 1 respuesta
totespare

#31 #33 vale el waitforframes es una extension que tenemos en el curro, no es de Unity, pensaba que sí, sorry xD

1 1 respuesta
n3krO

#38 Y funciona en FixedUpdate? :full_moon_with_face:

1 2 respuestas
B

#39 :full_moon_with_face: :full_moon_with_face: :full_moon_with_face: :full_moon_with_face:

Esto he encontrado, una clase para implementar ese waitfor.frames: https://ivanderevianko.com/2015/05/unity3d-waitforframes-in-coroutine
Que entiendo que llamando a la corrutina en FixedUpdate debería funcionar, pero en mi caso no lo sé (por puro desconocimiento) ya que mi variable isGrounded se actualiza en el evento ontriggerexit. A lo mejor dicho evento, al ser parte de las físicas (creo), se ejecuta en fixedupdate, pero lo ignoro por completo.

1 respuesta
totespare

#39 /// Waits a specified number of calls to update. This ignores time althogether. xD

#40 la corrutina da igual donde la llames, lo que importa es el yield que hagas dentro. Puedes hacer un WaitForFixedUpdate y esa corrutina irá al mismo tiempo que el fixed update.

1 respuesta
B

#41 Con lo sencillo que lo tengo ahora... Así ha quedado después de todo lo hablado:

  private bool isGrounded;
  private int actualCoyoteFrames ;
  private int maxCoyoteFrames = 5;

  private bool CheckCoyoteTime() {
    return actualCoyoteFrames < maxCoyoteFrames;
  }

  private void SetCoyoteTime() { // Se llama en el FixedUpdate
    if (!isGrounded){
      actualCoyoteFrames++;
    else
      actualCoyoteFrames = 0;
  }

  // En la función de salto
  if (InputController.Jump && !alreadyJumped && (isGrounded || CheckCoyoteTime())){
    // Haz que salte
  }
n3krO

Estas haciendo doble check a lo mismo.

Porque solo subes el contador del coyotetime si !isGrounded, pero aun asi en la funcion de salto pones isGrounded || CoyoteTime pero es que si isGrounded es true, el CheckCoyoteTime() siempre te va a devolver true.

Asi que puedes dejar como:

if (InputController.Jump && !alreadyJumped && CheckCoyoteTime()){
    // Haz que salte
  }

Igual mi explicacion es liosa:

Si isGrounded es verdadero -> actualCoyoteFrames = 0
Si actualCoyoteFrames es 0 -> CheckCoyoteTime() = verdadero

(isGrounded || CheckCoyoteTime())

Siempre te devuelve el valor que tenga CheckCoyoteTime();

1 respuesta
B

#43 Toda la razón del mundo, la función de salto es anterior a lo del coyote time y ni lo había pensado.

Pues así queda la versión final:

  private bool isGrounded;
  private int actualCoyoteFrames ;
  private int maxCoyoteFrames = 5;

  private bool CheckCoyoteTime() {
    return actualCoyoteFrames < maxCoyoteFrames;
  }

  private void SetCoyoteTime() { // Se llama en el FixedUpdate
    if (!isGrounded){
      actualCoyoteFrames++;
    else
      actualCoyoteFrames = 0;
  }

  // En la función de salto
  if (InputController.Jump && !alreadyJumped && CheckCoyoteTime()){
    // Haz que salte
  }

Y van tres :coffee:

1
B

.

3 3 respuestas
n3krO

Hostias, que no actualiza el input durante fixedUpdate, vaya vaya xDDDD

Eso si que me ha dejado roto xDDDD

#45axn:

Captura el tiempo al salir del collider y después en el salto determinas con ese timestamp si ha finalizado el Coyote Time.

Esto me gusta, y no tienes que modificar mucho el codigo para hacer esto @obZen

1 respuesta
B

#45 Vale, voy a necesitar un tiempo para digerir todo eso, de momento voy a ir viendo lo de hacerlo contando el tiempo. Muchísimas gracias por tan detallada respuesta!

#46 Lo del input en el FixedUpdate sí que lo sabía y me había generado ya algún dolor de cabeza, lo explico en uno de los posts del principio, de por qué estaba usando una clase que había encontrado en github para facilitar ese tema.

1 1 respuesta
n3krO

#47 https://docs.unity3d.com/ScriptReference/Time-time.html

A ver si algo asi funcionaria
2 respuestas
B

#48 Hmmm lo he hecho así:

    private float actualCoyoteTime;
    private float maxCoyoteTime = 0.2f;

private bool CheckCoyoteTime()
{
    return actualCoyoteTime < maxCoyoteTime;
}

private void SetCoyoteTime() // Se llama en el FixedUpdate
{
    // isGrounded se calcula en los eventos de entrada y salida de colisionadores de tierra
    if (!isGrounded) 
    {
        actualCoyoteTime += Time.fixedDeltaTime;
    }            
}

// En la función de saltar
if (inputController.Jump && !alreadyJumped && (isGrounded || CheckCoyoteTime())) { // Salto }

Aunque entiendo por lo que ha dicho #45 que da igual que use Time.fixedDeltaTime o Time.deltaTime porque si uso el segundo desde FixedUpdate me devolvera el primero de todas formas.

1 respuesta
n3krO

tienes que resetear actualCoyoteTime a 0 cuando isGrounded te devuelve verdadero en SetCoyoteTime().

Esa opcion la contemplé pero en mi mente era mas costosa computacionalmente.

Si vas a usar DeltaTime no hace falta que pongas fixedDeltaTime y en verdad lo puedes meter en el mismo Update si quieres, en caso de que tengas problemas de rendimiento va a tener menos impacto, y en caso de que tengas mas de 50 fps, va a ser mas fiable.

1 respuesta
B

#50 Ah sí, que no lo puse, reseteo a 0 el actualCoyoteTime en cuando pongo a true isGrounded en el evento de entrada al colisionador.

Lo del deltaTime o fixedDeltaTime entiendo que puedo poner siempre deltaTime y Unity me devolverá uno u otro dependiendo de si se está llamando desde Update o desde FixedUpdate, o eso he entendido!

Lo de ponerlo en Update no me convence, teniendo en cuenta que se recomienda poner los cálculos que tengan que ver con físicas en FixedUpdate. Voy a acabar soñando esta noche con Unity ya verás... que me he pasado la tarde pegándome con el sistema de escaleras que tenía, que quería mejorarlo y ahora de vueltas con el Coyote Time xDD

B

.

1 respuesta
B

#52 Vale, entonces se me simplifica incluso más, ya que no tengo que sumar incrementos de delta ni nada:

Guardo Time.time al salir del colisionador y luego compruebo que Time.time - timeGuardado < maxCoyoteTime y listo.

    private float maxCoyoteTime = 0.2f;
    private float actualCoyoteTime;

private bool CheckCoyoteTime()
{
    return Time.time - actualCoyoteTime < maxCoyoteTime;
}

actualCoyoteTime = Time.time; // En la salida de la colisión del suelo

if (inputController.Jump && !alreadyJumped && (isGrounded || CheckCoyoteTime())) { // Saltamos }
2 1 respuesta
B

.

1 2 respuestas
B

#54 Sí, eso lo leí en la documentación por eso a priori no me convencía la solución de n3krO, pero porque todavía iba con la idea de usarlo frame a frame, que no es el caso. Muchas gracias por la ayuda!

1 1 respuesta
B

.

1 respuesta
n3krO

#54 Yo eso lo pensé, pero no me gusta la solución que yo le daria xDDDDD

Yo lo que entiendo es que recomiendas esto:

if (inputController.Jump && !alreadyJumped) {
 if (isGrounded || CheckCoyoteTime()) { // Saltamos }
}
2 respuestas
B

#56 Le daré unas vueltas a eso, no creo que me cueste mucho implementarlo ya que ya tengo una clase separada que se encarga de gestionar/almacenar el input. Entiendo que lo único que debería hacer es que tuviera su propio Update y luego jugar con el orden de ejecución.

#57 Yep! Así me evito llamadas innecesarias a CheckCoyoteTime y por ende a Time.time. Lo cambio ahora mismo.

1 respuesta
B

.

1 respuesta
B

#59 Ya he hecho el cambio, en el orden de ejecución de scripts lo he puesto el primero:

Supongo que no tengo que hacer nada más, todos los de abajo de PlayerInput o los que no salen en la lista se ejecutarán después.

1 respuesta