Detección de colisiones — la física básica de todo videojuego

By Carlos Montiel | Especialista en IA Empresarial
Publicado: 2026-07-28 | Por: Carlos Montiel | Lectura: ~4 minutos

Casi todo lo que hace interesante a un videojuego depende de saber cuándo dos cosas se tocan. Hoy formalizamos esa pregunta con matemática simple y código reutilizable.

Por qué esto es más importante de lo que parece

En la lección anterior resolvimos animación de sprites. Antes de eso, en Pong, usamos `SDL_HasIntersection` para detectar cuándo la pelota tocaba una paleta — una solución rápida pero limitada. En esta lección vamos a entender qué hace esa función por dentro, y vamos a construir detección de colisiones que funcione para rectángulos y para círculos, porque no todos los juegos usan solo cajas.

La detección de colisiones es la base de: daño en combate, recolección de ítems, disparos que impactan, personajes que no atraviesan paredes, y prácticamente cualquier interacción física en un juego 2D.

Colisión de rectángulos: AABB

AABB significa "Axis-Aligned Bounding Box" — una caja alineada a los ejes, es decir, sin rotación. Es la forma de colisión más barata de calcular y la más usada en juegos 2D.

La lógica es simple: dos rectángulos NO se superponen si uno está completamente a la izquierda, derecha, arriba o abajo del otro. Si ninguna de esas cuatro condiciones es verdadera, entonces se están tocando.

struct AABB { float x, y; // esquina superior izquierda float ancho, alto; }; bool colisionan_aabb(const AABB& a, const AABB& b) { bool separados_en_x = (a.x + a.ancho <= b.x) || (b.x + b.ancho <= a.x); bool separados_en_y = (a.y + a.alto <= b.y) || (b.y + b.alto <= a.y); return !(separados_en_x || separados_en_y); }

Esto es exactamente lo que hace `SDL_HasIntersection` internamente. Ahora que lo entiendes, puedes extenderlo — por ejemplo, calculando cuánto se superponen (para resolver la colisión empujando los objetos) en vez de solo saber si chocan.

struct Solapamiento { bool hay_colision; float profundidad_x; float profundidad_y; }; Solapamiento calcular_solapamiento(const AABB& a, const AABB& b) { if (!colisionan_aabb(a, b)) return { false, 0, 0 }; float solape_derecha = (a.x + a.ancho) - b.x; float solape_izquierda = (b.x + b.ancho) - a.x; float solape_abajo = (a.y + a.alto) - b.y; float solape_arriba = (b.y + b.alto) - a.y; float menor_x = std::min(solape_derecha, solape_izquierda); float menor_y = std::min(solape_abajo, solape_arriba); return { true, menor_x, menor_y }; }

Colisión de círculos

Para objetos redondos (una pelota, una explosión, un proyectil), la colisión por círculo es más precisa y, sorprendentemente, más simple de calcular: dos círculos colisionan si la distancia entre sus centros es menor que la suma de sus radios.

struct Circulo { float x, y; // centro float radio; }; bool colisionan_circulos(const Circulo& a, const Circulo& b) { float dx = a.x - b.x; float dy = a.y - b.y; float distancia_al_cuadrado = dx * dx + dy * dy; float suma_radios = a.radio + b.radio; return distancia_al_cuadrado <= (suma_radios * suma_radios); }

Nota el truco de rendimiento: comparamos el cuadrado de la distancia contra el cuadrado de la suma de radios, en vez de usar `sqrt()`. La raíz cuadrada es una operación relativamente cara, y aquí es completamente evitable — solo nos interesa saber si una distancia es mayor o menor que otra, no su valor exacto.

Colisión círculo contra rectángulo

Un caso mixto muy común: una pelota redonda contra una plataforma rectangular. La técnica estándar es encontrar el punto del rectángulo más cercano al centro del círculo, y medir la distancia desde ahí.

bool colisiona_circulo_rect(const Circulo& c, const AABB& r) { float punto_cercano_x = std::max(r.x, std::min(c.x, r.x + r.ancho)); float punto_cercano_y = std::max(r.y, std::min(c.y, r.y + r.alto)); float dx = c.x - punto_cercano_x; float dy = c.y - punto_cercano_y; return (dx * dx + dy * dy) <= (c.radio * c.radio); }

Aplicándolo a Pong: colisión real de la pelota

Ahora podemos reemplazar el `SDL_HasIntersection` improvisado de la lección 3 con nuestra propia función AABB, y usar el solapamiento para decidir si el rebote debe ser horizontal o vertical según en qué lado ocurrió el impacto.

AABB rect_de(const SDL_Rect& r) { return { (float)r.x, (float)r.y, (float)r.w, (float)r.h }; } void resolver_colision_pelota_paleta(Pelota& pelota, const Paleta& paleta) { AABB caja_pelota = rect_de(pelota.rect); AABB caja_paleta = rect_de(paleta.rect); Solapamiento s = calcular_solapamiento(caja_pelota, caja_paleta); if (!s.hay_colision) return; if (s.profundidad_x < s.profundidad_y) { pelota.vel_x = -pelota.vel_x; } else { pelota.vel_y = -pelota.vel_y; } }

Evitando colisiones dobles y "atascos"

Un bug frecuente: si no separas los objetos después de detectar la colisión, el mismo choque se detecta en varios fotogramas seguidos y el objeto "tiembla" o queda atascado. La solución es empujar los objetos fuera de la zona de solapamiento inmediatamente después de resolver la física.

void separar_objetos(SDL_Rect& mover, const Solapamiento& s, bool eje_x) { if (eje_x) { mover.x += (s.profundidad_x > 0) ? (int)s.profundidad_x : -(int)s.profundidad_x; } else { mover.y += (s.profundidad_y > 0) ? (int)s.profundidad_y : -(int)s.profundidad_y; } }

Un buen uso de tu asistente de IA aquí

La geometría de colisiones es un terreno donde los asistentes de IA son particularmente buenos explicando "por qué" funciona una fórmula, no solo "qué" hace. Si la matemática del punto más cercano en colisión círculo-rectángulo no te queda clara del todo, pídele a tu asistente que te la dibuje en ASCII o que te la explique con un caso numérico concreto (por ejemplo, un círculo en `(50, 50)` con radio `10` contra un rectángulo en `(0,0,40,40)`). Ver los números moverse ayuda mucho más que la fórmula sola.

En la próxima lección vamos a usar estas mismas estructuras de datos (posiciones, estados de personajes) como base para algo distinto: un sistema de guardado que le dé memoria persistente a tu juego entre una sesión y la siguiente.

Carlos Montiel
Arquitecto de Soluciones IA Empresarial
Especialista en LLMs, Agentes y Orquestación
guatemalia.com/#contacto · info@guatemalia.com

¿Necesitas implementar IA en tu empresa?

Carlos Montiel es arquitecto de soluciones IA empresarial. Implementa LLMs, Agentes, RAG y orquestadores en empresas de Guatemala y Latinoamérica. Contáctalo para una consultoría.

Contactar a Carlos Montiel

info@guatemalia.com