Interpolación de fisica avanzada

Aunque las instrucciones anteriores brindarán resultados satisfactorios en muchos juegos, en algunos casos querrás ir un paso más allá para obtener los mejores resultados posibles y la experiencia más fluida.

Excepciones a la interpolación de fisica automatica

Incluso con la interpolación de físicas activada, puede haber algunas situaciones locales en las que te beneficiarías de desactivar la interpolación automática para un Node (o rama del SceneTree), y tener un control más preciso al realizar la interpolación manualmente.

Esto es posible utilizando la propiedad Node.physics_interpolation_mode, presente en todos los Nodos. Por ejemplo, si desactivas la interpolación para un Nodo, los hijos también se verán afectados de manera recursiva (ya que por defecto heredan la configuración del padre). Esto significa que puedes desactivar fácilmente la interpolación para toda una subescena.

La situación más común en la que puedes querer realizar tu propia interpolación es con las Cámaras.

Cámaras

En muchos casos, una Camera puede utilizar la interpolación automática al igual que cualquier otro nodo. Sin embargo, para obtener los mejores resultados, especialmente a frecuencias de tics de física bajas, se recomienda que adoptes un enfoque manual para la interpolación de la Cámara.

Esto se debe a que los espectadores son muy sensibles al movimiento de la Cámara. Por ejemplo, una Cámara que se realinea ligeramente cada 1/10 de segundo (a una frecuencia de 10 TPS) a menudo será notable. Puedes obtener un resultado mucho más suave moviendo la Cámara en cada fotograma en _process, siguiendo manualmente un objetivo interpolado.

Interpolación de cámara manual

Asegúrate de que la Cámara esté utilizando el espacio de coordenadas global

El primer paso al realizar la interpolación manual de la Cámara es asegurarse de que la transformación de la Cámara esté especificada en espacio global en lugar de heredar la transformación de un nodo padre en movimiento. Esto se debe a que puede ocurrir un feedback entre el movimiento de un nodo padre de la Cámara y el movimiento de la propia Cámara, lo que puede afectar la interpolación y causar problemas en el movimiento suave.

Hay dos formas de hacerlo:

  1. Mueve la Cámara para que sea independiente en su propia rama, en lugar de ser un hijo de un objeto en movimiento.

../../../_images/fti_camera_worldspace.png
  1. Llama a Spatial.set_as_toplevel y establece esto en true, lo cual hará que la Cámara ignore la transformación de su padre.

Ejemplo típico

Un ejemplo típico de un enfoque personalizado es utilizar la función look_at en la Cámara en cada fotograma dentro de _process(), para apuntar hacia un nodo objetivo (como el jugador).

Pero hay un problema. Si utilizamos el tradicional get_global_transform() en un Nodo "objetivo" de la Cámara, esta transformación solo enfocará la Cámara en el objetivo en el tik actual de la física. Esto no es lo que queremos, ya que la Cámara saltará en cada tic de la física mientras el objetivo se mueve. Aunque la Cámara se actualice en cada fotograma, esto no ayuda a lograr un movimiento suave si el objetivo solo cambia en cada tick de la física.

get_global_transform_interpolated()*

Lo que realmente queremos enfocar con la Cámara no es la posición del objetivo en el tic de física, sino la posición interpolada, es decir, la posición en la que el objetivo será renderizado.

Podemos lograr esto utilizando la función Spatial.get_global_transform_interpolated. Esta función actúa exactamente como obtener Spatial.global_transform, pero te proporciona la transformación interpolada (durante una llamada a _process()). Esto permitirá enfocar la Cámara en la posición interpolada del objetivo para obtener un movimiento suave y sin saltos.

Importante

get_global_transform_interpolated() solo debería usarse una o dos veces para casos especiales como las Cámaras. No debe utilizarse en todas partes de tu código (tanto por razones de rendimiento como para garantizar una jugabilidad correcta).

Nota

A excepción de casos especiales como la Cámara, en la mayoría de los casos, tu lógica del juego debe estar en _physics_process(). En la lógica del juego, debes llamar a get_global_transform() o get_transform(), lo cual te proporcionará la transformación de físicas actual (en espacio global o local, respectivamente), que es lo que generalmente deseas para el código del juego.

Ejemplo de script de Camara manual

Aquí tienes un ejemplo de una simple Cámara fija que sigue un objetivo interpolado:

extends Camera

# Node that the camera will follow
var _target

# We will smoothly lerp to follow the target
# rather than follow exactly
var _target_pos : Vector3 = Vector3()

func _ready() -> void:
        # Find the target node
        _target = get_node("../Player")

        # Turn off automatic physics interpolation for the Camera,
        # we will be doing this manually
        set_physics_interpolation_mode(Node.PHYSICS_INTERPOLATION_MODE_OFF)

func _process(delta: float) -> void:
        # Find the current interpolated transform of the target
        var tr : Transform = _target.get_global_transform_interpolated()

        # Provide some delayed smoothed lerping towards the target position
        _target_pos = lerp(_target_pos, tr.origin, min(delta, 1.0))

        # Fixed camera position, but it will follow the target
        look_at(_target_pos, Vector3(0, 1, 0))

Apuntar con el ratón

El "Mouse look" (mirar con el ratón) es una forma muy común de controlar Cámaras en los juegos. Pero hay un problema. A diferencia de la entrada del teclado que puede ser muestreada periódicamente en cada tic de físicas, los eventos de movimiento del ratón pueden llegar de forma continua. Se espera que la Cámara reaccione y siga estos movimientos del ratón en el próximo fotograma, en lugar de esperar hasta el siguiente tic de físicas. Esto puede resultar en una experiencia de cámara más suave y sensible a los movimientos del ratón.

En esta situación, puede ser mejor deshabilitar la interpolación de físicas para el nodo de la Cámara (usando Node.physics_interpolation_mode) y aplicar directamente la entrada del ratón a la rotación de la Cámara, en lugar de hacerlo en _physics_process.

A veces, especialmente con Cámaras, querrás utilizar una combinación de interpolación y no interpolación:

  • En una cámara en primera persona, puedes posicionar la cámara en la ubicación del jugador (quizás utilizando Spatial.get_global_transform_interpolated), pero controlar la rotación de la Cámara mediante el "Mouse look" sin interpolación. Esto te permitirá obtener una experiencia de cámara más sensible a los movimientos del ratón sin suavizar la rotación.

  • Una cámara en tercera persona puede determinar de manera similar la ubicación a la que mirar (posición del objetivo) de la cámara usando Spatial.get_global_transform_interpolated, pero posicionar la cámara mediante el "Mouse look" sin interpolación.

Hay muchas permutaciones y variaciones de tipos de cámaras, pero está claro que en muchos casos, deshabilitar la interpolación automática de físicas y manejarla manualmente puede dar un mejor resultado.

Desabilitando interpolación sobre otros nodos

Aunque las Cámaras son el ejemplo más común, hay varios casos en los que puede que desees que otros nodos controlen su propia interpolación o que no sean interpolados. Considera, por ejemplo, a un jugador en un juego de vista superior cuya rotación es controlada por el movimiento del ratón. Deshabilitar la rotación de la física permite que la rotación del jugador coincida con el movimiento del ratón en tiempo real.

MultiMeshes

Aunque la mayoría de los Nodos visuales siguen el paradigma de un solo Nodo con una sola instancia visual, los MultiMeshes pueden controlar varias instancias desde el mismo Nodo. Por lo tanto, tienen algunas funciones adicionales para controlar la funcionalidad de interpolación en una base de por instancia. Debes explorar estas funciones si estás utilizando MultiMeshes interpolados.

  • MultiMesh.reset_instance_physics_interpolation

  • MultiMesh.set_as_bulk_array_interpolated

Vea los detalles en la documentación Using MultiMesh.