Podrias implementar animation controller para lo primero que funciona a partir de eventos, por lo que usarias animaciones para las diferentes direcciones, y para lo segundo es tema vectores y posicion con respecto a la camara que es un poco mas complicado, pero todo depende de lo que quieras lograr.
¡RECUERDA QUE SI ERES UN NUEVO USUARIO, DEBES PRESENTARTE PARA PODER PUBLICAR MENSAJES! | TENEMOS CANAL OFICIAL DE TELEGRAM: t.me/unity3dspain
Mover y rotar personaje con teclas WASD
Iniciado por al_aranda, Noviembre 15, 2015, 07:13:21 PM
Tema anterior - Siguiente tema-
GSG3D

- Dev Junior
- Mensajes: 370
-
- En línea
-
al_aranda

- Newbie
- Mensajes: 7
-
- En línea
Muchas gracias por responder. Pero se podrían activar distintas animaciones según si el personaje se mueve hacia delante, hacia atrás o hacia los lados? Es lo que más me gustaría conseguir, pero la verdad, por el tiempo que tengo y por mis conocimientos, lo veo algo super chungo... Habría alguna función para eso?De no ser posible eso (yo de hecho ya lo había descartado) me gustaría poder mover a mi personaje con las teclas WASD pero siempre con la animación de correr hacia adelante, y que según la tecla que pulses, pues el personaje rote hacia esa dirección y siga desplazándose. Es que no sé si me explico con esta última parte.Muchas gracias!
-
GSG3D

- Dev Junior
- Mensajes: 370
-
- En línea
Lo primero es manejar una amigable interfaz que con un par de tutoriales se aprende y te ahorra un monton de trabajo para las transacciones, y para lo segundo si tienes una camara fija al personaje cambiale la rotacion del personaje y ya esta, ademas de utilizar boleanos para que tu personaje no gire.
-
al_aranda

- Newbie
- Mensajes: 7
-
- En línea
Imagínate que la cámara no está por detrás del personaje, sino encima (no exactamente de forma perpendicular a éste, pero arriba) de manera que se verá buena parte del escenario. La cámara solo seguirá al personaje en traslación, no en rotación, de manera que sólo rotaría el personaje. Sería un estilo como ésto https://www.youtube.com/watch?v=WDUORDhHCm8 Gracias!
-
GSG3D

- Dev Junior
- Mensajes: 370
-
- En línea
Y bueno solo es cuestion de inputs (que ya los tienes, wasd) y algunas condiciones con respecto a su posicion inicial.
Por ejemplo, estamos en la posicion inicial forward, si apretamos la W esta no girara ya que detectamos que ya esta en tal, por lo cual ignora esto y avanzamos.
Si presionamos la A vemos que estando en w(forward) para llegar a A(left) se debe restar -90 grados y asi respectivamente.
No se si logras comprender.
Por ejemplo, estamos en la posicion inicial forward, si apretamos la W esta no girara ya que detectamos que ya esta en tal, por lo cual ignora esto y avanzamos.
Si presionamos la A vemos que estando en w(forward) para llegar a A(left) se debe restar -90 grados y asi respectivamente.
No se si logras comprender.
-
al_aranda

- Newbie
- Mensajes: 7
-
- En línea
vale, pensé en eso de los grados, pero no sabía si sería una forma óptima. Entonces lo suyo seria obtener los inputs "Horizontal" y "Vertical" y a partir de ahi crear una serie de condicionales del estilo: si apreto la tecla A entonces obtener posicion del personaje y rotarlo -90º. Pero entonces habría que hacer tantos condicionales como opciones posibles no? porque tu puedes rotar desde forward a left, pero tambien desde forward a back, o desde back a right, etc...
-
GSG3D

- Dev Junior
- Mensajes: 370
-
- En línea
Exacto.
-
al_aranda

- Newbie
- Mensajes: 7
-
- En línea
en este caso deberia usar Quaternions?
-
al_aranda

- Newbie
- Mensajes: 7
-
- En línea
he hecho lo siguiente. El resultado se parece más a lo que buscaba, pero no me acaba de convencer...
public float speed = 6f;
Animator animPlayer; void Awake()
{
animPlayer = GetComponent<Animator>();
}
// Update is called once per frame
void Update () { float h = Input.GetAxisRaw("Horizontal");
float v = Input.GetAxisRaw("Vertical");
Move();
Animating(h, v);
} void Move()
{
if (Input.GetKey(KeyCode.W))
{
transform.Translate(0f, 0f, speed * Time.deltaTime, Space.World);
transform.eulerAngles = new Vector3(0, 0, 0);
} if (Input.GetKey(KeyCode.S))
{
transform.Translate(0f, 0f, -speed * Time.deltaTime, Space.World);
transform.eulerAngles = new Vector3(0, 180f, 0);
} if (Input.GetKey(KeyCode.A))
{
transform.Translate(-speed * Time.deltaTime, 0f, 0f, Space.World);
transform.eulerAngles = new Vector3(0, -90f, 0);
} if (Input.GetKey(KeyCode.D))
{
transform.Translate(speed * Time.deltaTime, 0f, 0f, Space.World);
transform.eulerAngles = new Vector3(0, 90f, 0);
}
} void Animating(float h, float v)
{
bool idle = ((h == 0) && (v == 0));
animPlayer.SetBool("IsMoving", !idle);
}
public float speed = 6f;
Animator animPlayer; void Awake()
{
animPlayer = GetComponent<Animator>();
}
// Update is called once per frame
void Update () { float h = Input.GetAxisRaw("Horizontal");
float v = Input.GetAxisRaw("Vertical");
Move();
Animating(h, v);
} void Move()
{
if (Input.GetKey(KeyCode.W))
{
transform.Translate(0f, 0f, speed * Time.deltaTime, Space.World);
transform.eulerAngles = new Vector3(0, 0, 0);
} if (Input.GetKey(KeyCode.S))
{
transform.Translate(0f, 0f, -speed * Time.deltaTime, Space.World);
transform.eulerAngles = new Vector3(0, 180f, 0);
} if (Input.GetKey(KeyCode.A))
{
transform.Translate(-speed * Time.deltaTime, 0f, 0f, Space.World);
transform.eulerAngles = new Vector3(0, -90f, 0);
} if (Input.GetKey(KeyCode.D))
{
transform.Translate(speed * Time.deltaTime, 0f, 0f, Space.World);
transform.eulerAngles = new Vector3(0, 90f, 0);
}
} void Animating(float h, float v)
{
bool idle = ((h == 0) && (v == 0));
animPlayer.SetBool("IsMoving", !idle);
}
-
Antonio

- Debugger
- Mensajes: 194
-
- En línea
Hola!
Bueno, el grupo de condiciones comprobando tecla por tecla, pues es una manera, pero no creo que sea la más usada, de hecho, en ese código que has puesto, ya tienes otros inputs que podrían reducir las línes un poquito.
En la función Update estás llamando estas variables:
Si miras el código del character controller de ese shooter, verás que lo que hace es usar esos inputs para crear un vector de dirección, que es el que se utiliza para decirle al personaje en qué dirección moverse, (tu en tus condicciones, sabes que Translate está usando otro vector de dirección, por eso pones cada una en función del (x,y,z). El código del tutorial también tiene en cuenta eso.
Esto lo que hace es 1º normalizar el vector, es decir, hacer que su longitud siempre sea 1, (cuando se pulsa 1 sóla tecla, la longitud se pone a 1, pero cuando se pulsa 2 teclas (1,0,1) la longitud es un poco mayor, por lo que si no la normalizamos, el jugador se movería más rápido al moverse en diagonal). Una vez normalizado a 1, multiplica ese vector por la velocidad (a lo mejor 1 es muy lento... pues le aumenta la velocidad aquí, también si hiciera falta reducirla, porque esté andando, atrapado o lo que sea, pues se atacaría por aqui). Y finalmente lo multiplica por el misterioso Time.deltaTime que es lo que hace que la distancia recorrida sea por segundo, y no por ciclo. (Si no estuviera, el personaje se movería más distancia por segundo en ordenadores que ejecuten el juego a 60 frames que en los ordenadores que lo ejecuten a 30 frames).
/---------------------/Si tomas ese vector de dirección, puedes reutilizarlo para más cosas, por ejemplo, para gestionar las animaciones. En el esquema del animator, puedes crear un "Blend Tree" que se gestione por 1 o 2 variables floats (por ejemplo, puedes poner que una sea la velocidad de movimiento (aunque tú estás usando sólo un bool para andar de modo que esta no es imprescindible) y la otra que sea le diga qué animaciones lanzar (adelante, atrás, lateral izquierda, lateral derecha, diagonales...).
Así que lo único que faltaría sería averiguar esa variable que decide las animaciones, teniendo el vector dirección, sabemos hacia qué lugar se está moviendo el personaje, también sabemos que la animación depende del punto a donde está mirando (que en ese ejemplo de Unity, es la dirección del ratón), luego entiendo que la animación varia dependiendo del ángulo entre el vector dirección y la dirección a la que está mirando (que no es más que otro vector3, punto de destino - punto de origen) (o lo que es lo mismo, punto donde está apuntando el ratón - transform.position del personaje).Pensando en ángulos, podríamos ver lo siguiente, Si el ángulo entre la dir movimiento y la dir de mira es:
<= 45º, entonces hay poca diferencia, el personaje ejecutaría la animación de correr adelante.
>45º && < 135º, entonces el personaje está moviéndose lateralmente.
>135º, entonces el personaje se está moviendo hacia atrás. Este sistema funciona pero hay un problema como ves, y es en los laterales. ¿Cómo diferenciar el lateral izq del lateral derecho? ya que muchas funciones del Ángulo, sólo dan la diferencia en positivo, no distingue entre un lado u otro. Por ello hay que complicar la cosa un poco más, en mi caso uso la función Atan ( http://docs.unity3d.com/ScriptReference/Mathf.Atan2.html">http://docs.unity3d.com/ScriptReference/Mathf.Atan2.html ).
La Atan2 permite calcular el ángulo de manera más precisa por lo que sí nos dirá si es +90 o -90, pero si lo usas sin más sobre el vector dirección, verás que los resultados están fijados al espacio global (si el personaje está mirando hacia +z, entones te dirá los ángulos correctamente, pero si el personaje esta mirando hacia +X es decir, hacia la derecha de la pantalla, entonces no te dirá los resultados exactos) por eso antes de usar la función Atan, necesitamos crear un nuevo Vector3 que transforme ese vector de movimiento adaptado al espacio global, en un vector de movimiento adaptado al game object del personaje.
Ejemplos:
- El personaje está mirando hacia la derecha y se está moviendo hacia la derecha, en el espacio global, el personaje se está moviendo en dirección (1,0,0) pero en el espacio local, el personaje se está moviendo en dirección (0,0,1), es decir, el personaje se está moviendo hacia su flecha azul que en ese momento, está apuntando hacia la derecha de la pantalla.
- El personaje está mirando hacia la pantalla, pero se está moviendo hacia derecha de la pantalla, (el personaje se estaría moviendo lateralmente), en este caso, su dirección de movimiento global es (1,0,0) pero su dirección de movimiento local sería (-1,0,0) (el personaje se está moviendo hacia su izquierda).
Por esto, necesitamos transformar la dirección global del movimiento a la dirección local del personaje, eso se puede hacer con la función InverseTransformDirection. Algo así:
Bueno, el grupo de condiciones comprobando tecla por tecla, pues es una manera, pero no creo que sea la más usada, de hecho, en ese código que has puesto, ya tienes otros inputs que podrían reducir las línes un poquito.
En la función Update estás llamando estas variables:
float h = Input.GetAxisRaw("Horizontal");
float v = Input.GetAxisRaw("Vertical");Los ejes (axis) "Horizontal" y "Vertical" puedes verlos en el menú Input ( Edit -> Project Settings -> Input), ahí podrás ver que esos ejes se corresponden con las teclas WSAD y las flechas arriba, abajo, izquierda y derecha. Es decir, cuando pulsas la tecla D, o la flecha derecha, el GetAxisRaw ("Horizontal") se pone a 1. Si pulsas la A o la flecha izquierda, el GetAxisRaw ("Horizontal") se pone a -1 y así... Y luego estos datos los guardas en las variables h y v, pero luego no los usas.Si miras el código del character controller de ese shooter, verás que lo que hace es usar esos inputs para crear un vector de dirección, que es el que se utiliza para decirle al personaje en qué dirección moverse, (tu en tus condicciones, sabes que Translate está usando otro vector de dirección, por eso pones cada una en función del (x,y,z). El código del tutorial también tiene en cuenta eso.
void Move (float h, float v)Más corto... movement = movement.normalized * speed * Time.deltaTime;
{
movement.Set (h,0,v);
movement = movement.normalized * speed * Time.deltaTime;
playerRigidbody.MovePosition (transform.position + movement);
}
Esto lo que hace es 1º normalizar el vector, es decir, hacer que su longitud siempre sea 1, (cuando se pulsa 1 sóla tecla, la longitud se pone a 1, pero cuando se pulsa 2 teclas (1,0,1) la longitud es un poco mayor, por lo que si no la normalizamos, el jugador se movería más rápido al moverse en diagonal). Una vez normalizado a 1, multiplica ese vector por la velocidad (a lo mejor 1 es muy lento... pues le aumenta la velocidad aquí, también si hiciera falta reducirla, porque esté andando, atrapado o lo que sea, pues se atacaría por aqui). Y finalmente lo multiplica por el misterioso Time.deltaTime que es lo que hace que la distancia recorrida sea por segundo, y no por ciclo. (Si no estuviera, el personaje se movería más distancia por segundo en ordenadores que ejecuten el juego a 60 frames que en los ordenadores que lo ejecuten a 30 frames).
/---------------------/Si tomas ese vector de dirección, puedes reutilizarlo para más cosas, por ejemplo, para gestionar las animaciones. En el esquema del animator, puedes crear un "Blend Tree" que se gestione por 1 o 2 variables floats (por ejemplo, puedes poner que una sea la velocidad de movimiento (aunque tú estás usando sólo un bool para andar de modo que esta no es imprescindible) y la otra que sea le diga qué animaciones lanzar (adelante, atrás, lateral izquierda, lateral derecha, diagonales...).
Así que lo único que faltaría sería averiguar esa variable que decide las animaciones, teniendo el vector dirección, sabemos hacia qué lugar se está moviendo el personaje, también sabemos que la animación depende del punto a donde está mirando (que en ese ejemplo de Unity, es la dirección del ratón), luego entiendo que la animación varia dependiendo del ángulo entre el vector dirección y la dirección a la que está mirando (que no es más que otro vector3, punto de destino - punto de origen) (o lo que es lo mismo, punto donde está apuntando el ratón - transform.position del personaje).Pensando en ángulos, podríamos ver lo siguiente, Si el ángulo entre la dir movimiento y la dir de mira es:
<= 45º, entonces hay poca diferencia, el personaje ejecutaría la animación de correr adelante.
>45º && < 135º, entonces el personaje está moviéndose lateralmente.
>135º, entonces el personaje se está moviendo hacia atrás. Este sistema funciona pero hay un problema como ves, y es en los laterales. ¿Cómo diferenciar el lateral izq del lateral derecho? ya que muchas funciones del Ángulo, sólo dan la diferencia en positivo, no distingue entre un lado u otro. Por ello hay que complicar la cosa un poco más, en mi caso uso la función Atan ( http://docs.unity3d.com/ScriptReference/Mathf.Atan2.html">http://docs.unity3d.com/ScriptReference/Mathf.Atan2.html ).
La Atan2 permite calcular el ángulo de manera más precisa por lo que sí nos dirá si es +90 o -90, pero si lo usas sin más sobre el vector dirección, verás que los resultados están fijados al espacio global (si el personaje está mirando hacia +z, entones te dirá los ángulos correctamente, pero si el personaje esta mirando hacia +X es decir, hacia la derecha de la pantalla, entonces no te dirá los resultados exactos) por eso antes de usar la función Atan, necesitamos crear un nuevo Vector3 que transforme ese vector de movimiento adaptado al espacio global, en un vector de movimiento adaptado al game object del personaje.
Ejemplos:
- El personaje está mirando hacia la derecha y se está moviendo hacia la derecha, en el espacio global, el personaje se está moviendo en dirección (1,0,0) pero en el espacio local, el personaje se está moviendo en dirección (0,0,1), es decir, el personaje se está moviendo hacia su flecha azul que en ese momento, está apuntando hacia la derecha de la pantalla.
- El personaje está mirando hacia la pantalla, pero se está moviendo hacia derecha de la pantalla, (el personaje se estaría moviendo lateralmente), en este caso, su dirección de movimiento global es (1,0,0) pero su dirección de movimiento local sería (-1,0,0) (el personaje se está moviendo hacia su izquierda).
Por esto, necesitamos transformar la dirección global del movimiento a la dirección local del personaje, eso se puede hacer con la función InverseTransformDirection. Algo así:
Vector3 localMove = transform.InverseTransformDirection(movement);Mira como la aplica en transform (minúscula) que es el del propio personaje. Así, ya con el localMove podemos calcular el ángulo que buscamos con Atan2:
float movangle = Mathf.Atan2(localMove.x, localMove.z) * Mathf.Rad2Deg;Y finalmente, llevas ese movangle al Animator para gestionar con él la animación que se debe ejecutar.
-
al_aranda

- Newbie
- Mensajes: 7
-
- En línea
Muchísimas gracias Adngel por tan detallada respuesta! Entonces sería posible crear los mismos controles que en el tutorial (WASD y mouse para apuntar) pero lanzando diferentes animaciones según si el personaje va hacia adelante, hacia atrás o hacia los lados no? La verdad que cuando vi ese tutorial, no me plantee el que mi jugador fuera a tener piernas y que tal hecho conllevaría todo este problema... Entonces vamos por pasos. Primero voy a intentar hacer lo del Blend Tree. Con esto
playerRigidbody.MovePosition (transform.position + movement);ya tendríamos el vector de dirección, y ahora haría falta crear otro Vector que será el que guarde la posición hacia la cuál esta mirando el personaje (que será la posición del mouse), no?
-
Antonio

- Debugger
- Mensajes: 194
-
- En línea
Sí, es posible.eature=oembed" frameborder="0" allowfullscreen="true"> Sobre la configuración del Blend Tree, yo la tengo así: En mi caso, hago algunos tejemanejes más, por eso mi ángulo guardado en Turn, va entre -1 y 1, en vez de -180 y 180, por otro lado, también tengo la velocidad speed para gestionar en el mismo Blend tree, la animación de andar y idle. Sobre las velocidades es algo más particular de las animaciones que estoy usando (algunas tenían una velocidad mayor que la deseada, por eso la redución).
La entrada a este Blendtree se hace desde fuera, algo parecido a lo que tendrás tu, es el estado principal y si el personaje muere, pues cambia de estado / animación. (A parte tengo otro Blendtree similar para cuando no lleve armas equipadas pero en fin, eso va para otro día XD ).
Sí, la posición hacia la que mira, debería ser el ratón, a veces, se acorta código diciendo que la posición a la que mira, es el vector forward del personaje, y en algunos casos puede funcionar. A mi no me funcionó, porque al hacerlo así, el rayo de disparo quedaba desviado. (El vector Z del personaje no se corresponde exactamente con la Z del punto de disparo, y el rayo eléctrico salía más torcido también). Así que nada, al final yo opté por buscar el punto donde se da al ratón.
En el tutorial del muñeco sin piernas, también tienes el código de cómo tomó dicha posición del ratón.
La entrada a este Blendtree se hace desde fuera, algo parecido a lo que tendrás tu, es el estado principal y si el personaje muere, pues cambia de estado / animación. (A parte tengo otro Blendtree similar para cuando no lleve armas equipadas pero en fin, eso va para otro día XD ).
Sí, la posición hacia la que mira, debería ser el ratón, a veces, se acorta código diciendo que la posición a la que mira, es el vector forward del personaje, y en algunos casos puede funcionar. A mi no me funcionó, porque al hacerlo así, el rayo de disparo quedaba desviado. (El vector Z del personaje no se corresponde exactamente con la Z del punto de disparo, y el rayo eléctrico salía más torcido también). Así que nada, al final yo opté por buscar el punto donde se da al ratón.
En el tutorial del muñeco sin piernas, también tienes el código de cómo tomó dicha posición del ratón.
-
Andrewu-12
- Visitante
- En línea
[quote author=Adngel" data-ipsquote-contapp="forums" data-ipsquote-contenttype="forums" data-ipsquote-contentclass="forums_Topic" data-ipsquote-contentid="34433" data-ipsquote-contentcommentid="123588">Sí, es posible. eature=oembed" frameborder="0" allowfullscreen="true" __idm_id__="179201"> Sobre la configuración del Blend Tree, yo la tengo así:
Etiquetas:
Acciones del Usuario