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 cuandonew()crea el objeto, con los argumentos que se le dan anew()._ready()se ejecuta cuando un nodo entra en el árbol de escenas, que es donde empiezamain.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 apagadaUn 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.
Desafío
FácilEscribe la clase Counter en counter.gd:
_init(start = 0, step_size = 1)guarda el valor inicial envaluey el tamaño del paso enstep. Los valores predeterminados ya están en la firma, así queCounter.new(),Counter.new(5)yCounter.new(5, 2)funcionan.tick()sumastepavalue.plus(other)reemplaza el operador+, que GDScript no permite definir: devuelve un nuevoCountercuyo valor es la suma de ambos valores y cuyo paso es el de este contador. Ninguno de los dos contadores cambia.equals(other)devuelvetruecuando 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: falseTu 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]))
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
1Fundamentos de la programación orientada a objetos
Archivos externosIntroducción a la programación orientada a objetosClases vs. objetosLa palabra clave selfMétodosPropiedadesConstructor (_init)Repaso: calculadora sencilla4Polimorfismo
Repaso de la sobrescritura de métodosTipado patoClases y métodos abstractosDiseño de interfacesRepaso: calculadora de formas7Señales
¿Qué es una señal?Declarar y emitirConectarse a las señalesSeñales con argumentosRepaso: sistema de salud10Patrones de diseño, parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón Composite2Propiedades de clase
Variables de instancia y estáticasFunciones estáticasMétodos setter de propiedadesMétodos getter de propiedadesPrivado por convenciónRepaso: administrador de cuentas bancarias5Encapsulación
Miembros públicos y privadosValidación con settersOcultación de informaciónPropiedades de solo lecturaRepaso: sistema de registros de estudiantes8Conceptos avanzados de POO
Composición frente a herenciaClases internasNodos como componentesRefCounted frente a NodeEnums en clases3Herencia
Herencia básicaLa palabra clave superSobrescritura de métodosCadenas de herenciaComprobaciones de tipo con isRepaso: jerarquía de empleados6Métodos especiales
Introducción a los métodos virtualesEl método _to_stringIteradores personalizadosRepaso: lista personalizada9Patrones de diseño, parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón ObserverPatrón StrategyPractica por tu cuenta: Compilador de GDScript online