Contenido del curso
Tu primer juego
Desarrollando el juego
Conclusión
Rebote de pelota con move_and_collide en Godot
Resumen
Si quieres aprender a programar una pelota con movimiento y rebote en Godot, aquí construimos paso a paso el segundo elemento clave de un juego tipo Pong: una ball controlable, con colisiones circulares y dirección aleatoria al inicio. Es ideal para quienes ya manejan lo básico de escenas y quieren entender cómo combinar sprites, collision shapes y físicas controladas.
La clave está en usar un KinematicBody2D, porque te da control absoluto sobre el cuerpo sin que las físicas del entorno lo afecten. Así, la pelota se mueve, choca y rebota exactamente como tú lo defines.
¿Por qué usar un KinematicBody2D para la pelota?
El KinematicBody2D es un nodo que ignora fuerzas externas y choques automáticos. Tú decides cuándo se mueve, hacia dónde y cómo reacciona ante una colisión. Esto es perfecto para una pelota de Pong, donde no quieres que la gravedad o un impacto azaroso modifiquen su trayectoria.
¿Qué es un KinematicBody2D en Godot? Es un tipo de nodo físico que no responde a fuerzas ni colisiones automáticas. Tú controlas su movimiento por código, lo que lo hace ideal para personajes y objetos como una pelota de Pong. [01:00]
Para crear la escena, abres una nueva, eliges Other Node y seleccionas KinematicBody2D. Lo renombras como ball y ya tienes el nodo raíz listo.
¿Cómo agrego una imagen a la pelota con un Sprite?
En vez de usar un rectángulo de color, aquí trabajas con un Sprite, un nodo que permite cargar imágenes como texturas. Importas un PNG arrastrándolo al sistema de archivos y luego lo asignas a la propiedad Texture del Sprite.
Un detalle útil: en el inspector puedes desactivar el filter de la imagen, una opción pensada para mejorar pixel art que no siempre conviene en otros estilos visuales [03:30].
¿Qué CollisionShape usar para una pelota?
Como la pelota es redonda, necesitas un CircleShape en vez del rectángulo que usaste para el jugador. El radio del círculo va desde el centro hasta el borde, así que si tu imagen mide 64x64 píxeles, el radio correcto es 32, es decir, la mitad.
¿Cómo programar el movimiento inicial de la pelota?
El script de la pelota arranca con tres variables fundamentales:
speed, inicializada en cero porque la pelota empieza quieta.direction, un Vector2 que define hacia dónde irá.is_moving, una variable booleana que indica si la pelota está activa.
La variable booleana es un patrón muy usado en videojuegos para saber si algo está ocurriendo en un momento dado. En este caso, te dice si la pelota ya fue lanzada o sigue detenida.
¿Cómo genero una dirección aleatoria con randi?
Dentro de la función _ready(), defines la velocidad en 600 y eliges una dirección al azar usando un array y la función randi() de Godot. La lógica es así:
- Creas un array
[-1, 1]para la dirección horizontal. - Usas
randi() % 2para obtener un cero o un uno, que selecciona una de las dos posiciones del array. - Repites lo mismo para el eje vertical, pero con valores
-0.8y0.8, para forzar un movimiento diagonal.
¿Por qué diagonal y no vertical? Porque si la pelota solo rebotara entre techo y piso, ningún jugador podría tocarla. La diagonal asegura que cruce el campo [07:30].
¿Qué hace randomize en Godot? Inicializa el generador de números aleatorios. Sin llamar a
randomize()antes de usarrandi(), los resultados serían predecibles y siempre iguales. Es un paso obligatorio.
Finalmente, cambias is_moving a true para indicar que la pelota ya está en juego.
¿Cómo aplicar movimiento y colisiones frame a frame?
El movimiento real ocurre dentro de _physics_process(delta), una función que se ejecuta una vez por frame. Si tu juego corre a 30 FPS, la pelota se actualiza 30 veces por segundo, generando la sensación de movimiento continuo.
Dentro de esta función, si is_moving es true, mueves la pelota. Pero aquí viene la decisión clave: ¿move_and_slide o move_and_collide?
¿Cuál es la diferencia entre move_and_slide y move_and_collide?
Al principio podrías pensar en move_and_slide, igual que con el jugador. El problema es que esa función hace que la pelota se deslice por las paredes en vez de rebotar, lo cual rompe la mecánica del juego.
La función correcta es move_and_collide, que detiene el movimiento en el momento exacto del choque y te devuelve información sobre el objeto impactado. Eso sí, debes multiplicar direction * speed * delta, porque esta función no incorpora delta automáticamente como sí lo hace move_and_slide [12:00].
Multiplicar dos veces por delta genera movimientos extraños y poco predecibles, así que cuida ese detalle.
¿Cómo hacer que la pelota rebote al chocar?
Cuando usas move_and_collide, la pelota se queda clavada al chocar contra una pared, porque sigue empujando en la misma dirección sin poder avanzar. La solución es cambiar la dirección al detectar la colisión.
Guardas el resultado de move_and_collide en una variable collide. Si esa variable contiene un objeto, significa que hubo impacto. Entonces aplicas:
if collide: direction = direction.bounce(collide.normal)
La propiedad normal te da el vector perpendicular a la superficie golpeada, y el método bounce() calcula la dirección reflejada. Si la pelota venía con dirección (1, -0.8) y choca contra el techo, rebotará con (1, 0.8). Es un rebote perfecto, sin pérdida de energía [14:30].
Guardas los cambios, ejecutas la escena y verás que la pelota ahora rebota correctamente contra las paredes superior e inferior, manteniendo su trayectoria hacia el lado opuesto.
Hay un detalle pendiente: el piso del escenario quedó flotando en una posición incorrecta, un pequeño bug visual que puedes intentar resolver por tu cuenta antes de la próxima clase. ¿Cómo lo resolverías tú? Déjalo en los comentarios.