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ę, gdynew()tworzy obiekt, z argumentami przekazanymi donew()._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łaObiekt 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).
Wyzwanie
ŁatwyNapisz klasę Counter w pliku counter.gd:
_init(start = 0, step_size = 1)zapisuje wartość początkową wvalue, a wielkość kroku wstep. Wartości domyślne są już podane w sygnaturze, więc działają wszystkie wywołania:Counter.new(),Counter.new(5)iCounter.new(5, 2).tick()dodajestepdovalue.plus(other)zastępuje operator+, którego nie można zdefiniować w GDScript: zwraca nowy obiektCounter, którego wartością jest suma obu wartości, a krokiem — krok tego licznika. Żaden z liczników się nie zmienia.equals(other)zwracatrue, 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: falseTwó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]))
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy programowania obiektowego
Pliki zewnętrzneWprowadzenie do programowania obiektowegoKlasy a obiektySłowo kluczowe selfMetodyWłaściwościKonstruktor (_init)Powtórka – prosty kalkulator4Polimorfizm
Ponowne omówienie przesłaniania metodDuck typingKlasy i metody abstrakcyjneProjektowanie interfejsówPowtórzenie – kalkulator kształtów7Sygnały
Czym jest sygnał?Deklarowanie i emitowanieŁączenie z sygnałamiSygnały z argumentamiPodsumowanie — system zdrowia10Wzorce projektowe, część 2
Wzorzec poleceniaWzorzec adapteraWzorzec dekoratoraWzorzec metody szablonowejWzorzec stanuWzorzec kompozytu2Właściwości klas
Zmienne instancji a zmienne statyczneFunkcje statyczneSettery właściwościGettery właściwościPrywatne z konwencjiPodsumowanie — menedżer kont bankowych5Enkapsulacja
Elementy publiczne i prywatneWalidacja za pomocą setterówUkrywanie informacjiWłaściwości tylko do odczytuPodsumowanie – system ewidencji uczniów8Zaawansowane koncepcje OOP
Kompozycja a dziedziczenieKlasy wewnętrzneWęzły jako komponentyRefCounted a NodeTypy wyliczeniowe w klasach11Projekt: Zarządzanie biblioteką
Przegląd projektuKlasy książki i użytkownika3Dziedziczenie
Podstawy dziedziczeniaSłowo kluczowe superNadpisywanie metodŁańcuchy dziedziczeniaSprawdzanie typów za pomocą isPodsumowanie – hierarchia pracowników6Metody specjalne
Wprowadzenie do metod wirtualnychMetoda _to_stringWłasne iteratoryPodsumowanie — własna lista9Wzorce projektowe — część 1
Wprowadzenie do wzorców projektowychWzorzec SingletonWzorzec FactoryWzorzec ObserverWzorzec StrategyPoćwicz samodzielnie: Kompilator GDScript online