Jump to content

Archived

This topic is now archived and is closed to further replies.

AngelFG

RigidBody en jerarquías...

Recommended Posts

Hola a todos.

A ver si me podéis ayudar...

Tengo dos gameobjects con RigidBody y collider asociados, movidos por la física.

A es el padre y B es el hijo en la jerarquía, situado encima del objeto A (pos Y más  arriba)

Ya sé que el rigidbody del hijo no se actualiza aunque se mueva el padre.

La situación es la siguiente:

  • El objeto A se mueve de izquierda  a derecha de forma continua empleado su rigidbody y método MovePosition
  • El objeto B se mueve con el objeto A, manteniendo su posición relativa.

Si en el objeto B hago esto en el método FixedUpdate:

Quote

Debug.Log("Transform:" + transform.position + "- RigidBody" + rb.position);

compruebo que su rigidbody.position no se mueve, pero sí su posición GLOBAL (transform.position). Su posición relativa (transform.localPosition) no se mueve.Hasta aquí lo entiendo, todo correcto. Ahora quiero mover el objeto B al pulsar una tecla, pero que siga desplazándose al mismo tiempo, por lo que tengo este código asociado a B:
 

Quote

 

private void FixedUpdate()
    {
      float hor = Input.GetAxis("Horizontal") * 50 * Time.deltaTime;
       float ver = Input.GetAxis("Vertical") * 50 * Time.deltaTime;

        Debug.Log("Transform:" + transform.position + "- RigidBody" + rb.position);
        rb.MovePosition(transform.position + rb.transform.forward * ver + transform.right * hor);
    }

 

Esto da como resultado que el objeto B ya no se mueva con el padre y que sólo se mueva por la pulsación de las flechas (ejes virtuales).

 

Share this post


Link to post
Share on other sites

Dudas:

  1. ¿Por qué son padre e hijo si no se mueven solidariamente, cada uno tiene su rigidbody que lo gobierna?
    1. Combinar dos RigidBodys hará que el hijo se mueva con el transform del padre, pero sujeto a sus propias físicas https://docs.unity3d.com/Manual/class-Rigidbody.html (sección "Parenting"): When an object is under physics control, it moves semi-independently of the way its transform parents move. If you move any parents, they will pull the Rigidbody child along with them. However, the Rigidbodies will still fall down due to gravity and react to collision events.
    2. Habría que ver tu caso pero (yo diría) que rara vez esto es lo que deseas.
  2. ¿Por qué A es un Rigidbody si lo mueves con MovePosition siempre? ¿y si es para mantener su comportamiento físico, masa, etc... no sería mejor AddForce?
  3. En el código que gobierna B, estás llamando a MovePosition siempre, lo que provocará que se mueva a donde está ahora mismo.
    1. Para comprobarlo: evita llamar a MovePosition si no estás moviendo ningún eje a ver si se mueve cuando no lo mueves tú.
    2. ¿Tampoco podemos usar AddForce para el objeto B? ¿para qué usas el motor físico entonces? ¿es para otros objetos externos? (entonces igual podrías usar rigidbodies kinemáticos en A, B o ambos, y moverlos a tu aire ¿?)
    3. ¿No podrías modelar esa relación entre RidigBody deshaciendo la relación padre-hijo y usando Joints ?

O quizá, depende del caso, puedas replantearte la manera de controlar tus objetos...

Para otra, alguna(s) captura(s) de pantalla mostrando la situación siempre ayudan ;-).

Share this post


Link to post
Share on other sites

Muchas gracias por responder.

La idea es hacer que al subir a una plataforma (objeto A) el protagonista (Objeto B) se mueva con la plataforma y al mismo tiempo pueda moverse.

Buscando por internet, la solución que dan es la de hacer el transform.parent de B = transform del A: https://answers.unity.com/questions/167404/rigidbody-on-a-platform.html?_ga=2.71220112.143840515.1583333028-1717286999.1553115133

Haciendo más pruebas, resulta que moviendo la plataforma con rb.velocity, no hace falta hacer que el protagonista sea hijo de la plataforma, al caer sobre ella, ya se mueve con ella y si lo muevo con velocity se desplaza por encima de ella....pero si muevo la plataforma con rb.MovePosition, estonces no funciona.

Es que Unity es un poco contradictorio. En la documentación viene a decir que hacer un MovePosition es equivalente a realizar un transform.position y que sólo se emplee cuando el RigidBody es Kinematic. Yo entendía que si hacemos kinematic, deja de actuar la física y el movimiento se debería de realizar haciendo uso del transform, ya que el rigidbody es como si no existiera. Por otro lado, MoveRotation no dice nada que tenga que ser Kinematic.

 

Entiendo que como está no sería la forma óptima, pero tenía curiosidad por qué si pongo este código al protagonista que es hijo de la plataforma:

Quote

 

private void FixedUpdate()
    {
      float hor = Input.GetAxis("Horizontal") * 50 * Time.deltaTime;
       float ver = Input.GetAxis("Vertical") * 50 * Time.deltaTime;

        Debug.Log("Transform:" + transform.position + "- RigidBody" + rb.position);
    }

 

Puedo comprobar como transform.position se mueve y el rb permanece en su posición (lo correcto)

Y si añado este código: rb.MovePosition(transform.position + rb.transform.forward * ver + transform.right * hor);

se queda quieto, cuando transform.position debería guardar la posición del protagonista 'movido' por la plataforma (al estar debajo en la jerarquía) y que es lo que aparece en el Log si no pongo la orden MovePosition.

Share this post


Link to post
Share on other sites

Cuando llamas a MovePosition, el movimiento se ejecuta en el siguiente update de físicas (no en FIxedUpdate, sino en el momento en que el motor resuelve el siguiente paso físico). Si lo llamas varias veces, sólo la útima llamada se aplica. Si lo llamas todo el rato, estás estableciendo continuamente la misma posición que ya tiene, y evitando que sea movido por el motor físico. 

MovePosition es más recomendable para movimientos ocasionales (en mi opinión, MoveRotation se comporta igual, aunque no lo ponga el manual explícitamente). Viene a ser un "cuando actualices la física, pon este objeto en esta posición, asegurándote de que si ha colisionado con algo por el camino se ejecuten esas colisiones".

Un Rigidbody kinemático no es exactamente igual que un objeto sin Rigidbody (sólo con un collider). Puede aún tener Joints y empujar a otros objetos físicos.

If isKinematic is enabled, Forces, collisions or joints will not affect the rigidbody anymore. The rigidbody will be under full control of animation or script control by changing transform.position. Kinematic bodies also affect the motion of other rigidbodies through collisions or joints

Por lo que has dicho, yo intentaría haciendo la plataforma kinemática, el jugador un Rigidbody normal (esto supongo no es discutible). No haciéndolos padre e hijo, y asegurándote de que tienes fricción en la plataforma para que mueva al jugador con ella.  

Pero al final, el comportamiento depende un poco también del tipo de controlador que hayas programado para tu personaje (los scripts que tenga asociados y que lo manipulen en cada update, si es que los hay). Como ves, usar MovePosition para el personaje en general no es

Un saludo,

Share this post


Link to post
Share on other sites

 

4 hours ago, AngelFG said:

La idea es hacer que al subir a una plataforma (objeto A) el protagonista (Objeto B) se mueva con la plataforma y al mismo tiempo pueda moverse.

Y por qué estás usando padre e hijo? no es recomendable usar jerarquías para esto, lo mejor es que sean dos objetos completamente separados.

 

4 hours ago, AngelFG said:

Haciendo más pruebas, resulta que moviendo la plataforma con rb.velocity, no hace falta hacer que el protagonista sea hijo de la plataforma, al caer sobre ella, ya se mueve con ella y si lo muevo con velocity se desplaza por encima de ella....pero si muevo la plataforma con rb.MovePosition, estonces no funciona.

Exacto, aunque dejar que el personaje se mueva solo con la velocidad de la plataforma puede llegar a ser problemático en muchos casos, lo que se suele hacer es:

  1. Calcular el desplazamiento de la plataforma
  2. Calcular la velocidad de la plataforma ( el desplazamiento de 1 dividido el fixedDeltaTime)
  3. Agregar esa velocidad a la velocidad del pasajero

Y si fuera kinemático igual, pero en vez de sumarle la velocidad le tenés que sumar el desplazamiento.

Con MovePosition no te va a funcionar si es dinámico.

4 hours ago, AngelFG said:

Es que Unity es un poco contradictorio. En la documentación viene a decir que hacer un MovePosition es equivalente a realizar un transform.position

En la documentación dice: si el RB es dinámico (isKinematic = false) entonces llamar a MovePosition(P) equivale a hacer un transform.position = P. La razón de esto es porqué después del update físico se hace un "sync" entre rigidbody y transform, es decir que el transform toma el valor del Rigidbody (pos y rot). Ya que como dijeron arriba MovePosition se llama al final del ciclo, el sync en este caso especial te va a dar igual que hacer directamente transform.position = P.

Igual, con la físicas te diría que si no te quedan algunas cosasclaras te leas la parte en 2D (aunque busques algo en 3D), el encargado de la parte en 2D (Melvyn:  https://twitter.com/melvmay) es un tipo que explica muy bien muchos de estos conceptos base, muchos de ellos funcionan casi igual que en 3D (MovePosition, rigidbody.position, autoSync, etc).

 

 

 

Share this post


Link to post
Share on other sites

Gracias a los dos por contestar. Me ha quedado más claro todo.

Y gracias a pioj  por poner mejor el post. Tomaré nota para la próxima vez en el uso de etiquetas...

Pensando en la idea de lightbug de hacer que al protagonista se le sume la velocidad de la plataforma, se me ocurre este código (para a quien le pueda valer)

    // Script asociado al protagonista. 
    [SerializeField]
    public GameObject plataforma;


    private Rigidbody rb;
    private Rigidbody rbPlataforma;

    // Start is called before the first frame update
    void Start()
    {
        rb = GetComponent<Rigidbody>();
        rbPlataforma = plataforma.GetComponent<Rigidbody>();
    }


    private void FixedUpdate()
    {
       float hor = Input.GetAxis("Horizontal") * 5;
       float ver = Input.GetAxis("Vertical") * 5;

        if (hor == 0 && ver == 0)
        {            // Tenemos que poner esta condición para que cuando se mueva no reste o sume la velocidad de la plataforma a su velocidad
            Vector3 velocidad = new Vector3(rbPlataforma.velocity.x, rb.velocity.y, rbPlataforma.velocity.z);   // La velocidad y la dejamos para que tenga en cuenta la gravedad
            rb.velocity = velocidad;
        }
        rb.velocity += hor * transform.right + ver * transform.forward;


    }

Seguramente lo estaré liando más :)

Este script hace que un objeto B se mueva como otro objeto A, pero al mismo tiempo se podrá mover libremente.

También funciona con la gravedad activada siempre que los dos (A y B) tengan el mismo rozamiento (Drag)

Share this post


Link to post
Share on other sites

×
×
  • Create New...