Jump to content
UnitySpain
Sreaver

ANSWERED Problema con la gravedad y fuerza

Recommended Posts

Buenas tardes,

espero saber explicarme.

Soy muy novato, y estoy realizando pruebas para un juego que quiero hacer 2d para android con unity (en c #). Con el movimiento por teclas me resulta más fácil, pero ahora con el acelerómetro del teléfono estoy aún más perdido.

Os planteo la situación:

Una pelota y una rampa. Aplico rigibody 2d en la pelota, y un collaider para la rampa. Cuando comienza la aplicación, la pelota cae a la rampa y la gravedad hace el resto.

Si el acelerómetro maneja la pelota en el eje x funciona bien, pero cuando el móvil la rampa está totalmente horizontal, la pelota sigue actuando como si tuviese inclinación.

Adjunto a pequeños dibujos para aclarar el problema. La imagen 1 es conforme comienza el juego correctamente. La imagen 2 es con la base horizontal aún sigue habiendo gravedad. Edito el mensaje porque me acabo de dar cuenta que las imágenes 1 y 2 están cambiadas entre sí.

¿Será cosa del acelerómetro?

Creando los dibujos se me ha ocurrido una posible solución. Ir restando a la fuerza de la gravedad una cantidad limitada del ángulo de inclinación, pero no se si es posible.

Gracias anticipadas,

Imagen 2.jpg

Imagen 1.jpg

Edited by Sreaver

Share this post


Link to post
Share on other sites

Buenas Streaver,

La verdad nunca he usado funciones de acelerometros etc...pero entiendo que aunque tu gires el movil para unity la rampa sigue inclinada, quizás deberías inclinar todos los objetos en relación a la inclinación del movil.

 

 

Share this post


Link to post
Share on other sites

Gracias zelleGAmes,

lo he probado, pero entonces lo que giro es la plataforma y no es lo que quiero.

un saludo,

Share this post


Link to post
Share on other sites

Más datos. Aparte de que el problema es de Newton y no nuestro :D

Datos del rigidbody de la esfera. Cuando dices problema de acelerómetro, como lo utilizas? Código.

 

Share this post


Link to post
Share on other sites
25 minutes ago, iRobb said:

Más datos. Aparte de que el problema es de Newton y no nuestro :D

Datos del rigidbody de la esfera. Cuando dices problema de acelerómetro, como lo utilizas? Código.

 

Haciendo pruebas el acelerómetro parece estar bien. Las pruebas las estoy realizando con un Samsung s5, conectado por medio de unity remote 5.

Este es el código (Si es que se puede llamar código) XD: 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BallMove : MonoBehaviour
{
    public float SpeedD = 40f;
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        transform.position += new Vector3(Input.acceleration.x * Time.deltaTime, 0, 0) * SpeedD;
    }
}

El Rigidbody tiene todos los datos conforme se crea, lo único que he modificado la masa, la escala de la gravedad y el Linear Drag sin éxito, por lo que lo he vuelto a dejar todo igual.

Creo que la solución va estar en rotar la gravedad, porque creo que es eso realmente lo que quiero.

Muchas gracias

Share this post


Link to post
Share on other sites

Ya sabes que un ridigbody se debe modificar por físicas en fixedupdate, no en plan directo la transform.

Y me refería a los datos del rb de mass, etc. (la escala de la gravedad?)

Share this post


Link to post
Share on other sites
3 hours ago, Sreaver said:

Este es el código (Si es que se puede llamar código) XD: 


using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BallMove : MonoBehaviour
{
    public float SpeedD = 40f;
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        transform.position += new Vector3(Input.acceleration.x * Time.deltaTime, 0, 0) * SpeedD;
    }
}

 

Ponelo así mejor (si es que acceleration.x pasa cuadro a cuadro no debería dar problema en FixedUpdate, sino habrá que meter también un update que registre todos los deltas y aplicarlos en fixedUpdate):

Rigidbody2D rb2D

void Awake()
{
	rb2D = GetComponent<Rigidbody2D>();
}

void FixedUpdate()
{
      //es lo mismo que antes (en 2D), Vector2.right es <1,0>
      // y quité deltaTIme, la  simulación pide fuerzas o velocidades, no desplazamientos
      rb2D.velocity += Vector2.right * Input.acceleration.x * SpeedD; 
}

Yo recuerdo que hice un juego para Android que usaba el acelerómetro, me acuerdo que estuve algun tiempo usando un método X y diciendo "esto no anda!". Al final recuerdo que era otra funcionalidad la que debía utilizar, digo esto porque esto me suena mucho a mi situación. De todos modos acá está la doc oficial:

Parte de aceleración (conceptual):

As a device moves, its accelerometer hardware reports linear acceleration changes along the three primary axes in three-dimensional space. You can use this data to detect both the current orientation of the device (relative to the ground) and any immediate changes to that orientation.

Acceleration along each axis is reported directly by the hardware as G-force values. A value of 1.0 represents a load of about +1g along a given axis while a value of -1.0 represents -1g. If you hold the device upright (with the home button at the bottom) in front of you, the X axis is positive along the right, the Y axis is positive directly up, and the Z axis is positive pointing toward you.

Scripting:

You can read the Input.acceleration property to get the accelerometer reading. You can also use the Input.deviceOrientation property to get a discrete evaluation of the device's orientation in three-dimensional space. Detecting a change in orientation can be useful if you want to create game behaviors when the user rotates the device to hold it differently.

 

Al final yo creo entender que podés encontrar cambios en la orientación (aunque mencionan aceleración lineal también, por eso es algo confuso) y también la orientación final del dispositivo (?), probá con eso último, no lo se, podría ser que estés modificando Input.acceleration.x solamente cuando estés girando tu movil, probá con deviceOrientation.

Saludos

Share this post


Link to post
Share on other sites
10 hours ago, Sreaver said:

Si el acelerómetro maneja la pelota en el eje x funciona bien, pero cuando el móvil la rampa está totalmente horizontal, la pelota sigue actuando como si tuviese inclinación.

La inclinación casi nunca será cero en el dispositivo, siempre oscila en cantidades diminutas. ¿Tal vez lo que buscas es que cuando Input.acceleration.x sea muy pequeño y esté entre -0.1f y 0.1f (las cantidades son un ejemplo), ignore esas pequeñas cantidades y haga como que Input.acceleration.x sea igual a 0.0f?

Aunque si la pelota se mueve más rápido que una simple inclinación diminuta, podría ser algo que me pasó a mí hasta que descubrí que los ejes del acelerómetro cambian con el modo de orientación de la pantalla (mira los comentarios del ejemplo). Vamos, que Input.acceleration no funciona igual si el dispositivo está con la pantalla en "apaisado" o "retrato". A lo mejor Input.acceleration.x no es el eje que necesitas y te está registrando la inclinación adelante/atrás en lugar de la de izquierda/derecha (por lo de que la gente tiende a sujetar los dispositivos "recostados" sobre la mano, nunca rectos). ¿Has probado a usar otros ejes del Input.acceleration?

10 hours ago, Sreaver said:

Creando los dibujos se me ha ocurrido una posible solución. Ir restando a la fuerza de la gravedad una cantidad limitada del ángulo de inclinación, pero no se si es posible.

Creo que es demasiado complicado para lo que quieres hacer, pero poder, se puede hacer.

Como idea alternativa: en lugar de mover la pelota con el acelerómetro, podrías cambiar Physics.gravity en FixedUpdate() y que eso afecte a todos los Rigidbody del juego. Da un resultado diferente a lo que describes, pero quizá te resulte más cómodo. ¯\_(ツ)_/¯

Si necesitas ayuda con el código de cualquiera de estos enfoques, te echo una mano encantado (salvo la de restar fuerza). Pero especifica con cuál en concreto, que prefiero no tener que escribir tanto (ni llenar el hilo) para nada. xD

9 hours ago, Sreaver said:

lo he probado, pero entonces lo que giro es la plataforma y no es lo que quiero.

JAJAJAJAJA :4_joy: Esta idea es tremenda, pero yo no la aconsejaría para nada. Aún así, SI QUISIERAS, se arreglaría, por ejemplo, haciendo que todos los objetos del nivel (pelota, plataformas, obstáculos y cía.) sean ahijados (child) de un mismo objeto vacío y rotar ese objeto padre (parent). Pero repito: mala idea. Cambiar el Transform de un Rigidbody = problemas de rendimiento.

Edited by Deaymon

Share this post


Link to post
Share on other sites

Muchas gracias a todos!!

De momento he logrado que funcione cambiando el FixedUpdate, que ahora contiene solo esta línea: 

Physics2D.gravity = new Vector3((Input.acceleration.x)* speedX, ejey, 0);

Así funciona, pero ahora me encuentro con varios problemas. De este modo la pelota queda sin gravedad, así que he creado una variable: "ejey" que utilizo en negativo para crear una falsa gravedad, y funciona bien, pero cuando aplico un physics2d materials para un pequeño rebote que quiero conseguir, pero queda continuamente vibrando la pelota. Si disminuyo el valor del eje Y no vibra la pelota, pero tarda mucho en bajar. 

Deaymon lo de los ejes me volvió loco ayer, pero al final me dí cuenta que efectivamente mis ejes no coincidían con los del acelerómetro. Fue cuestión de ir probando en los tres lugares del vector y con distintos ejes.

Mañana probaré el código de Lightbug,

Lo digo, muchísimas gracias a todos!!

Share this post


Link to post
Share on other sites
22 hours ago, Sreaver said:

Physics2D.gravity = new Vector3((Input.acceleration.x)* speedX, ejey, 0);

Nota sobre esto: speedX cambia la gravedad de TODO, no solo la "velocidad" de la pelota, así que creo que deberías de dejar ese factor como un valor constante, ya sea 9.8f, que es el valor por defecto de la gravedad, o bien cambiarlo a otro valor que te dé mejor resultado (a no ser que quieras cambiar la fuerza de la gravedad a mitad de juego, en cuyo caso, no lo hagas constante, claro).

En cualquier caso, si hasta ahora te ha funcionado decentemente ese enfoque, lo que haría yo sería

const float GRAVEDAD = 9.8f;

private void FixedUpdate() {
	// Convertimos Input.acceleration.x del rango "-1 ~ 1" a "0 ~ π" radianes para simplificar cálculos
	float angulo = (Input.acceleration.x + 1f) * Mathf.PI * 0.5f;
	// Aplicamos trigonometría para "rotar" la gravedad
	Physics2D.gravity = new Vector2( -Mathf.Cos(angulo), Mathf.Sin(angulo) ) * GRAVEDAD;
}

EDIT: Sobre cambiar la fuerza de la gravedad a mitad de juego, puedes usar Rigidbody2D.gravityScale para cambiar cuánto afecta la gravedad a ese Rigidbody en particular.
EDIT2: ¡Mathf.Sin(angulo) hará que la gravedad vaya hacia arriba! Ponle un '-' delante para invertirlo (xD Socorro, qué fallo más básico)

Edited by Deaymon

Share this post


Link to post
Share on other sites
On 8/31/2019 at 1:09 AM, Deaymon said:

Nota sobre esto: speedX cambia la gravedad de TODO, no solo la "velocidad" de la pelota, así que creo que deberías de dejar ese factor como un valor constante, ya sea 9.8f, que es el valor por defecto de la gravedad, o bien cambiarlo a otro valor que te dé mejor resultado (a no ser que quieras cambiar la fuerza de la gravedad a mitad de juego, en cuyo caso, no lo hagas constante, claro).

En cualquier caso, si hasta ahora te ha funcionado decentemente ese enfoque, lo que haría yo sería


const float GRAVEDAD = 9.8f;

private void FixedUpdate() {
	// Convertimos Input.acceleration.x del rango "-1 ~ 1" a "0 ~ π" radianes para simplificar cálculos
	float angulo = (Input.acceleration.x + 1f) * Mathf.PI * 0.5f;
	// Aplicamos trigonometría para "rotar" la gravedad
	Physics2D.gravity = new Vector2( -Mathf.Cos(angulo), Mathf.Sin(angulo) ) * GRAVEDAD;
}

EDIT: Sobre cambiar la fuerza de la gravedad a mitad de juego, puedes usar Rigidbody2D.gravityScale para cambiar cuánto afecta la gravedad a ese Rigidbody en particular.
EDIT2: ¡Mathf.Sin(angulo) hará que la gravedad vaya hacia arriba! Ponle un '-' delante para invertirlo (xD Socorro, qué fallo más básico)

Si, en cuanto ha empezado a flotar la pelota hacia arriba me he dado cuenta, pero me ha servido para detectar que cuando el dispositivo android estaba del revés, la pelota no caía, y para ello he añadido este código:

float gradosY;

gradosY = Input.acceleration.y;

        if (gradosY < 0)
        {
            Physics2D.gravity = new Vector2(-Mathf.Cos(angulo), -Mathf.Sin(angulo)) * Gravedad;
        }
        else
        {
            Physics2D.gravity = new Vector2(-Mathf.Cos(angulo), Mathf.Sin(angulo)) * Gravedad;
        }

Muchas gracias

Share this post


Link to post
Share on other sites

¿Le ha explicado alguien la diferencia entre ACELERÓMETRO y GIROSCOPIO? Es importante para entender cómo funciona lo que trata de hacer...

Share this post


Link to post
Share on other sites
8 hours ago, pioj said:

¿Le ha explicado alguien la diferencia entre ACELERÓMETRO y GIROSCOPIO? Es importante para entender cómo funciona lo que trata de hacer...

Efectivamente hasta tu mensaje no lo distinguía.  De echo creo que aún no lo tengo claro. 

¿Acelerómetro detecta la posición del terminal y giroscopio es el encargado de hacerlo girar? 

¿Entonces lo estoy enfocando mal? 

Share this post


Link to post
Share on other sites

El acelerómetro, como su nombre indica, detecta cambios de aceleración. Los cambios de posición con movimiento que afecten al dispositivo. Ahora bien, como detecta aceleraciones y estamos en la Tierra, las rotaciones que afecten al eje Y serán detectadas debido a la gravedad. Y si es rotado solo horizontalmente no habrá aceleraciones que detectar.
En cambio el giróscopo detecta rotaciones en todos los ejes.

¿Por qué a veces se utiliza el acelerómetro para medir la rotación? Aunque es más complejo utilizarlo para rotaciones al incluir la gravedad en el mismo vector y no para todos los ejes, tiene un coste de proceso (leáse batería) muy inferior al giróscopo. Se puede decir que es un "hack" ya que no se utiliza para lo que fue diseñado.

Por último, la posición sería detectada por el GPS.

Share this post


Link to post
Share on other sites
13 hours ago, iRobb said:

El acelerómetro, como su nombre indica, detecta cambios de aceleración. Los cambios de posición con movimiento que afecten al dispositivo. Ahora bien, como detecta aceleraciones y estamos en la Tierra, las rotaciones que afecten al eje Y serán detectadas debido a la gravedad. Y si es rotado solo horizontalmente no habrá aceleraciones que detectar.
En cambio el giróscopo detecta rotaciones en todos los ejes.

¿Por qué a veces se utiliza el acelerómetro para medir la rotación? Aunque es más complejo utilizarlo para rotaciones al incluir la gravedad en el mismo vector y no para todos los ejes, tiene un coste de proceso (leáse batería) muy inferior al giróscopo. Se puede decir que es un "hack" ya que no se utiliza para lo que fue diseñado.

Por último, la posición sería detectada por el GPS.

Buenas noches. 

Me queda bastante más claro, pero aún así me parece un tema complejo. 

Creo que estoy enfocando mal el juego desde el principio. Rotar la gravedad con el acelerómetro me dio un resultado aceptable, pero surge un nuevo problema.

Cuando la pelota está en el aire, se puede seguir girando la gravedad, por lo que la pelota cambia la trayectoria. Es fácil de solucionar, sólo tengo que hacer que detecte cuando está tocando una base y entonces pueda rotar y cuando esté en el aire no, pero eso creo que no me sirve. Me resulta difícil de cabeza, está madrugada haré unas pruebas.

Un saludo 

Share this post


Link to post
Share on other sites

×
×
  • Create New...