Menu
CoddyTech

Kết nối với tín hiệu

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 37 trên 65.

connect() nhận hàm cần chạy dưới dạng Callable. Ghi tên phương thức không có dấu ngoặc đơn hoặc viết lambda:

chest.opened.connect(_on_chest_opened)          # một phương thức (method) của script này
chest.opened.connect(quest_log.add_entry)       # một phương thức của đối tượng khác
chest.opened.connect(func(): print("Creak!"))   # một hàm lambda

Godot đặt tên cho phương thức lắng nghe theo thứ tự _on_, tên đối tượng phát tín hiệu, rồi đến tên tín hiệu: _on_chest_opened. Một tín hiệu có thể kết nối với nhiều hàm, và chúng chạy theo thứ tự được kết nối.

Một đối tượng lắng nghe thường tự kết nối trong một phương thức nhận đối tượng phát sự kiện:

# quest_log.gd
class_name QuestLog
extends RefCounted

var chests_opened := 0

func track(chest: Chest) -> void:
	if not chest.opened.is_connected(_on_chest_opened):
		chest.opened.connect(_on_chest_opened)

func untrack(chest: Chest) -> void:
	if chest.opened.is_connected(_on_chest_opened):
		chest.opened.disconnect(_on_chest_opened)

func _on_chest_opened() -> void:
	chests_opened += 1

Kết nối cùng một hàm với cùng một tín hiệu hai lần sẽ gây ra lỗi, và ngắt kết nối một hàm chưa được kết nối cũng vậy. is_connected() kiểm tra trước. disconnect() ngừng lắng nghe, và lần phát tín hiệu tiếp theo sẽ không chạy hàm đó nữa.

Truyền CONNECT_ONE_SHOT làm đối số (argument) thứ hai, kết nối sẽ tự xóa sau lần gọi đầu tiên: chest.opened.connect(_on_first_open, CONNECT_ONE_SHOT).

Lambda giữ giá trị mà biến cục bộ có tại thời điểm tạo lambda. count += 1 bên trong một lambda đã kết nối sẽ thay đổi bản sao đó, còn count trong _ready() vẫn là 0. Hãy giữ bộ đếm trong biến thành viên của một đối tượng lắng nghe, như QuestLog.

challenge icon

Thử thách

Dễ

Trường bắn có các mục tiêu phát tín hiệu hit khi bị bắn. Hãy viết ScoreBoard để lắng nghe các tín hiệu đó:

  • watch(target) kết nối tín hiệu hit của mục tiêu với _on_target_hit. Theo dõi một mục tiêu đã được theo dõi không làm thay đổi gì.
  • ignore(target) ngắt kết nối tín hiệu. Bỏ theo dõi một mục tiêu chưa được theo dõi không làm thay đổi gì.
  • _on_target_hit() cộng 10 vào points và in ra Hit! Score: N.

Theo dõi hai lần hoặc bỏ theo dõi một mục tiêu chưa được theo dõi không được gây lỗi, vì bất kỳ lỗi nào cũng khiến bài kiểm tra thất bại. target.gd đã hoàn chỉnh.

Code được cung cấp đọc số lượng mục tiêu, sau đó đọc các lệnh như watch 0, ignore 0 và shoot 0, rồi in ra điểm số cuối cùng. Với hai mục tiêu và các lệnh watch 0, shoot 0, shoot 1, watch 1, watch 1, shoot 1, ignore 0, shoot 0, chương trình in ra:

Shot target 0
Hit! Score: 10
Shot target 1
Shot target 1
Hit! Score: 20
Shot target 0
Final score: 20

Code của bạn nằm trong score_board.gd và target.gd. main.gd chứa code đầu vào/đầu ra được cung cấp và không thể chỉnh sửa.

Tự làm thử

extends Node

func _ready():
	# Đoạn code đầu vào/đầu ra có sẵn: giữ nguyên
	var board := ScoreBoard.new()
	var targets: Array[Target] = []
	for i in int(OS.read_string_from_stdin()):
		targets.append(Target.new())
	var count := int(OS.read_string_from_stdin())
	for i in count:
		var parts := OS.read_string_from_stdin().split(" ")
		var target := targets[int(parts[1])]
		if parts[0] == "watch":
			board.watch(target)
		elif parts[0] == "ignore":
			board.ignore(target)
		else:
			print("Shot target ", parts[1])
			target.shoot()
	print("Final score: ", board.points)
quiz iconTự kiểm tra

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

Tự luyện tập: Trình biên dịch GDScript online