Menu
CoddyTech

Wprowadzenie do metod wirtualnych

Część sekcji Programowanie obiektowe ścieżki GDScript w Coddy. Lekcja 31 z 65.

Python ma magiczne metody, takie jak __init__ i __str__, które język wywołuje za Ciebie. Odpowiednikiem w Godot jest metoda wirtualna: metoda o ustalonej nazwie, zaczynającej się od podkreślenia, którą definiujesz w swojej klasie, a Godot wywołuje w odpowiednim momencie. Użyłeś już dwóch:

  • _init() uruchamia się, gdy new() tworzy obiekt, z argumentami przekazanymi do new().
  • _ready() uruchamia się, gdy węzeł wchodzi do drzewa sceny — właśnie tam rozpoczyna się main.gd.

Do innych należą _to_string(), wywoływana, gdy obiekt jest wypisywany, metody iteratora, które pozwalają pętli for przechodzić przez obiekt (obie kwestie omówimy w kolejnych lekcjach), oraz _notification(), która odbiera zdarzenia z silnika. Jedno z nich, NOTIFICATION_PREDELETE, jest wysyłane tuż przed usunięciem obiektu:

# 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") # Pochodnia w holu została zapalona
torch = null # Pochodnia w holu się wypaliła

Obiekt RefCounted jest usuwany, gdy tylko żadna zmienna już się do niego nie odwołuje, więc torch = null natychmiast wysyła powiadomienie. Wartość domyślna w _init() sprawia, że argument new() jest opcjonalny: Torch.new() tworzy pochodnię o nazwie Torch.

Python również używa metod specjalnych do obsługi operatorów, takich jak __add__ dla + i __eq__ dla ==. GDScript nie obsługuje przeciążania operatorów: potion_a + potion_b powoduje błąd. Zamiast tego napisz metodę:

# 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) zwraca nową miksturę i pozostawia obie oryginalne bez zmian. Operator == między dwoma obiektami sprawdza, czy obie strony są tym samym obiektem, a nie czy ich wartości są zgodne: Potion.new(5) == Potion.new(5) to false. Gdy potrzebujesz porównać wartości, napisz metodę taką jak equals(other).

challenge icon

Wyzwanie

Łatwy

Napisz klasę Counter w pliku counter.gd:

  • _init(start = 0, step_size = 1) zapisuje wartość początkową w value, a wielkość kroku w step. Wartości domyślne są już podane w sygnaturze, więc działają wszystkie wywołania: Counter.new(), Counter.new(5) i Counter.new(5, 2).
  • tick() dodaje step do value.
  • plus(other) zastępuje operator +, którego nie można zdefiniować w GDScript: zwraca nowy obiekt Counter, którego wartością jest suma obu wartości, a krokiem — krok tego licznika. Żaden z liczników się nie zmienia.
  • equals(other) zwraca true, gdy oba liczniki mają tę samą wartość.

Dostarczony kod odczytuje dwa wiersze, które tworzą liczniki a i b (pusty wiersz, START lub START STEP), a następnie jeden wiersz z liczbą wywołań tyknięcia dla a i b. Wypisuje oba liczniki, ich sumę, informację, czy ich wartości są równe, oraz informację, czy a == b. Dla wierszy 5, 2 3 i 3 1 wypisuje:

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

Twój kod umieść w pliku counter.gd. main.gd zawiera dostarczony kod wejścia/wyjścia i nie można go edytować.

Spróbuj swoich sił

extends Node

func _ready():
	# Dostarczony kod wejścia/wyjścia: pozostaw go bez zmian
	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 iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator GDScript online