Jump to content
Sign in to follow this  
nomoregames

ANSWERED gravedad aplicada en el eje local y

Recommended Posts

Muy buenas a todos 

Esta duda guarda relación con otra que postee hace ya algún tiempo llamado gravedad planetaria. 

En ella me explique fatal, y acabasteis poniéndome delante un montón de código que ni entendía, ni servia para lo que buscaba...

Hoy me presento ante ustedes con una explicación mejor y un poco mas de conocimiento sobre la espalda.

 

Para ejemplificar, diré que estoy trabajando en unas botas de gravedad, o imantadas... de esas que se ponen en las pelis para andar por las paredes ignorando cualquier ley física. Es decir, la gravedad siempre se aplicara hacia los pies de el jugador

image.pngimage.png

(la gravedad son las flechas)

Para hacer este efecto, uso este script

 RaycastHit hit;
      
        if (Physics.Raycast(transform.position,-transform.up * 4, out hit))
        {

           Physics.gravity = (hit.point - transform.position);
          
           
        }

Lo que me queda es hacer que el eje y quede alineado con el hit.point, para hacerlo he leído que tengo qué usar:

            transform.rotation = Quaternion.FromToRotation(-transform.up, hit.point - transform.position);

pero nada....

 

Sabéis como solucionar este problema? 

 

Gracias

Share this post


Link to post
Share on other sites

Primero y más importante. Formatear el código de forma correcta. 

Este tema puede ser un poco complejo cuando no dominas la matemática básica que lo rodea - 

1 - Identificar la normal de la superficie. 

2 - Modificar el valor de vector de gravedad basándonos en la normal de la superficie <- Normalizar

3 - Rotar el personaje según el vector de gravedad.

Share this post


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

Primero y más importante. Formatear el código de forma correcta. 

A que te refieres? He posteado bien el codigo? es eso? XD

A que te refieres con identificar el normal de la superficie?

 

Gracias por responder 

Share this post


Link to post
Share on other sites

el normal de la superficie es hacia donde "apunta" la superficie, el poligono con el que ha "impactado" tu rayo... 

la normal de una superficie completamente horizontal seria un vector que apuntaria hacia arriba..

esta informacion esta por ejemplo dentro del "hit" (hit.normal)

normalizar un vector seria hacer que ese vector mida 1 (su magnitud,su longitud) esto se usa para vectores de direccion a los que luego vayas a usar para aplicar una "fuerza" con un valor determinado ...o mover una distancia determinada (porejemplo un vector de direccion por una distancia sirve para mover un objeto esa distancia en esa direccion)

porejemplo para tu caso de "las botas de gravedad" puedes lanzar todo el rato un rayo (raycast) hacia abajo de tu "player" ( -transform.up) y entonces consigues el "hit.normal" (la normal de la superficie) seria combeniente que creases una capa (layerMask) para el suelo para que el raycast compruebe solo las colisiones contra el suelo y no contra enemigos u otros objetos...

espera un poco que me pillas en la calle...

ahora miro como era para orientae el objeto hacia "arriba" de la superficie que pisas y te lo pongo

Share this post


Link to post
Share on other sites

ya estoy en casa

a ver, seria algo asi:

 

LayerMask lmask = (1 << 10);//he puesto la capa 10,  ...pon el numero que sea la capa "suelo"
//esto es para que las colisiones solo se comprueben contra esa capa (la 10)
RaycastHit hit;
float radius = 0.4f;//radio del la sphereCast, ...ponlo un poco mas pequeño que el radio de tu personaje
float distance = 4;//maxima distancia a la que el rayo llega

if (Physics.SphereCast(transform.position, radius, transform.up, out hit, distance, lmask))) {
	Vector3 newUp = hit.normal;
  	//la normal del suelo
	Vector3 left = Vector3.Cross(transform.forward, newUp);
  	//si es un juego 2d puedes, y estas usando solo las coordenadas X e Y, puedes poner Vector3 left = new Vector3(0,0,1);
    Vector3 newForward = Vector3.Cross(newUp, left);//con esto hayas la nueva direccion a la que tiene que "mirar" tu player
   	Quaternion oldRot = transform.rotation;//esto es para "cojer" tu antigua rotacion;
    Quaternion newRot = Quaternion.LookRotation(newForward, newUp);//esto es para calcular la nueva rotacion
  	transform.rotation = Quaternion.Lerp(oldRot, newRot, 0.1f);//esto es para que rote "suavemente" entre la antigua rotacion y la nueva
}

 

yo tambien lo que haria seria calcular y aplicar la gravedad en el script, en vez de usar "physics.gravity", aya que physics.gravity va a afectar a todos los objetos que tengan graveda y no solo al player.

seria muy facil implementar la gravedad. necesitas un vector de direccion para la direccion de la gravedad. necesitas un float para ver a que velocidad estas cayendo. ese float tiene que ir incrementandose contra mas tiempo estes en el aire y volverse cero (0) cuando tocas suelo. y luego tiene que aplicar ese movimiento al player.  puedes usarlo tambien para saltar. poniendo un valor negativo a la velocidad a la que caes. yo suelo hacer eso. uso la gravedad (el vector y el float) tanto para caer como para saltar. 

Edited by Igor

Share this post


Link to post
Share on other sites

No me funciona... pero creo que mas que error tuyo, es falta de conocimiento por mi parte

Se que es lo que hace Vector3.cross, pero no acabo de entender para que lo utilizas...

 

En todo caso, muchísimas gracias por responder y por los comentarios explicativos en el código 

Edited by nomoregames

Share this post


Link to post
Share on other sites
20 hours ago, nomoregames said:

Physics.gravity = (hit.point - transform.position);

Eso está mal, nunca vas a cambiar de Vector3.down de gravedad. El raycast (aunque prefiero un sphere cast) tiene que darte solamente la normal. Una vez que tengas esto es cuestión de hacer gravityDirection = - normal (tenés bastantes problemas con esto, pero para arrancar ta bien).

gravity = gravityMagnitude * gravityDirection;

Luego para rotar el personaje:

Quaternion targetDeltaRotation = Quaternion.FromToRotation( transform.up , - gravityDirection );

(definí "deltaRotation" como privado de la clase, slerpSpeed y suavizar también )
deltaRotation = suavizar ? Quaternion.Slerp( deltaRotation , targetDeltaRotation , slerpSpeed * Time.deltaTime ) : targetDeltaRotation;

transform.rotation = deltaRotation * transform.rotation; 

Fijate que la multiplciación de Quaternions no es conmutativa, es decir que Qa * Qb != Qb * Qa . Me pasa todo el rato que algo debería funcionar y simplemente no lo hace porque las puse alrevés.

Como dice @Igor no uses Physics.gravity, vas a cambiar la gravedad de todo cuerpo rígido en la escena. Aplicá tu propia gravedad:

rigidbody.velocity += gravity * Time.deltaTime;

 

Edited by lightbug

Share this post


Link to post
Share on other sites
7 hours ago, Igor said:

if (Physics.SphereCast(transform.position, radius, transform.up, out hit, distance, lmask))) {

huy! perdon.... 

donde he puesto "transform.up" tendria que ser en negativo.... poner un "menos" delante  ( -transform.up)

...normal que no te funcione... estamos lanzando el "rayo" hacia arriba.... en vez de hacia abajo...

😅

sorry

Share this post


Link to post
Share on other sites

bua, tranki....   errores de esos mil....   lo chungo es cuando llevas nosecuantas horas buscando el error y de repente te das cuenta que es una tonteria asi....  la cara de tonto que se me queda es peor que la de Tobey Maguire en su papel de Peter Parker hablando con Mary Jane en la primera peli de Spiderman

  • Like 1

Share this post


Link to post
Share on other sites

Gracias por vuestras respuestas! he creado mi propia gravedad y todo funciona 👌...

eso si... tengo que aprender si o si lo de por que se usa .normal (supongo que para que luego al multiplicar... como es uno, de como resultado el multiplicador)

También tengo que mirarme bien lo de Vector.cross

No se... para mi es como tener una espina clavada el echo de tener un script en mi proyecto al cual no entiendo

Gracias

PD: he añadido la siguiente linea de código

transform.localEulerAngles  += new Vector3( 0,Input.GetAxis("Mouse X"),0);

Y pasa algo muy muy raro... cuanto mas inclinado está el jugador mas lento gira 😨... eso por que ocurre? 

 

Edited by nomoregames

Share this post


Link to post
Share on other sites

lo de que gire mas lento no tiene nada que ver con la linea de codigo que has puesto...  "translate" es para mover objetos...  con esta linea se supone que el objeto se mueve arriba o abajo (en el "world") dependiento si pulsas arriba o abajo en el teclado/gamepad

vector.cross sirve para obtener el vector perpendicular al plano que forman otros dos vectores... osea si tiene un vector que apunta hacia adelante, y otro que apunta hacia la derecha... entre los dos vectores se puede interpretar como que forman un planl horizontal...  si haces el vector cross de esos dos obtendrias un vector que apuntaria hacia arriba (o hacia abajo, dependiendo del orden que pongas los otros dos vectores)

porejemplo en mi script de orientar al personaje hacia donde apunte la normal de la superficie...

LayerMask lmask = (1 << 10);
RaycastHit hit;
float radius = 0.4f;
float distance = 4;

if (Physics.SphereCast(transform.position, radius, -transform.up, out hit, distance, lmask))) {
	Vector3 newUp = hit.normal;
  	//la normal del suelo, hacia donde "apunta" la superficie del suelo, hacia donde esta mirando el poligono
  
	Vector3 left = Vector3.Cross(transform.forward, newUp);
  	//el vector "forward" del player y el vector "newup" del del suelo forman un plano,
  	//dos lineas que se cruzan forman un plano, imagina dos boligrafos, si se cruzas esarian delimitando un plano
  	//.... podrias poner un papel que tocase los dos boligrafos y solo podria estar ese papel ese plano en una posicion...
  	//con esa linea "cross" obtengo un vector "left" perpendicular al plano que formarian esos boligrafos... 
  	//al tratarse de el "forward" del player y el "up" del suelo pues sale un vector "left" 
  	// ...que NO es igual al "left" del player porque el "up" del player no es igual al "up" del suelo...
  
    Vector3 newForward = Vector3.Cross(newUp, left);
  	//ahora hago lo mismo con el "nuevoLeft" y el vector "up" del suelo
  	//y obtengo un nuevo vector forward que es el deveria estar mirando el player para estar "de pie" 
  	//...orientado correctamente encima de ese poligono del suelo
  
   	Quaternion oldRot = transform.rotation;//esto es para "cojer" tu antigua rotacion;
    Quaternion newRot = Quaternion.LookRotation(newForward, newUp);//esto es para calcular la nueva rotacion
  	transform.rotation = Quaternion.Lerp(oldRot, newRot, 0.1f);//esto es para que rote "suavemente" entre la antigua rotacion y la nueva
}

 

Edited by Igor

Share this post


Link to post
Share on other sites

Madre mia, craso error... lo que quería poner era

transform.localEulerAngles  += new Vector3( 0,Input.GetAxis("Mouse X"),0);

 

Share this post


Link to post
Share on other sites

hola...

he acabado de escribir lo de arriba... que lo habia dejado a medias

te he explicado como hace mi codigo para rotar el objeto para que se oriente como el suelo.

 

6 minutes ago, nomoregames said:

Madre mia, craso error... lo que quería poner era


transform.localEulerAngles  += new Vector3( 0,Input.GetAxis("Mouse X"),0);

 

deverias usar transform.Rotate(x,y,z)  ...ya que tu objeto no va a estar siempre horizontal....  Rotate() lo rota respecto a la rotacion que ya tenga

 

Edited by Igor

Share this post


Link to post
Share on other sites

haber si he e entendido tus explicaciones...

image.png

lo rojo es el vector.normal de el suelo que es el que asignaste a newUp...

el azul es transform.forward

y el rosa es el Vector3.cross de ambos

 

ahora se hace el cross de el rosa y el rojo... 

image.png

dando como resultado el azul... y esa... no es la dirección de el suelo, no?

 

Lo estoy explicando todo en base a lo que creo que he entendido 

Buenas

 

Share this post


Link to post
Share on other sites
Sign in to follow this  

UnitySpain © Todos los derechos reservados 2020
×
×
  • Create New...