Unity Physics 3d

⚙️ Físicas en Unity 3D

Una guía completa y exhaustiva sobre el sistema de físicas en Unity 6, componentes, mecanismos y mejores prácticas para crear simulaciones realistas.

🎮 Introducción al Sistema de Físicas en Unity

El sistema de físicas de Unity es un motor de simulación basado en PhysX, que calcula las interacciones realistas entre objetos en el mundo 3D. Sin agregar código, un objeto con Rigidbody será atraído por la gravedad y reaccionará a las colisiones.

💡 Dato Importante: El motor PhysX es utilizado por la industria de videojuegos profesional. Está optimizado para CPU/GPU y produce resultados predecibles y consistentes.

¿Por qué importa la física?

  • Realismo: Los objetos se mueven de forma creíble y predecible
  • Gameplay: Las mecánicas de juego dependen de la física (saltos, colisiones, gravedad)
  • Optimización: PhysX está altamente optimizado para producción
  • Control: Puedes ajustar cada aspecto para tu juego específico
⚠️ Nota Técnica: La física en Unity se calcula en intervalos fijos (Fixed Timestep) típicamente de 0.02 segundos. Esto es independiente del FPS de renderizado.

🔧 Componentes Principales del Sistema de Físicas

Para que la física funcione en Unity necesitas al menos dos componentes trabajando juntos:

📦 Rigidbody

Función: Controla el movimiento y la física de un GameObject.

Requiere: Un Collider para interactuar.

Propiedades clave:

  • Mass (Masa)
  • Drag (Resistencia al aire)
  • Angular Drag (Resistencia rotacional)
  • Gravity (Afectado por gravedad)
  • Constraints (Restricciones)
⚡ Collider

Función: Define la forma del objeto para detectar colisiones.

Tipos: Box, Sphere, Capsule, Mesh, Wheel, Terrain.

Propiedades clave:

  • Is Trigger (Disparador)
  • Material (Physics Material)
  • Offset (Desplazamiento)
  • Size (Tamaño)

Estados del Rigidbody

Estado Descripción Casos de Uso
Dynamic Simulación física completa. Afectado por fuerzas y colisiones. Objetos móviles (pelotas, cajas, enemigos)
Kinematic Se mueve por scripts, pero los objetos dinámicos rebotan en él. Plataformas móviles, puertas
Static No se mueve. Más eficiente que dinámico. Piso, paredes, obstáculos fijos

📐 Tipos de Colliders en Unity 3D

Cada tipo de collider está optimizado para diferentes formas y casos de uso:

Primitivo
📦 Box Collider

Forma: Cubo/Rectángulo.

Uso: Cajas, paredes, plataformas.

Ventaja: Muy rápido, ideal para objetos geométricos simples.

CPU: ⭐⭐⭐ | Precisión: ⭐⭐⭐

Primitivo
🟢 Sphere Collider

Forma: Esfera.

Uso: Bolas, explosiones, projectiles.

Ventaja: Perfecto para cálculos de distancia y detección esférica.

CPU: ⭐⭐⭐ | Precisión: ⭐⭐

Primitivo
🔷 Capsule Collider

Forma: Cilindro con semiesferas.

Uso: Personajes, enemigos humanoides.

Ventaja: Excelente para movimiento sin atascarse en esquinas.

CPU: ⭐⭐⭐ | Precisión: ⭐⭐⭐

Avanzado
🧩 Mesh Collider

Forma: Geometría exacta del modelo 3D.

Uso: Terrenos complejos, escenarios.

Advertencia: Más costoso. Usar con moderación.

CPU: ⭐ | Precisión: ⭐⭐⭐⭐⭐

Especializado
🎡 Wheel Collider

Forma: Rueda especializada.

Uso: Vehículos, coches, motos.

Ventaja: Simulación realista de suspensión y agarre.

CPU: ⭐⭐ | Precisión: ⭐⭐⭐⭐

Terreno
🗻 Terrain Collider

Forma: Mapa de altitud.

Uso: Terrenos amplios, montañas.

Ventaja: Optimizado para grandes áreas.

CPU: ⭐⭐⭐ | Precisión: ⭐⭐⭐

Compound Colliders (Colliders Compuestos)

Para objetos complejos, puedes combinar múltiples colliders primitivos en objetos hijo:

GameObject Player
├─ Capsule Collider (cuerpo)
├─ Box Collider (brazos)
└─ Sphere Collider (cabeza)

Ventaja: Mayor precisión que Mesh Collider, mejor rendimiento que un Mesh único.

🎨 Physics Materials: Fricción y Rebote

Los Physics Materials definen cómo se comportan las superficies cuando entran en contacto con otros objetos.

Propiedades Principales

  • Dynamic Friction: Fricción mientras se desliza (0 = hielo, 1 = pegajoso)
  • Static Friction: Fricción en reposo
  • Bounciness: Rebote (0 = sin rebote, 1 = rebote máximo)
  • Friction Combine: Cómo se combinan fricciones
  • Bounce Combine: Cómo se combinan rebotes

Ejemplos de Valores

Material Fricción Rebote
Hielo 0.05 0.0
Asfalto 0.7 0.2
Pelota de Tenis 0.5 0.8
Goma 1.0 0.3
Acero 0.4 0.9

Modos de Combinación

Al colisionar dos materiales, se combinan usando uno de estos modos:

Average

Promedio de ambos valores. Es el más realista.

Multiply

Multiplicación. Resulta en valores más bajos.

Minimum

Usa el valor más pequeño (más pegajoso/menos rebote).

Maximum

Usa el valor más grande (más resbaladizo/más rebote).

🔗 Joints: Articulaciones y Restricciones

Los Joints conectan dos Rigidbodies y crean comportamientos de movimiento restringido. Son esenciales para ragdolls, cadenas, y mecanismos.

📌 Fixed Joint

Comportamiento: Fija rígidamente dos Rigidbodies en su posición relativa.

Uso: Objetos unidos, partes de máquinas conectadas.

Parámetro importante: Breaking Force (fuerza necesaria para romper la articulación).

// Fixed Joint en código
Rigidbody rb1 = obj1.GetComponent<Rigidbody>();
Rigidbody rb2 = obj2.GetComponent<Rigidbody>();
FixedJoint joint = obj1.AddComponent<FixedJoint>();
joint.connectedBody = rb2;
joint.breakForce = 1000f;
🎪 Spring Joint

Comportamiento: Actúa como un resorte elástico entre dos Rigidbodies.

Uso: Cuerdas, cables, suspensiones de vehículos.

Parámetros:

  • Spring: Resistencia del resorte (más alto = más fuerte)
  • Damper: Amortiguamiento (reduce oscilaciones)
  • Min/Max Distance: Distancia de reposo
🔄 Hinge Joint

Comportamiento: Permite rotación en un eje (como una puerta).

Uso: Puertas, brazos mecánicos, palancas.

Configuración: Define el eje de rotación (X, Y, o Z) y límites de rotación.

// Hinge Joint - Puerta
HingeJoint hinge = doorGameObject.AddComponent<HingeJoint>();
hinge.axis = Vector3.up; // Rotación en eje Y
hinge.limits = new JointLimits() {
    min = 0,
    max = 90,
    bounciness = 0
};
👤 Character Joint

Comportamiento: Joint extendido de bola y encaje para ragdolls.

Uso: Esqueletos de ragdoll, articulaciones humanas (brazos, piernas, cuello).

Ventaja: Permite rotación compleja en múltiples ejes.

Parámetros: Swing Limits (rotación frontal), Twist Limits (rotación axial).

⚙️ Configurable Joint

Comportamiento: El joint más flexible. Configurable en todos los grados de libertad.

Uso: Comportamientos personalizados, joints especializados.

Complejidad: Alta. Permite bloquear/desbloquear 6 grados de libertad (3 rotaciones + 3 traslaciones).

Nota: Más costoso computacionalmente que otros joints.

🎯 Ball Joint

Comportamiento: Bola y encaje como una articulación de cadera.

Uso: Articulaciones esféricas, caderas, hombros.

Característica: Permite rotación en todos los ejes con límites específicos.

💪 Aplicación de Fuerzas y Movimiento

Existen múltiples formas de mover un Rigidbody. Cada una tiene su propósito:

⚡ AddForce()

Aplica una fuerza continuada que se acumula.

rigidbody.AddForce(Vector3.forward * 10);
// Acelera gradualmente

Casos: Saltos, empujes, explosiones.

🎯 Velocity

Establece la velocidad directamente.

rigidbody.velocity = Vector3.forward * 5;
// Velocidad instantánea

Casos: Knockback, movimiento de proyectiles.

🌪️ AddTorque()

Aplica fuerza rotacional.

rigidbody.AddTorque(Vector3.right * 5);
// Rotación gradual

Casos: Pelotas girando, objetos rotatorios.

📍 MovePosition()

Movimiento cinemático interpolado.

rigidbody.MovePosition(transform.position + Vector3.forward);

Casos: Personajes, plataformas móviles.

Force Modes (Modos de Fuerza)

Cuando usas AddForce(), puedes especificar cómo se aplica la fuerza:

Force Mode Fórmula Uso
Force (Default) acceleration = Force / Mass Fuerzas reales (viento, gravedad, empujes)
Acceleration Aceleración pura sin considerar masa Cuando quieres que todos los objetos se aceleren igual
Velocity Cambio de velocidad directo Movimiento suave del personaje
Impulse Aplicada en un frame Explosiones, saltos instantáneos
⚠️ Importante: Siempre aplica fuerzas en FixedUpdate(), no en Update(). La física corre en Fixed Timestep separado.
void FixedUpdate() {
    rigidbody.AddForce(Vector3.forward * 10);
}

💥 Detección de Colisiones

Unity ofrece tres formas de detectar colisiones:

📞 OnCollisionEnter

Se ejecuta cuando dos colliders comienzan a tocarse.

Requiere: Ambos con Collider, al menos uno con Rigidbody.

void OnCollisionEnter(Collision collision) {
    Debug.Log("¡Colisión!");
}
👀 OnTriggerEnter

Se ejecuta cuando un objeto entra en un Trigger.

Requiere: Collider con "Is Trigger" activado.

void OnTriggerEnter(Collider collider) {
    Debug.Log("¡Entró!");
}
🎯 Physics.Raycast

Lanza un rayo invisible para detectar colisiones.

Uso: Armas, visión de IA, terreno.

RaycastHit hit;
if (Physics.Raycast(pos, dir, out hit)) {
    Debug.Log(hit.collider.name);
}

Collision Detection Methods

El Rigidbody tiene opciones para detectar colisiones de diferente manera:

📊 Discrete (Default)
Detecta colisiones checando posición cada frame. Más rápido, pero puede fallar con objetos muy rápidos.
📏 Continuous
Calcula la trayectoria completa. Detecta todas las colisiones, más lento.

⚡ Optimización del Sistema de Físicas

La física puede ser costosa. Aquí están las mejores prácticas para optimizar:

1️⃣ Usar Colliders Primitivos

❌ Evitar: Mesh Colliders para objetos dinámicos.

✅ Hacer: Usar Box, Sphere, Capsule Colliders.

Los colliders primitivos son 10-100x más rápidos.

2️⃣ Marcar objetos estáticos

❌ Evitar: Rigidbody dinámico para objetos que no se mueven.

✅ Hacer: Dejar como Static o usar Kinematic solo si es necesario.

Los objetos Static no se recalculan cada frame.

3️⃣ Usar Layers y Collision Matrix

En Edit > Project Settings > Physics:

  • Define qué layers pueden colisionar entre sí
  • Ejemplo: Enemigos no necesitan colisionar con Enemigos
  • Reduce cálculos innecesarios
4️⃣ Compound Colliders

Para objetos complejos:

  • Usa múltiples colliders primitivos en objetos hijo
  • Mejor que un único Mesh Collider
  • Más rápido + mejor precisión
5️⃣ Limitar Rigidbodies Dinámicos

Cada Rigidbody dinámico cuesta CPU:

  • Limita la cantidad en escena (máx ~100 en 60 FPS)
  • Usa Kinematic para objetos que no necesitan física completa
  • Destruye/Poolea objetos cuando sea posible
6️⃣ Ajustar Fixed Timestep

En Edit > Project Settings > Time:

  • Fixed Timestep: Por defecto 0.02s (50 FPS)
  • Aumenta a 0.03s-0.05s para juegos menos exactos
  • Reduce llamadas a FixedUpdate()
7️⃣ Usar Constraints

Congela ejes innecesarios:

  • Personaje 2D: Congela Z y rotaciones
  • Objeto que no rota: Congela todas las rotaciones
  • Reduce cálculos matemáticos
💡 Tip Profesional: Usa Unity Profiler (Window > Analysis > Profiler) para medir el costo de física. Busca "Physics" en la pestaña Profiler.

🎮 Ejemplos Prácticos

Ejemplo 1: Movimiento de Personaje

// Personaje con salto
public class PlayerController : MonoBehaviour {
    private Rigidbody rb;
    public float moveSpeed = 5f;
    public float jumpForce = 5f;

    void Start() {
        rb = GetComponent<Rigidbody>();
    }

    void FixedUpdate() {
        // Movimiento horizontal
        float x = Input.GetAxis("Horizontal");
        rb.velocity = new Vector3(x * moveSpeed, rb.velocity.y, 0);

        // Salto
        if (Input.GetKeyDown(KeyCode.Space)) {
            rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
        }
    }
}

Ejemplo 2: Física Realista de Auto

// Suspensión y tracción
public class CarPhysics : MonoBehaviour {
    private Rigidbody rb;
    public WheelCollider[] wheels;
    public float motorForce = 3000;
    public float brakeTorque = 3000;

    void FixedUpdate() {
        float accel = Input.GetAxis("Vertical") * motorForce;
        float brake = Input.GetKey(KeyCode.Space) ? brakeTorque : 0;

        foreach (WheelCollider wheel in wheels) {
            wheel.motorTorque = accel;
            wheel.brakeTorque = brake;
        }
    }
}

Ejemplo 3: Ragdoll

// Activar/Desactivar ragdoll
void EnableRagdoll() {
    // Desactivar animador
    animator.enabled = false;

    // Activar todos los Rigidbodies
    Rigidbody[] allBodies = GetComponentsInChildren<Rigidbody>();
    foreach (Rigidbody body in allBodies) {
        body.isKinematic = false;
    }

    // El esqueleto ahora simulará física
}

Ejemplo 4: Projectile con Física

// Bala/Flecha realista
public class Projectile : MonoBehaviour {
    private Rigidbody rb;

    public void Launch(Vector3 direction, float force) {
        rb = GetComponent<Rigidbody>();
        rb.velocity = direction * force;

        // Rotar según dirección de movimiento
        transform.rotation = Quaternion.LookRotation(direction);
    }

    void OnTriggerEnter(Collider collision) {
        if (collision.CompareTag("Enemy")) {
            Destroy(gameObject);
        }
    }
}

📚 Tabla de Referencia Rápida

Componente/Método Descripción Rendimiento
Rigidbody Controla física de un objeto ⭐⭐⭐
Box Collider Collider cúbico ⭐⭐⭐⭐⭐
Sphere Collider Collider esférico ⭐⭐⭐⭐⭐
Capsule Collider Collider cilíndrico ⭐⭐⭐⭐⭐
Mesh Collider Collider de geometría exacta ⭐⭐ (Evitar si es posible)
Physics.Raycast Detecta colisiones con rayo ⭐⭐⭐⭐
AddForce Aplica fuerza acumulativa ⭐⭐⭐⭐⭐
Velocity Establece velocidad directa ⭐⭐⭐⭐⭐
FixedJoint Fija dos cuerpos ⭐⭐⭐
SpringJoint Crea elasticidad ⭐⭐
HingeJoint Articulación de rotación ⭐⭐⭐
CharacterJoint Articulación compleja ⭐⭐

✅ Mejores Prácticas

✅ HACER

  • Usar Colliders primitivos
  • Aplicar fuerzas en FixedUpdate()
  • Usar Raycasts para detección
  • Limitar objetos dinámicos
  • Usar Constraints para optimizar
  • Perfilar rendimiento regularmente
  • Documentar valores de física

❌ EVITAR

  • Mesh Colliders en objetos dinámicos
  • Cambiar transform directamente
  • Aplicar fuerzas en Update()
  • Demasiados joints complejos
  • Continuous Collision para todo
  • Ignorar la matriz de colisiones
  • Física sin propósito

🔧 Solución de Problemas

Q: Mi objeto cae a través del piso

A: Problemas comunes:

  • El piso NO tiene Collider
  • El Rigidbody tiene "Is Kinematic" activado
  • La velocidad del objeto es demasiado alta (usa Continuous Collision)
  • El Collider es demasiado pequeño (Check "Edit Collider" en Inspector)
Q: Mi personaje no se mueve suavemente

A: Soluciones:

  • Aplica fuerzas en FixedUpdate(), no Update()
  • Usa MovePosition() para movimiento suave
  • Verifica el Fixed Timestep (Project Settings > Time)
  • Asegúrate de que el Capsule Collider tenga altura correcta
Q: Los objetos vibran o comportamiento errático

A: Esto es "jitter":

  • Aumenta Solver Iterations en Physics Settings
  • Reduce Force Scale y Penetration per Iteration
  • Asegúrate de que los Colliders no se solapan
  • Revisa que la masa sea realista (no muy pequeña)
Q: Joint roto o comportamiento extraño

A: Problemas de joints:

  • Verifica que ambos Rigidbodies existan y estén configurados
  • Asegúrate que el Connected Body no sea nulo
  • Aumenta Solver Iterations si es inestable
  • Para ragdolls: configura Character Joints correctamente

🎓 Conclusión

El sistema de físicas de Unity es poderoso pero requiere comprensión. Recuerda:

  • Rigidbody + Collider = Sistema base (no una sin la otra)
  • FixedUpdate() = Única forma correcta de aplicar fuerzas
  • Primitivos = Más rápidos que Mesh Colliders
  • Physics Materials = Control total del comportamiento
  • Joints = Crear comportamientos complejos
  • Optimización = Esencial para juegos en producción

La clave está en entender la diferencia entre qué hace la física automáticamente vs qué necesita ser controlado por código.

🚀 Próximos Pasos:
  • Experimenta con diferentes valores en Physics Settings
  • Crea un pequeño prototipo: Una bola rodando en una rampa
  • Construye un ragdoll simple para entender Character Joints
  • Perfila tu juego para identificar cuellos de botella de física