Juan Carlos Frausto Arias
FixedUpdate: se utiliza para actualizar el motor de física, con intervalos establecidos Esta linea de codigo sirve para girar 180º: this.transform.eulerAngles = new Vector3(0, 180, 0);
Mover un enemigo en Unity con FixedUpdate garantiza una física estable y un movimiento suave, incluso si bajan los frames. Aquí verás cómo calcular la velocidad y el giro según la dirección, y cómo aplicar la velocidad al rigidbody solo cuando el juego está en marcha, para mantener un control total del comportamiento.
¿Por qué usar fixedupdate en Unity para física del enemigo?
Usar FixedUpdate evita que las caídas de FPS afecten al movimiento. A diferencia de Update, que corre cada frame, FixedUpdate se llama menos veces por segundo pero a intervalos fijos, ideal para cálculos de fuerzas, aceleraciones y velocidades que impactan el motor de físicas y los rigid bodies. Así se minimizan los cambios visuales indeseados en pantalla.
Ejemplo de estructura básica:
void FixedUpdate() { // 1) Calcular velocidad según dirección. // 2) Girar el sprite con eulerAngles si cambia la orientación. // 3) Aplicar la velocidad al rigidbody solo si el estado es InGame. }
¿Cómo calcular dirección y girar al enemigo con euler angles?
Primero se define una velocidad actual y se ajusta su signo según el sentido. Si mira a la derecha, es positiva; si mira a la izquierda, es negativa. Luego, se gira el objeto con transform.eulerAngles a 0 o 180 grados en el eje Y para reflejar visualmente el cambio de sentido.
¿Cómo invertir la velocidad según facing right?
float currentRunningSpeed = runningSpeed; if (facingRight) { currentRunningSpeed = runningSpeed; // derecha: velocidad positiva } else { currentRunningSpeed = -runningSpeed; // izquierda: velocidad negativa }
¿Cómo girar con transform.eulerAngles 0/180?
if (facingRight) { transform.eulerAngles = new Vector3(0f, 180f, 0f); } else { transform.eulerAngles = Vector3.zero; // 0,0,0 }
¿Cómo aplicar la velocidad con gamemanager y rigidbody2d?
La velocidad calculada solo se aplica cuando el estado del juego es InGame. Si la partida no ha empezado o hay game over, el enemigo se queda quieto. Esto ofrece más control sobre el comportamiento y evita movimientos fuera de contexto.
if (GameManager.Instance.CurrentGameState == GameState.InGame) { rb.velocity = new Vector2(currentRunningSpeed, rb.velocity.y); }
¿Qué parámetros ajusta el game designer?
¿Te gustaría que el enemigo reaccione al chocar con paredes y se dé la vuelta de forma automática? Cuéntame qué comportamiento quieres añadir y lo diseñamos paso a paso.
Es util si solo necesitas que el sprite se voltee (solo el sprite), pero en el caso de que por ejemplo tengas algun colisionador al lado derecho del gameObject, y no decees poner otro y por ende añadir otro script; lo mejor es hacerlo de la otra forma. P.D. Ademas del
this.transform.eulerAngles = new Vector3(0, 180, 0) ... this.transform.eulerAngles = new Vector3(0, 0, 0)
Yo recomiendo una manera mas sencilla para voltearlo:
void ToFlip() { //Logica para determinar cuando voltea //Ejemplo if(xDir < 0 && facingRight == true) { Flip(); } if(xDir > 0 && facingRight == false) { Flip(); } } //Funcion para voltear void Flip() { facingRight = !facingRight; this.transform.localScale = new Vector2(-transform.localScale.x, transform.localScale.y); }
Juan Carlos Frausto Arias
FixedUpdate: se utiliza para actualizar el motor de física, con intervalos establecidos Esta linea de codigo sirve para girar 180º: this.transform.eulerAngles = new Vector3(0, 180, 0);
Tomas Leonardo Amaya Ríos
Dirección del enemigo;
Al igual que otros puntos del setting del videojuego hay varias formas de querer realizar tal o cual acción, mi pregunta seria de nuevo... EulerAngles o LocalScale? :D
Richard Eduardo Lara Rueda
Yo pensé exactamente lo mismo, prefiero usar el LocalScale
Alexis Duque
Ervic Perez Mendoza
Usaremos FixedUpdate(se ejecuta a intervalos fijos de tiempo) siempre que necesitemos el motor de físicas (fuerzas, aceleraciones, velocidades) - de esta manera evitaremos tener desfaces visuales.
Luis Antonio Preza Padilla
¿Entonces podríamos decir entonces que utilizar el Delta Time y el método FixedUpdate() funcionarían igual en lo que a físicas se refiere?
Adrian Alexander Castro Peñaherrera
Primero, hablemos de deltaTime. Esta es una medida de tiempo en segundos que representa el tiempo que ha pasado desde el último frame. Es esencial para hacer que tus juegos sean consistentes en diferentes dispositivos y velocidades de fotogramas. Al multiplicar valores como la velocidad del movimiento por Time.deltaTime, te aseguras de que el movimiento se realice de manera suave y constante, sin importar cuántos fotogramas se muestren por segundo.
Por otro lado, FixedUpdate es un método especial en Unity que se utiliza para realizar cálculos de física y movimiento en intervalos de tiempo fijos. A diferencia de Update, que se llama una vez por cada frame, FixedUpdate se llama a una tasa constante, generalmente cada 0.02 segundos por defecto. Esto es útil para evitar problemas de física en situaciones de alta velocidad de fotogramas, donde Time.deltaTime podría ser muy pequeño y causar comportamientos inconsistentes en el movimiento.
Entonces, en resumen, deltaTime se usa para hacer que el movimiento sea suave y dependiente del tiempo, mientras que FixedUpdate se utiliza para manejar cálculos de física y movimiento en intervalos de tiempo fijos, lo que ayuda a mantener la estabilidad en el juego. No son lo mismo, pero a menudo se usan juntos para lograr un control preciso en los juegos de Unity.
He añadidoal script la posibilidad de esocger el tipo de movimiento del enemigo, horizontal y vertical, les dejo el código.
using System.Collections; using System.Collections.Generic; using UnityEngine; public enum MovementDirection { horizontal, vertical } public class Enemy : MonoBehaviour { public MovementDirection movementDirection = MovementDirection.horizontal; public bool facingRight = false; public bool facingUp = false; public float runningSpeed = 1.5f; Rigidbody2D rigidbody2D; Vector3 startPosition; private void Awake() { rigidbody2D = GetComponent<Rigidbody2D>(); startPosition = this.transform.position; } // Start is called before the first frame update void Start() { this.transform.position = startPosition; } private void FixedUpdate() { float currentRunnningSpeed = runningSpeed; if (movementDirection == MovementDirection.horizontal) { rigidbody2D.constraints = RigidbodyConstraints2D.FreezePositionY; if (facingRight) { currentRunnningSpeed = runningSpeed; this.transform.eulerAngles = new Vector3(0, 180, 0); } else { currentRunnningSpeed = -runningSpeed; this.transform.eulerAngles = Vector3.zero; } } if (movementDirection == MovementDirection.vertical) { rigidbody2D.constraints = RigidbodyConstraints2D.FreezePositionX; if (facingUp) { currentRunnningSpeed = runningSpeed; this.transform.eulerAngles = new Vector3(0, 0, -90); } else { currentRunnningSpeed = -runningSpeed; this.transform.eulerAngles = new Vector3(0, 0, 90); } } if (GameManager.sharedInstance.currentGameState == GameState.inGame) { if (movementDirection == MovementDirection.horizontal) { rigidbody2D.velocity = new Vector2(currentRunnningSpeed, rigidbody2D.velocity.y); } if (movementDirection == MovementDirection.vertical) { rigidbody2D.velocity = new Vector2(rigidbody2D.velocity.x, currentRunnningSpeed); } } } }