[Unity] ¿Como desarrollais el movimiento?

B

Cuando hacéis el movimiento en 2D, ¿que método utilizáis? He visto que hay quien usa la propiedad velocity del RigidBody2D, hay quien le añade fuerza en diferentes direcciones...

Por poner algo de código, el último vídeo que he visto, para mi la manera más fácil de hacerlo es:

public class PlayerController2D : MonoBehaviour
{

Rigidbody2D rb2d;

public float speed;
public float jumpForce;

 void FixedUpdate()
{
    if (Input.GetKey("d") || Input.GetKey("right"))
    {
        rb2d.velocity = new Vector2(speed, rb2d.velocity.y);
    }
    else if (Input.GetKey("a") || Input.GetKey("left"))
    {
        rb2d.velocity = new Vector2(-speed, rb2d.velocity.y);
    } else
    {
        rb2d.velocity = new Vector2(0, rb2d.velocity.y);
    }

    if (Input.GetKey("space"))
    {
        rb2d.velocity = new Vector2(rb2d.velocity.x, jumpForce);
    }
}
}

totespare

Esa suele ser la manera que uso yo para mover cosas sin complicarme mucho. Si quieres un movimiento tipo nave, por ejemplo (como asteroids), un aplicar fuerzas también funciona bien. O si no también puedes usar el CharacterController para mover un personaje. Ya si quieres un controlador a medida, puedes picartelo tu, simular la gravedad etc. Según lo que necesites y el tiempo que tengas, claro.

1 comentario moderado
B

#3 Tengo que ser sincero, no he entendido nada xD

Bueno si, que coja inputs en Update y los ejecute en FixedUpdate. Tendré que leerte con calma.

#3gdev:

reciclaría con una variable en vez de crear vectores de usar y tirar en cada tick de física

Esto como lo harías, no me hago a la idea.

2 respuestas
totespare

#4 que en vez de hacer new Vector2(speed, rb2d.velocity.y); todo el tiempo, te crees como una variable de la clase un vector3 que sea la velocidad que vas a crear, y en cada update le cambias la XYZ del vector y se la asignas al velocity, en vez de crear uno al asignarlo.

Lo de ejecutarlos en el FixedUpdate no se a que te refieres, pero el caso es que inputs van en el Update, luego si necesitas aplicar físicas en el tiempo, usa el FixedUpdate (o el Update y utiliza el Time.deltaTime para no ser framedependiente). Echale un ojo a esto: https://docs.unity3d.com/Manual/ExecutionOrder.html te será útil

2 respuestas
1 comentario moderado
B

#5 #6 Vale si joder xD Menuda empanada arrastro.

He refactorizado el código, la única duda que me queda sobre esto es, el tema de animaciones en el update o en el fixed?

void Update()
    {
        if (Input.GetKey("d") || Input.GetKey("right"))
        {
            movement = new Vector2(runSpeed, rb2d.velocity.y);
            spriteRenderer.flipX = false;
        }
        else if (Input.GetKey("a") || Input.GetKey("left"))
        {
            movement = new Vector2(-runSpeed, rb2d.velocity.y);
            spriteRenderer.flipX = true;
        }
        else
        {
            movement = new Vector2(0, rb2d.velocity.y);
        }

    if ((Input.GetKey("w") || Input.GetKey("up")) && isGrounded)
    {
        movement = new Vector2(rb2d.velocity.x, jumpForce);
    }
    
    if (isGrounded)
    {
        if (movement.x != 0)
        {
            animator.Play("Player_Run");
        }
        else
        {
            animator.Play("Player_Idle");
        }
    }
    else
    {
        animator.Play("Player_Jump");
    }
    
}

void FixedUpdate()
    {
        rb2d.velocity = movement;
    }
2 respuestas
totespare
#7Kazulu:

el tema de animaciones

te refieres a darle al play al animator? En el update está bien

void FixedUpdate()
{
rb2d.velocity = movement;
}

Esto te sobra por cierto, setealo al final del update (o al final de la parte en la que calculas el movimiento, más bien). Piensa que por cada update, se ejecutan varios fixedupdates, no te sirve de nada que calcules 1 vez la velocidad y se la apliques varias veces en el mismo frame (una por cada llamada al fixed update), ya que estas haciendo el set varias veces con el mismo valor.

1 respuesta
Meleagant

#3 Me parece que en Unity no puedes reciclar vectores de esa manera ¿no?. Rigidbody.velocity es un accedente público que devuelve una copia del vector si lo lees y guarda uno nuevo si lo asignas.

Es algo que me ha llamado mucho la atención en Unity, cada vez que manipulas el transform andas asignando vectores nuevos.

2 respuestas
B
#8totespare:

Piensa que por cada update, se ejecutan varios fixedupdates, no te sirve de nada que calcules 1 vez la velocidad y se la apliques varias veces en el mismo frame (una por cada llamada al fixed update), ya que estas haciendo el set varias veces con el mismo valor

Vale, ahora acaba de perder sentido todo lo explicado antes...

#5totespare:

el caso es que inputs van en el Update, luego si necesitas aplicar físicas en el tiempo, usa el FixedUpdate

1 comentario moderado
B

#11 Osea que estaría bien como yo lo tengo, inputs en el Update y la ejecución sobre el RigidBody2D.velocity en FixedUpdate.

Estoy mirando ahora el tema de animator, para manejar las animaciones desde ahí en vez de desde código, a ver que tal.

1 respuesta
1 comentario moderado
kesada7

Madre mía la que estáis liando aquí xDD

Lo correcto sería usar tal cual lo tienes en #1 pero cambiándolo del FixedUpdate a Update

Asnarth

Aprovecho el hilo para preguntar yo también, que siempre que me pongo a tontear con Unity me surge esta misma duda.

En mi caso utilizo un Rigidbody, y el movimiento lo quiero hacer aplicando fuerza (con AddForce o AddRelativeForce). ¿Supongo que debería hacer lo mismo? Tener una variable de clase que registre de alguna manera los inputs, seteandola en el Update, y luego en el FixedUpdate la consulto y aplico las fuerzas necesarias.

B

No quedar mal la cosa la verdad...

Para la posición de las balas tengo dentro de Player 3 EmptyObjects colocados donde se situa el arma al disparar y depende de la situación a la bala le paso la posición de uno de ellos.

 if (Input.GetKeyDown("space"))
        {
            isShooting = true;
            GameObject bullet = (GameObject)Instantiate(bulletRef);
            if (isGrounded)
            {
                if (movement.x != 0)
                {
                    bullet.transform.position = bulletStartRunning.position;
                }
                else
                {
                    bullet.transform.position = bulletStartIdle.position;
                }
            }
            else
            {
                bullet.transform.position = bulletStartJumping.position;
            }
        }
        else
        {
            isShooting = false;
        }
1 respuesta
Jastro

#11 Please, utiliza las @ de forma correcta y por favor no os traigais vuestros piques personales al subforo.

Usad los privados para lo que querais, pero fuera de esto, todos somos compañeros, algunos sabemos mas, algunos sabemos menos y comprendo que es imposible llevarnos todos bien, pero usa los nombre de forma correcta anda, que no cuesta nada y tenemos un subforo que valga la pena mantener.

Dicho eso, No sabia lo de este parrafo :

Nunca uses física con time.deltatime en update por motivos varios, un ej: si los fps son superiores a los hz de la física, probable que acabes sobreescribiendo valores desde update antes de que los procese el engine de física.

NO TENIA NI PUTA IDEA, yo siempre usaba el Delta time

Edit: Aunque ahora que lo pienso, yo use FixedUpdate, no Update

#16 Pinta genial.

PD: como me hace llorar esas llaves en una nueva linea xD

2 respuestas
B

Buah, creo que no lo he pensado bien lo de disparar, me acabo de dar cuenta de que solo disparo en una dirección xDDDDDD

#17 Macho, yo de C# ni puta idea, me dijeron que era convención que lo usara así y yo con mi buena fé pienso, vale, si es típico de C# lo haré así para que en los foros la gente lo veo guay.

1 respuesta
Jastro

#18 tendrias que calcular la direccion de donde dispara y aplicarlo en la bala

ten en cuenta, que a la izquierda es -1, a la derecha +1

#18 Si si, tranqui son neuras mias, no siginifca que este mal xD

1 respuesta
B

#19 Lo dejo para mañana ya, voy a ver un vídeo a ver como lo explica, si no por seguir con la idea original sería:

  • Hacer 3 EmptyObjects en el otro lado del personaje y con un if/else crear la bala en los puntos de la derecha y velocidad normal o en los de la izquierda con velocidad negativa.
1 respuesta
B

#17 no hay problema, todo el hilo para vosotros

1 respuesta
Jastro

#20 lol, que cosa mas loca

#21 Yo lo siento men, pero te has sobrepasado, no venia a cuento ese @ y lo sabes. Aqui estamos todos aportando y dando ideas para mejorar, nadie te ha increpado para que hayas hecho eso, sin mas.

1 respuesta
B

#22 Fue la forma más fácil que se me ocurrió para que la bala saliera de diferentes sitios dependiendo de si estaba en salto, corriendo o parado xDDDD

1 respuesta
Jastro

#23

void Start() {
        Vector3 playerPos = new Vector3(player.position.x, player.position.y + 1, player.position.z); //+1 para que aparezca un poco lejos, sumale lo que necesites, 
        transform.rotation = Quaternion.LookRotation(playerPos); //comprueba la posicion en la que esta
    }
 
void Update() {
    transform.position += transform.forward * speed * Time.deltaTime; //se mueve a la velocidad que pongas en speed
}
Meleagant

A mí normalmente no me gusta mucho usar las físicas de Unity porque no sé con certeza lo que hacen por debajo. Para un plataformas 2D me haría las mías, pero si te funcionan bien tira con ellas.

kesada7

Vale vamos por partes

#3gdev:

Primero de todo, reciclaría con una variable en vez de crear vectores de usar y tirar en cada tick de física.

  1. Si estuviera haciendo new de una clase que son de tipo por referencia si pero recordad que en Unity los vectores son un struct por tanto de tipo valor y se almacenan en el stack en vez del heap por tanto no genera garbage.

#9 Por esto mismo los transform en Unity que son vectores -> struct -> no puedes modificarlos directamente haciendo transform.x = 3f porque ese transform.x devuelven un valor (una copia) y no una referencia.

  1. El Update es framedependiente y generalmente se van a ejecutar más que el de físicas FixedUPdate. (Esto no tiene por qué ser siempre así pero en general si, sin entrar mucho en detalles el fixedupdate está configurado por defecto en unas 50 llamadas por segundo)
    Puedes modificar sin problemas el rigibody.velocidy en el update ya que no estás aplicando ninguna física solo estás modificando el valor del cual luego el motor de físicas tiene que tener en cuenta y aunque no es recomendable manipular directamente los velocity porque es el motor de físicas el que debería de encargarse de calcular estos aplicando fuerzas, gravedad, etc si sabes lo que quieres no hay problema.

  2. Puedes modificar sin problema la variable “movement” en el update, lo único que puede pasar es lo que te han dicho de que si los fps son superiores a las llamadas de físicas acabaras sobreescribiendo el “movement” antes de que los procese el engine de físcia pero no le veo el problema a esto ya que siempre va a tener el valor más “actualizado” por el mismo hecho de que el update está siendo más rápido. En resumen lo que te puse en mi comentario anterior, puedes hacer tal como lo tienes en #1 pero en el Update en vez del FixedUpdate

PD: NO tengo la verdad absoluta, estoy abierto a debatir o corregir si me demostráis que algo está mal.

2 1 respuesta
B

Aprovecho el hilo para pregunta algo relacionado.

Hay alguna diferencia entre usar solo un Sprite que mire a la der por ejemplo y luego hacerle flip depende de donde esté mirando? con tener un Sprite para cada dirección izq y der?

Por qué haciendo un blend tree se podría usar el mismo Sprite y haciendo el flip por código?

B

#26 Haz la prueba. Un bucle que cree 50.000 news vs bucle con 50.000 asignaciones.

Respecto a la física, si gestionas múltiples eventos con acciones diferentes desde update con un FPS evelado acabarán sobreescribiéndose.

Usuarios habituales