Menu
CoddyTech

Introducción a los métodos virtuales

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

Python tiene métodos mágicos como __init__ y __str__, que el lenguaje llama por ti. La versión de Godot es el método virtual: un método con un nombre fijo, que empieza con un guion bajo, que defines en tu clase y que Godot llama en el momento adecuado. Ya has usado dos:

  • _init() se ejecuta cuando new() crea el objeto, con los argumentos que se le dan a new().
  • _ready() se ejecuta cuando un nodo entra en el árbol de escenas, que es donde empieza main.gd.

Otros son _to_string(), que se llama cuando se imprime un objeto, los métodos iteradores que permiten a un bucle for recorrer un objeto (ambos se verán en las próximas lecciones) y _notification(), que recibe eventos del motor. Uno de ellos, NOTIFICATION_PREDELETE, se produce justo antes de que se elimine el objeto:

# torch.gd
class_name Torch
extends RefCounted

var label: String

func _init(new_label: String = "Torch") -> void:
	label = new_label
	print(label, " lit")

func _notification(what: int) -> void:
	if what == NOTIFICATION_PREDELETE:
		print(label, " burned out")
# main.gd
var torch := Torch.new("Hall torch") # Antorcha del pasillo encendida
torch = null # Antorcha del pasillo apagada

Un objeto RefCounted se elimina en cuanto ninguna variable hace referencia a él, así que torch = null envía la notificación de inmediato. El valor predeterminado en _init() hace que el argumento de new() sea opcional: Torch.new() crea una antorcha llamada Torch.

Python también usa métodos mágicos para los operadores, como __add__ para + y __eq__ para ==. GDScript no admite la sobrecarga de operadores: potion_a + potion_b es un error. En su lugar, escribe un método:

# potion.gd
class_name Potion
extends RefCounted

var power: int

func _init(start_power: int) -> void:
	power = start_power

func combined(other: Potion) -> Potion:
	return Potion.new(power + other.power)

potion_a.combined(potion_b) devuelve una nueva poción y deja ambos originales sin cambios. == entre dos objetos comprueba si ambos lados son el mismo objeto, no si sus valores coinciden: Potion.new(5) == Potion.new(5) es false. Escribe un método como equals(other) cuando necesites comparar valores.

challenge icon

Desafío

Fácil

Escribe la clase Counter en counter.gd:

  • _init(start = 0, step_size = 1) guarda el valor inicial en value y el tamaño del paso en step. Los valores predeterminados ya están en la firma, así que Counter.new(), Counter.new(5) y Counter.new(5, 2) funcionan.
  • tick() suma step a value.
  • plus(other) reemplaza el operador +, que GDScript no permite definir: devuelve un nuevo Counter cuyo valor es la suma de ambos valores y cuyo paso es el de este contador. Ninguno de los dos contadores cambia.
  • equals(other) devuelve true cuando ambos contadores tienen el mismo valor.

El código proporcionado lee dos líneas que crean los contadores a y b (una línea vacía, START o START STEP), y después una línea con la cantidad de veces que se debe incrementar a y b. Imprime ambos contadores, su suma, si sus valores son iguales y si a == b. Para las líneas 5, 2 3 y 3 1, imprime:

a: 8 (step 1)
b: 5 (step 3)
a plus b: 13 (step 1)
same value: false
same object: false

Tu código va en counter.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: déjalo tal como está
	var a := make_counter(OS.read_string_from_stdin())
	var b := make_counter(OS.read_string_from_stdin())
	var ticks := OS.read_string_from_stdin().split(" ")
	for i in int(ticks[0]):
		a.tick()
	for i in int(ticks[1]):
		b.tick()
	print("a: %d (step %d)" % [a.value, a.step])
	print("b: %d (step %d)" % [b.value, b.step])
	var total := a.plus(b)
	print("a plus b: %d (step %d)" % [total.value, total.step])
	print("same value: %s" % a.equals(b))
	print("same object: %s" % (a == b))

func make_counter(line: String) -> Counter:
	var parts := line.split(" ", false)
	if parts.is_empty():
		return Counter.new()
	if parts.size() == 1:
		return Counter.new(int(parts[0]))
	return Counter.new(int(parts[0]), int(parts[1]))
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