El problema: no todos los ordenadores van a los mismos FPS#
Update se llama una vez por fotograma, pero un PC potente hace 200 fotogramas por segundo y un móvil 30. Si mueves posicion += 5 por fotograma, el objeto irá 6 veces más rápido en el PC. Injusto e impredecible.
La solución: multiplicar por Time.deltaTime#
Time.deltaTime es cuántos segundos han pasado desde el fotograma anterior. Multiplicar por él convierte "por fotograma" en "por segundo":
void Update()
{
// ✅ 5 unidades por SEGUNDO, igual en cualquier equipo
transform.position += Vector3.right * 5f * Time.deltaTime;
}La regla: cualquier cosa que cambie con el tiempo en Update (movimiento, rotación, temporizadores) se multiplica por Time.deltaTime.
Si en tu cabeza dices "muévete 5 metros por segundo", el código es 5 * Time.deltaTime. Si dices "5 metros por fotograma", casi seguro es un bug de FPS.
deltaTime vs fixedDeltaTime#
En FixedUpdate (la física) el tiempo entre pasos es fijo (0,02 s por defecto). Ahí usa Time.fixedDeltaTime. Unity es listo: dentro de FixedUpdate, Time.deltaTime ya devuelve fixedDeltaTime, así que en la práctica puedes usar Time.deltaTime en ambos y funciona.
| Propiedad | Qué mide |
|---|---|
Time.deltaTime | Segundos desde el último fotograma (o el paso fijo, si estás en FixedUpdate) |
Time.fixedDeltaTime | Duración del paso de física (fijo, configurable) |
Time.time | Segundos desde que arrancó el juego |
Time.unscaledDeltaTime | Como deltaTime, pero ignora timeScale |
Pausar y ralentizar con timeScale#
Time.timeScale es un multiplicador global de la velocidad del tiempo. 1 = normal, 0 = congelado, 0.5 = cámara lenta.
public void Pausar() => Time.timeScale = 0f; // congela física, animaciones y deltaTime
public void Reanudar() => Time.timeScale = 1f;
public void CamaraLenta() => Time.timeScale = 0.3f;Es la base de un menú de pausa.
Al pausar con timeScale = 0, Time.deltaTime vale 0 y las corrutinas con WaitForSeconds se congelan. Para animar el propio menú de pausa o un contador que debe seguir con el juego parado, usa Time.unscaledDeltaTime y WaitForSecondsRealtime, que ignoran el timeScale.
Un temporizador correcto#
[SerializeField] private float duracion = 3f;
private float restante;
void OnEnable() => restante = duracion;
void Update()
{
restante -= Time.deltaTime; // baja en segundos reales
if (restante <= 0f) Explotar();
}Errores frecuentes#
- Mover o rotar en
UpdatesinTime.deltaTime(velocidad dependiente de los FPS). - Multiplicar por
deltaTimealgo que no es por tiempo (p. ej. un salto instantáneo). - Olvidar poner
timeScale = 1al salir de la pausa (el juego se queda congelado). - Usar
WaitForSecondsen el menú de pausa contimeScale = 0(no avanza; usa Realtime).
Ponte a prueba#
Resumen#
Unity mide el tiempo entre fotogramas con Time.deltaTime: multiplícalo por todo lo que cambie con el tiempo en Update para ser independiente de los FPS. En física usa el paso fijo (fixedDeltaTime). Con Time.timeScale pausas (0) o ralentizas (0.3) el juego entero; y cuando algo debe seguir con el juego pausado (menús, contadores reales), usa unscaledDeltaTime.