You don't have access to this class

Keep learning! Join and start boosting your career

Aprovecha el precio especial y haz tu profesión a prueba de IA

Antes: $249

Currency
$209
Suscríbete

Termina en:

2 Días
14 Hrs
56 Min
26 Seg

Dando vida a la pelota

10/17
Resources

How to build a controllable ball in Godot?

Creating motion dynamics for your characters and objects is essential to develop an interactive and engaging game. In this tutorial, I will guide you on how to bring a ball to life in Godot using a 2D Kinematic Body. Through these steps, you will be able to control and direct the ball in your game.

What are 2D Kinematic Body nodes?

Kinematic Body 2D nodes allow you to have full control over objects, as they are not affected by external physics such as forces or shocks. This is especially useful for objects that require precise control, like our ball in this example.

  • Why use Kinematic Body?
    • Absolute control without influence of external physics.
    • Allows to steer the ball as desired.
    • Avoids unexpected variations due to the environment.

How to create the scene and add sprites and images?

Let's create the ball scene from scratch, starting by giving it a visual representation and setting up collisions.

  1. Create the scene:

    • Start a new node from Kinematic Body 2D and name it Ball.
  2. Add image to the ball:

    • Import an image in PNG format, preferably a ball, into the file system.
    • Use a Sprite node to display it and drag the image to the Texture property inside the sprite.
  3. Set up collisions:

    • Use a Collision Shape 2D node with a CircleShape2D.
    • Set the radius of the circle to half the size of your image (if the image measures 64x64 pixels, the radius would be 32).

How to program the motion logic?

A suitable script will control the behavior and reaction of the ball to the environment:

# Defining initial variablesvar speed = 0var direction = Vector2.ZEROvar isMoving = false
func _ready(): randomize() # Initialize random number generator speed = 600 # Set initial speed direction.x = [-1, 1][randi() % 2] # Random horizontal direction direction.y = [-0.8, 0.8][randi() % 2] # Initial diagonal direction isMoving = true
func _physics_process(delta): if isMoving: var collide = move_and_collide(direction * speed * delta) if collide: direction = direction.bounce(collide.normal) # Bounce on collision

How to implement the collision system?

The move_and_collide function handles interactions with colliding objects. In case of collision, the bounce() method is used to reflect the direction of the ball:

  • Collisions:
    • Detects collisions and changes the direction using collide.normal.
    • Collisions are reflected creating realistic bounces.

Once the code is executed, you should see the ball move and bounce correctly, interacting dynamically with the game elements. Although you may encounter some bugs, such as a "floating floor", this is part of the learning and development process in the world of game programming, so keep exploring and improving! Coming soon, we will be developing the opponent to complete the game experience - don't miss it!

Contributions 30

Questions 3

Sort by:

Want to see more contributions, questions and answers from the community?

Seguro el profe no lo quiso explicar para mantener el video simple, pero quería aclarar que la función randi SI funciona sin usar el randomize(), lo que pasa es que por default Godot usa la misma ‘seed’ de randomización para cada vez que ejecutamos el juego.
Si la primera vez la pelota salió para la derecha, sin usar randomize(), saldrá siempre para la derecha cada vez que lo ejecutemos (esto es util para debuggear)

Ejecutar randomize() genera una nueva ‘seed’ y nos permite tener diferentes resultados en cada ejecución.

Para todos aquellos que esten haciendo este tutorial con Godot 4.0, deben utilizar el metodo get_normal() en vez de acceder al parametro normal directamente. Esto es por los cambios de convencion que ocurrieron de una version a otra.

Por ende tu codigo, dependiendo de la version en la que estas trabajando, quedaria:

// PARA GODOT 4.0 
func _physics_process(delta):
	if is_moving:
		var collide = move_and_collide(speed * direction * delta);
		if collide:
			direction = direction.bounce(collide.get_normal()); //AQUI ESTA EL CAMBIO 

// PARA VERSIONES ANTERIORES
func _physics_process(delta):
	if is_moving:
	var collide = move_and_collide(speed * direction * delta);
	if collide:
		direction = direction.bounce(collide.normal);

Le adicione un giro a la bola con lo siguiente:

var angular_speed = PI 

func _physics_process(delta):
	if is_moving:
		var collide = move_and_collide(direction * speed * delta)
		rotation += angular_speed * delta
		
		if collide:
			direction = direction.bounce(collide.normal)

Para descargar la imagen pueden entrar aqui https://www.pngwing.com/en/search?q=ball y escogen la que quieran ❤️

Versión del script de la pelota para godot 4:

extends CharacterBody2D

var speed = 0
var is_moving = false

func _ready():
	randomize()
	
	speed = 600
	velocity.x = [-1,1][randi() % 2] * speed
	velocity.y = [-0.8, 0.8][randi() % 2] * speed
	is_moving = true

func _physics_process(delta):
	
	if is_moving:
		var collide = move_and_collide(velocity * delta)
		if collide:
			velocity = velocity.bounce(collide.get_normal())

ya puse la pelota 😃

Creo que al detectar la colisión se debería recalcular la dirección 🤔 basadose en cuál de los StaticBody2D haya colisionado.

func _physics_process(delta):
if is_moving:
var collide = move_and_collide(direction * speed * delta)
if collide:
direction = direction.bounce(collide.normal)
if collide.collider.has_method(“hit”):
collide.collider.hit()
Yo lo hice de esta forma y funciona, lo hice leyendo la documentacion en gadot pero realmente no me quedo muy claro como es que funciona.

Arreglado, la pared inferior necesitaba ser colocada en los limites del tablero.

La solución al problema planteado es que la pelota rebote al hacer contacto con la superficie inferior o superior. Imagino que esa característica se debe configurar desde las propiedades de la pelota.

Para Godot 4.2.1: * Para lograr que la pelota rebote, se hace esto: direction = direction.bounce(collide.get\_normal())
asi es como va mi progreso. es la primera vez usando godot. estoy en la version 4.0![](https://static.platzi.com/media/user_upload/image-e1f2dc6c-10f2-41fd-9e68-b97aeaf0985c.jpg)![]()

Yo lo primero que pense para el rebote fue invertir la dirección pero claro solo servía para las paredes superiores no para el player

if collide:
			direction.y *= -1

La solucion al problema de porque no se mueve cuando colisiona, es porque esta intentando ir siempre en la misma direccion, es como si chocaramos contra una pared y intentamos seguir caminando, hay que decirle que de la vuelta y siga su trayectoria jajaja

Para poder probarlo usé a un “jugador 2” del largo de la pantalla 😅.
Por cierto, no encontré el sprite para la pelota así que usé un rectángulo con textura de ruido jaja.

Yo lo hice de la siguiente forma, si el proceso que hay dentro de la función _ready() hace que la pelota se mueva en una dirección aleatoria y la variable collide almacena el objeto con el que colisiona el balón, entonces, aisló todo ese proceso de _ready() en una función diferente que llame mover() y luego llamo a esta función en _ready() para que se ejecute una vez cargado el balón y en _physics_process() después de validar que la variable collide sea diferente a null.

La pelota ha chocado con otro objeto y ya no se mueve

No hemos cambiado el valor de is_moving, entonces creo que la pelota se quiere mover en cada nuevo frame, pero como su direccion sigue apuntando hacia el objeto, entonces no vemos cambio en su posicion (no se mueve)

Imagino que la funcion move_and_collide retorna un valor cuando el objeto choca o quiere moverse y el resultado de este movimiento es una colision

Podemos entonces, con un condicional en respuesta al choque, cambiar la direccion del movimiento en la pelota para que en el siguiente frame la pelota pueda moverse

De esta manera se podria hacer el efecto del rebote, que creo buscamos

Yo creo que para resolver el problema de la pelota se debe preguntar contra que elemento colisiono y dependiendo de esto cambiar la dirección de la pelota .

extends CharacterBody2D const SPEED = 400.0 func \_physics\_process(delta): var direction = Vector2.ZERO \# Movimiento hacia arriba if Input.is\_action\_pressed("ui\_up"): direction.y -= 1 # Mueve hacia arriba \# Movimientos hacia abajo if Input.is\_action\_pressed("ui\_down"): direction.y += 1 # Mueve hacia abajo \# Normaliza la dirección para evitar movimientos más rápidos en diagonal if direction != Vector2.ZERO: direction = direction.normalized() \# Mueve el personaje velocity = direction \* SPEED move\_and\_slide()
yo lo hice de esta manera, que es mas sencillo para mi : ```js extends CharacterBody2D @export var speed: float func _ready(): randomize() if randi() % 2 == 0: velocity.x = 1 velocity.y = 1 else: velocity.x = -1 velocity.y = -1 velocity *= speed func _physics_process(delta): var collision_info = move_and_collide(velocity * delta) if collision_info: velocity = velocity.bounce(collision_info.get_normal()) ```
yo lo hice de esta forma `extends CharacterBody2D` `@export var speed: float` `func _ready():` ` ``randomize()` ` ` ` ``if randi() % 2 == 0:` ` `` ``velocity.x = 1` ` `` ``velocity.y = 1` ` ``else:` ` `` ``velocity.x = -1` ` `` ``velocity.y = -1` ` `` ` ` ``velocity *= speed` `func _physics_process(delta):` ` ``var collision_info = move_and_collide(velocity * delta)` ` ` ` ``if collision_info:` ` `` ``velocity = velocity.bounce(collision_info.get_normal())`
yo lo hice de esta manera mas sencilla para mi ```js extends CharacterBody2D @export var speed: float func _ready(): randomize() if randi() % 2 == 0: velocity.x = 1 velocity.y = 1 else: velocity.x = -1 velocity.y = -1 velocity *= speed func _physics_process(delta): var collision_info = move_and_collide(velocity * delta) if collision_info: velocity = velocity.bounce(collision_info.get_normal()) ```extends CharacterBody2D @export var speed: float func \_ready(): randomize() if randi() % 2 == 0: velocity.x = 1 velocity.y = 1 else: velocity.x = -1 velocity.y = -1 velocity \*= speed func \_physics\_process(delta): var collision\_info = move\_and\_collide(velocity \* delta) if collision\_info: velocity = velocity.bounce(collision\_info.get\_normal())
yo lo hice de esta manera me pareció mas sencilla ```js extends CharacterBody2D @export var speed: float func _ready(): randomize() if randi() % 2 == 0: velocity.x = 1 velocity.y = 1 else: velocity.x = -1 velocity.y = -1 velocity *= speed func _physics_process(delta): var collision_info = move_and_collide(velocity * delta) if collision_info: velocity = velocity.bounce(collision_info.get_normal()) ```extends CharacterBody2D @export var speed: float func \_ready(): randomize() if randi() % 2 == 0: velocity.x = 1 velocity.y = 1 else: velocity.x = -1 velocity.y = -1 velocity \*= speed func \_physics\_process(delta): var collision\_info = move\_and\_collide(velocity \* delta) if collision\_info: velocity = velocity.bounce(collision\_info.get\_normal())
Yo lo hice diferente. Buscando en la documentacion de godot encontre que GetAngle() me devolvia el angulo de la colicion. `public override void _PhysicsProcess(double delta){` `    if(is_moving){` `        KinematicCollision2D collition = MoveAndCollide(direction * (int)(speed * delta));` `        if(collition != null){` `            float angle = collition.GetAngle();` `            if(angle == 0 || (collition.GetAngle() > 3.14 && angle < 3.15)){` `                direction.Y *= -1;` `            }else{` `                direction.X *= -1;` `            }` `        }` `    }` `}` Yo lo estoy haciendo en C# (Basicamente porque me gusta mas el lenguaje)
![](https://drive.google.com/file/d/1e4iFSGrRTkEGYrLRVrw9qzbfxy28nnHd/view?usp=sharing)
extends CharacterBody2D var speed = 600 var direction = Vector2.ZERO var is\_moving = false func \_ready(): randomize() direction.x = \[-1,1]\[randi() % 2] direction.y = \[-0.8,0.8]\[randi() % 2] is\_moving = true func \_physics\_process(delta): if is\_moving: var collide = move\_and\_collide(direction \* speed \* delta) if collide: direction = direction.bounce(collide.get\_normal()); Si este código de programación de la manipulación de la pelota no les funciona y hay defectos con el colisionador, tengo escrito esto.extends CharacterBody2D var speed = 600 var direction = Vector2.ZERO var is\_moving = false func \_ready(): randomize() direction.x = \[-1,1]\[randi() % 2] direction.y = \[-0.8,0.8]\[randi() % 2] is\_moving = true func \_physics\_process(delta): if is\_moving: var collide = move\_and\_collide(direction \* speed \* delta) if collide: direction = direction.bounce(collide.get\_normal()); ```js extends CharacterBody2D var speed = 600 var direction = Vector2.ZERO var is_moving = false func _ready(): randomize() direction.x = [-1,1][randi() % 2] direction.y = [-0.8,0.8][randi() % 2] is_moving = true func _physics_process(delta): if is_moving: var collide = move_and_collide(direction * speed * delta) if collide: direction = direction.bounce(collide.get_normal()); ```
Saludos cordiales. Hice una pequeña prueba sobre el código de programación que hice en la animación o manipulación de la pelota, o en mi caso que lo nombre como disco, porque es como hockey. El GDScript que tengo es sobre la clase de darle vida a la pelota tal y como mencionó el profesor, y una mitad del tutorial de YouTube. extends CharacterBody2D var speed = 600 var direction = Vector2.ZERO var is\_moving = false func \_ready(): randomize() direction.x = \[-1,1]\[randi() % 2] direction.y = \[-0.8,0.8]\[randi() % 2] is\_moving = true func \_physics\_process(delta): if is\_moving: var collide = move\_and\_collide(direction \* speed \* delta) if collide: direction = direction.bounce(collide.get\_normal()); Eso fue lo que corregí de los errores que tuve durante la programación de la manipulación de la pelota y aquí está la exposición del juego.

del reto del piso flotante es que al principio lo movio arriba de borde y tenia que moverlo debajo

yo pienso que si chocamos rebote dependiendo de la pared que choque:
Por ejemplo:
If collide:
direction = y que cambie a la derecha o izquierda

Bien, entiendo, entonces hicimos paredes con Collision Shape para que cuando la pelota se mueva y colisione con algo, lo detectemos y cambiemos su dirección, es interesante 😄