自定义信号

一个节点声明信号,却从不知道谁在监听。五个面板连上它,轮到自己时就亮起。

上方的编辑器正在运行这个项目。改一行代码,它就会重新加载。

用到的 Godot 类

signalSignal.emitSignal.connectPanelContainer

代码

scripts/main.gd
extends Node

signal ping(slot: int)
signal broadcast(message: String)

const NAMES: Array = ['audio', 'score', 'quest', 'hud', 'save']
const TICK: float = 0.09

var status: Label
var elapsed: float = 0.0
var emitted: int = 0


func _ready() -> void:
	var column: VBoxContainer = _root()

	var title: Label = Label.new()
	title.text = 'Five listeners, one signal'
	title.add_theme_font_size_override('font_size', 28)
	column.add_child(title)

	var hint: Label = Label.new()
	hint.text = 'main.gd declares signal ping(slot) and knows nothing about who listens. Each panel connects itself.'
	hint.add_theme_color_override('font_color', Color('#8a90a0'))
	column.add_child(hint)

	var row: HBoxContainer = HBoxContainer.new()
	row.add_theme_constant_override('separation', 16)
	column.add_child(row)

	var listener_script: GDScript = Get.script('listener')

	for i in NAMES.size():
		var listener: PanelContainer = PanelContainer.new()
		listener.set_script(listener_script)
		row.add_child(listener)
		listener.setup(i, NAMES[i])
		ping.connect(listener.on_ping)
		broadcast.connect(listener.on_broadcast)

	var button: Button = Button.new()
	button.text = 'emit broadcast to everyone'
	button.pressed.connect(func(): broadcast.emit('broadcast'))
	column.add_child(button)

	status = Label.new()
	status.add_theme_color_override('font_color', Color('#8eef97'))
	status.text = 'nothing emitted yet'
	column.add_child(status)

	print('a ping walks the slots on its own, the button hits every listener at once')


func _process(delta: float) -> void:
	elapsed += delta

	if elapsed < TICK:
		return

	elapsed = 0.0
	var slot: int = emitted % NAMES.size()
	emitted += 1

	if emitted % 13 == 0:
		broadcast.emit('broadcast')
		status.text = 'broadcast reached all %d listeners' % NAMES.size()
		return

	ping.emit(slot)
	status.text = 'ping(%d) emitted, %d emits so far' % [slot, emitted]


func _root() -> VBoxContainer:
	var background: ColorRect = ColorRect.new()
	background.color = Color('#12141a')
	add_child(background)
	background.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)

	var center: CenterContainer = CenterContainer.new()
	add_child(center)
	center.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)

	var column: VBoxContainer = VBoxContainer.new()
	column.custom_minimum_size = Vector2(1030, 0)
	column.add_theme_constant_override('separation', 18)
	center.add_child(column)

	return column
scripts/listener.gd
extends PanelContainer

const IDLE: Color = Color('#2a2f3d')
const LIT: Color = Color('#8da5f3')

var slot: int = 0
var hits: int = 0
var glow: float = 0.0
var style: StyleBoxFlat
var counter: Label
var last: Label


func setup(index: int, listener_name: String) -> void:
	slot = index

	style = StyleBoxFlat.new()
	style.bg_color = IDLE
	style.set_corner_radius_all(14)
	style.set_content_margin_all(18)
	add_theme_stylebox_override('panel', style)
	custom_minimum_size = Vector2(190, 150)

	var box: VBoxContainer = VBoxContainer.new()
	box.add_theme_constant_override('separation', 6)
	add_child(box)

	var title: Label = Label.new()
	title.text = listener_name
	title.add_theme_font_size_override('font_size', 20)
	box.add_child(title)

	last = Label.new()
	last.text = 'slot %d' % slot
	last.add_theme_color_override('font_color', Color('#8a90a0'))
	box.add_child(last)

	counter = Label.new()
	counter.text = '0'
	counter.add_theme_font_size_override('font_size', 44)
	box.add_child(counter)


func on_ping(index: int) -> void:
	if index != slot:
		return

	hits += 1
	glow = 1.0
	counter.text = str(hits)
	last.text = 'ping(%d)' % index


func on_broadcast(message: String) -> void:
	hits += 1
	glow = 1.0
	counter.text = str(hits)
	last.text = message


func _process(delta: float) -> void:
	if glow <= 0.0:
		return

	glow = maxf(glow - delta * 3.0, 0.0)
	style.bg_color = IDLE.lerp(LIT, glow)

更多数据示例