RigidBody

¿Qué es RigidBody?

RigidBody representa un cuerpo rígido que es un cuerpo que es controlado directamente por el motor de física para simular el comportamiento de objetos físicos. Para definir la forma del cuerpo se debe usar uno o más recursos derivados de Shape. Tener en cuenta que la posición de las formas de colisión afectarán el centro de masa del cuerpo.

Cómo controlar un cuerpo rígido

El comportamiento de un cuerpo rígido puede ser alterado asignando propiedades como friction (fricción), mass (masa), bounce (rebote/elasticidad), etc. Esas propiedades pueden asignarse en el Inspector o mediante código. Ver RigidBody para la lista completa de propiedades y sus efectos.

Existen varios modos de controlar el movimiento de un cuerpo rígido, dependiendo de la aplicación deseada.

Si sólo necesitas ubicar un cuerpo rígido una sola vez, por ejemplo, para asignar la posición inicial, se pueden utilizar los métodos provistos por la clase Spatial, como set_global_transform() or look_at(). Sin embargo, esas funciones no pueden ser llamadas en cada frame o el motor de física no será capaz de simular correctamente el estado del cuerpo. Como un ejemplo, considera un cuerpo rígido que quieres rotar así apunta hacia otro objeto. Un error común cuando se quiere crear este tipo de comportamiento, es utilizar look_at() en cada frame, lo que rompe la simulación física. En el siguiente ejemplo demostramos cómo implementar esto correctamente.

El hecho de que no puedes usar métodos set_global_transform() o look_at() no quiere decir que no puedes tener control completo de un cuerpo rígido. Esto se puede conseguir usando la llamada interna _integrate_forces(). En esta función, puedes agregar fuerzas, aplicar impulsos o asignar la velocidad para conseguir el movimiento deseado.

The «look at» method

Como se describió anteriormente, los nodos derivados de Spatial poseen una función look_at() (utilizada para apuntar hacia un lugar en el espacio) que no puede ser llamada en cada frame para seguir un objetivo. Aquí hay una versión personalizada de la función look_at() que funciona bien con cuerpos rígidos:

extends RigidBody

func look_follow(state, current_transform, target_position):
    var up_dir = Vector3(0, 1, 0)
    var cur_dir = current_transform.basis.xform(Vector3(0, 0, 1))
    var target_dir = (target_position - current_transform.origin).normalized()
    var rotation_angle = acos(cur_dir.x) - acos(target_dir.x)

    state.set_angular_velocity(up_dir * (rotation_angle / state.get_step()))

func _integrate_forces(state):
    var target_position = $my_target_spatial_node.get_global_transform().origin
    look_follow(state, get_global_transform(), target_position)
class Body : RigidBody
{
    private void LookFollow(PhysicsDirectBodyState state, Transform currentTransform, Vector3 targetPosition)
    {
        var upDir = new Vector3(0, 1, 0);
        var curDir = currentTransform.basis.Xform(new Vector3(0, 0, 1));
        var targetDir = (targetPosition - currentTransform.origin).Normalized();
        var rotationAngle = Mathf.Acos(curDir.x) - Mathf.Acos(targetDir.x);

        state.SetAngularVelocity(upDir * (rotationAngle / state.GetStep()));
    }

    public override void _IntegrateForces(PhysicsDirectBodyState state)
    {
        var targetPosition = GetNode<Spatial>("my_target_spatial_node").GetGlobalTransform().origin;
        LookFollow(state, GetGlobalTransform(), targetPosition);
    }
}

Esta función utiliza el método set_angular_velocity() de RigidBody (asigna velocidad angular) para rotar el cuerpo. Primero calcula la diferencia entre el ángulo actual y el deseado y luego agrega la velocidad necesaria para rotar esa cantidad en el tiempo del frame.

Nota

Este script no funcionará con rigid bodies en character mode porque en este modo la rotación del cuerpo está bloqueada. En este caso, tendrías que rotar el nodo conectado a la malla utilizando el método Spatial estándar.