Giới thiệu về phương thức ảo
Thuộc phần Lập trình hướng đối tượng trong hành trình GDScript của Coddy. Bài học 31 trên 65.
Python có các phương thức đặc biệt như __init__ và __str__, mà ngôn ngữ sẽ gọi thay bạn. Phiên bản tương ứng trong Godot là phương thức ảo: một phương thức có tên cố định, bắt đầu bằng dấu gạch dưới, do bạn định nghĩa trong lớp và Godot gọi vào đúng thời điểm. Bạn đã dùng hai phương thức:
_init()chạy khinew()tạo đối tượng, với các đối số được truyền vàonew()._ready()chạy khi một nút đi vào cây cảnh, nơimain.gdbắt đầu.
Các phương thức khác là _to_string(), được gọi khi in ra một đối tượng, các phương thức iterator cho phép vòng lặp for duyệt qua một đối tượng (cả hai nội dung này sẽ có trong các bài học tiếp theo), và _notification(), nhận sự kiện từ engine. Một trong số đó, NOTIFICATION_PREDELETE, được gửi ngay trước khi đối tượng bị xóa:
# 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") # Đuốc Hall torch đã sáng
torch = null # Đuốc Hall torch đã tắtĐối tượng RefCounted sẽ bị xóa ngay khi không còn biến nào tham chiếu đến nó, vì vậy torch = null gửi thông báo ngay lập tức. Giá trị mặc định trong _init() khiến đối số của new() trở thành tùy chọn: Torch.new() tạo ra một ngọn đuốc có tên là Torch.
Python cũng dùng các phương thức đặc biệt cho toán tử, chẳng hạn như __add__ cho + và __eq__ cho ==. GDScript không hỗ trợ nạp chồng toán tử: potion_a + potion_b sẽ gây lỗi. Thay vào đó, hãy viết một phương thức:
# 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) trả về một lọ thuốc mới và giữ nguyên cả hai lọ thuốc ban đầu. Toán tử == giữa hai đối tượng kiểm tra xem hai bên có phải là cùng một đối tượng hay không, chứ không kiểm tra xem giá trị của chúng có khớp nhau hay không: Potion.new(5) == Potion.new(5) là false. Hãy viết một phương thức như equals(other) khi bạn cần so sánh các giá trị.
Thử thách
DễViết lớp Counter trong counter.gd:
_init(start = 0, step_size = 1)lưu giá trị bắt đầu vàovaluevà bước tăng vàostep. Các giá trị mặc định đã có trong chữ ký hàm, nênCounter.new(),Counter.new(5)vàCounter.new(5, 2)đều hoạt động.tick()cộngstepvàovalue.plus(other)thay cho toán tử+, vốn không thể được định nghĩa trong GDScript: hàm trả về một mớiCountercó giá trị bằng tổng của hai giá trị và có bước tăng bằng bước tăng của bộ đếm này. Cả hai bộ đếm đều không thay đổi.equals(other)trả vềtruekhi hai bộ đếm có cùng giá trị.
Đoạn code được cung cấp đọc hai dòng để tạo bộ đếm a và b (một dòng trống, START hoặc START STEP), sau đó đọc một dòng cho biết số lần tăng a và b. Đoạn code in ra cả hai bộ đếm, tổng của chúng, việc giá trị của chúng có bằng nhau hay không và việc a == b có đúng hay không. Với các dòng 5, 2 3 và 3 1, đoạn code in ra:
a: 8 (step 1)
b: 5 (step 3)
a plus b: 13 (step 1)
same value: false
same object: falseĐặt code của bạn trong counter.gd. main.gd chứa code đầu vào/đầu ra được cung cấp và bạn không thể chỉnh sửa tệp này.
Tự làm thử
extends Node
func _ready():
# Đoạn code đầu vào/đầu ra đã cho: giữ nguyên
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]))
Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Lập trình hướng đối tượng
1Nền tảng về OOP
Tệp bên ngoàiGiới thiệu về OOPLớp và đối tượngTừ khóa selfPhương thứcThuộc tínhHàm khởi tạo (_init)Ôn tập: máy tính đơn giản4Tính đa hình
Xem lại cách ghi đè phương thứcĐịnh kiểu vịtLớp và phương thức trừu tượngThiết kế interfaceÔn tập: máy tính hình học7Tín hiệu
Tín hiệu là gì?Khai báo và phát tín hiệuKết nối với tín hiệuTín hiệu có đối sốÔn tập: hệ thống sức khỏe10Các mẫu thiết kế phần 2
Mẫu lệnhMẫu bộ chuyển đổiMẫu trang tríMẫu phương thức khuôn mẫuMẫu trạng tháiMẫu tổng hợp2Thuộc tính của lớp
Biến instance và biến staticHàm staticPhương thức thiết lập thuộc tínhPhương thức lấy thuộc tínhQuy ước về tính riêng tưÔn tập: trình quản lý tài khoản ngân hàng5Tính đóng gói
Thành viên công khai và riêng tưXác thực bằng phương thức setterẨn thông tinThuộc tính chỉ đọcÔn tập: hệ thống hồ sơ học sinh8Khái niệm OOP nâng cao
Kết hợp và kế thừaLớp bên trongNode dưới dạng thành phầnRefCounted và NodeEnum trong lớp3Kế thừa
Kế thừa cơ bảnTừ khóa superGhi đè phương thứcChuỗi kế thừaKiểm tra kiểu bằng isTổng kết: phân cấp nhân viên6Phương thức đặc biệt
Giới thiệu về phương thức ảoPhương thức _to_stringTrình lặp tùy chỉnhÔn tập: danh sách tùy chỉnhTự luyện tập: Trình biên dịch GDScript online