Menu
CoddyTech

Tipado pato

Parte de la sección Programación orientada a objetos del Journey de GDScript de Coddy. Lección 22 de 65.

La tipificación pato se centra en lo que un objeto puede hacer, no en la clase a la que pertenece. Si tiene el método que llamas, la llamada funciona. El nombre proviene del dicho «si nada como un pato y grazna como un pato, es un pato».

Estas dos clases no comparten ningún padre propio, pero ambas tienen swim() y quack():

# duck.gd
class_name Duck
extends RefCounted

func swim() -> String:
	return "Duck swimming"

func quack() -> String:
	return "Quack!"
# robot.gd
class_name Robot
extends RefCounted

func swim() -> String:
	return "Robot swimming with propellers"

func quack() -> String:
	return "Robot sound: BEEP BEEP!"

Un parámetro sin tipo acepta cualquier objeto. La función llama a los métodos, y cada objeto ejecuta los suyos:

func make_it_swim_and_quack(thing) -> void:
	print(thing.swim())
	print(thing.quack())
make_it_swim_and_quack(Duck.new())
make_it_swim_and_quack(Robot.new())
Duck swimming
Quack!
Robot swimming with propellers
Robot sound: BEEP BEEP!

La sobrescritura necesita una clase padre compartida; la tipificación pato no. Con el parámetro tipado como thing: Duck, pasar un Robot sería un error de análisis.

Cuando a un objeto le falta el método, la llamada detiene la función con un error como Invalid call. Nonexistent function 'quack'. Primero, comprueba con has_method(), que recibe el nombre del método como un String:

var things := [Duck.new(), Rock.new()]
for thing in things:
	if thing.has_method("quack"):
		print(thing.quack())
	else:
		print("This one cannot quack")
Quack!
This one cannot quack

El precio: con los tipos, Godot detecta un nombre de método incorrecto antes de que se ejecute el programa; con el tipado pato, solo te enteras cuando se ejecuta la línea. Úsalo para objetos de clases no relacionadas que comparten algunos métodos.

challenge icon

Desafío

Fácil

Una explosión daña todo lo que hay cerca y que puede recibir daño. Los objetos no comparten ninguna clase principal. player.gd y rock.gd están terminados: un Player tiene take_damage(amount) y status(), mientras que un Rock solo tiene status().

  • En crate.gd, dale a Crate una variable broken que empiece en false, un método take_damage(amount) que rompa la caja cuando la cantidad sea 10 o más, y un método status() que devuelva Crate: broken o Crate: intact.
  • En explosion.gd, escribe la función estática hit_all(things, amount). Llama a take_damage(amount) en cada objeto del Array que tenga ese método y devuelve cuántos objetos alcanzó.

El código proporcionado lee una línea con nombres de objetos (player, crate o rock), después cuántas explosiones siguen y el daño de cada una. Imprime cuántos objetos alcanzó cada explosión y, después, el estado de cada objeto. Para player crate rock y explosiones de 5 y 20, imprime:

Explosion 1 hit 2 objects
Explosion 2 hit 2 objects
Player: 75 HP
Crate: broken
Rock: solid

Tu código va en crate.gd y explosion.gd. main.gd contiene el código de entrada/salida proporcionado y no se puede editar.

Pruébalo tú mismo

extends Node

func _ready():
	# Código de entrada/salida proporcionado: mantenlo tal como está
	var things := []
	for word in OS.read_string_from_stdin().split(" "):
		if word == "player":
			things.append(Player.new())
		elif word == "crate":
			things.append(Crate.new())
		else:
			things.append(Rock.new())
	var count := int(OS.read_string_from_stdin())
	for i in count:
		var hits := Explosion.hit_all(things, int(OS.read_string_from_stdin()))
		print("Explosion %d hit %d objects" % [i + 1, hits])
	for thing in things:
		print(thing.status())
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación orientada a objetos

Practica por tu cuenta: Compilador de GDScript online