一个小的事件总线的模块

一个小的事件总线的模块

BanBuFC

2025-01-11 发布184 浏览 · 1 点赞 · 0 收藏

这是我自用的一个事件总线的模块。其主要作用是可以在整个系统内传递信号,可以随时的去连接一个信号然后,通过发送这个信号来运行对应的函数。推荐把它作为单例运行。在使用的时候只需要在一个地方先声明一个信号,在需要使用该信号的地方连接函数,然后适当的时候发出对应的信号就可以了。

部分思路来自于玩物不丧志的老李
对应视频地址老李godot4.2仿《杀戮尖塔》战斗系统-09-EventBus事件总线的实现,利用signal信号和自动加载全局脚本_哔哩哔哩_bilibili

为了方便对信号进行控制,这里除了普通的订阅与取消订阅以外还会有一些阻塞的状态和一些冻结的状态。
阻塞状态会使得该信号可以被发出,但不会有任何的响应。这在某些时候需要暂停用户输入的时候非常有用,比方说打开背包界面的时候禁止玩家使用w a s d。
而冻结状态更多的是当一个信号不再会被使用的时候你无法对它进行新增订阅但可以随时取消这样方便信号之间的管理。

当然也存在一些不足。由于本人技术有限,暂时不能把对应的函数具体位置给定位出来。
也就意味着你在调试的时候你并不能将信号与连接的方法具体在那个文件的哪一行定位出来。

extends Node

## 记录信号与事件的字典
## {"signal_name":[callable1,callable2]}
var buss:Dictionary
var block_list=[]
var lock_list=[]

## 推送事件
func push_event(destination: String,payload) ->void:
	# 获取内部信号名称
	var dest_signal:String =_get_destination_signal(destination)
	
	# 需要以列表传递参数,如果不是,将其变为列表形式
	if not payload is Array:
		payload =[payload]

 	# 判断是否有信号,如果没有,则会触发提示,但是不会终止程序
	if not buss.has(dest_signal):
		printerr(destination+"目前还没有订阅者")
		return

	if event_is_block(destination):
		printerr(destination+"目前处于被阻塞状态")
		return
		
	# 遍历信号对应的方法列表
	var callables=buss[dest_signal]
	for each:Callable in callables:
		each.get_object().callv(each.get_method(),payload)
	
	# 打印信号流 不适用于以发布模式导出的项目
	var pusher_stack=get_stack()
	var pusher:String="null"
	if pusher_stack.size()>=2:
		pusher=pusher_stack[1]["source"] +' '+pusher_stack[1]["function"]
	print(pusher+" -> "+str(buss[dest_signal]))

## 订阅事件
func subscribe(destination:String,callback:Callable)-> void:
	if event_is_lock(destination):
		printerr(destination+"目前处于锁定状态,暂时不可订阅")
		return
	# 获取内部信号名称
	var dest_signal:String =_get_destination_signal(destination)
	
	# 向buss添加键值对
	if not buss.has(dest_signal):
		buss[dest_signal]=[callback]
	else:
		buss[dest_signal].append(callback)

## 取消订阅事件
func unsubscribe(destination: String, callback: Callable) -> void:
	## 获取内部信号名称
	var dest_signal: String =_get_destination_signal(destination)
	
	# 如果有该信号,继续判断
	if buss.has(dest_signal):
		# 如果信号有对应的方法,则删除
		if buss[dest_signal].has(callback):
			buss[dest_signal].erase(callback)
		else:
			printerr(destination+"没有被绑定的该方法...")
			
		# 删除完成后判断是否方法为空,如果为空就删除信号,释放空间
		if buss[dest_signal]==[]:
			buss.erase(dest_signal)
	else:
		printerr(destination+":没有该信号...")

## 取消某一事件的所有订阅
func unsubscribe_all_unsubscribes(destination: String)->void:
	# 获取内部信号名称
	var dest_signal=_get_destination_signal(destination)
	
	var callbacks=buss[dest_signal]
	# 反向遍历
	for i in range(callbacks.size() - 1, -1, -1):
		unsubscribe(destination,buss[dest_signal][i])

## 获取事件名
func _get_destination_signal(destination:String)-> String:
	var dest_signal:String ="EventBus|%s"% destination
	if not has_user_signal(dest_signal):
		add_user_signal(dest_signal)
	return dest_signal

## 阻塞信号的发出,暂时断开信号连接
func block_event(destination:String)->void:
	# 获取内部信号名称
	var dest_signal=_get_destination_signal(destination)
	block_list.append(dest_signal)

## 取消信号的阻塞状态,恢复信号连接
func unblock_event(destination:String)->void:
	# 获取内部信号名称
	var dest_signal=_get_destination_signal(destination)
	if block_list.has(dest_signal):
		block_list.erase(dest_signal)

## 判断信号的阻塞状态
func event_is_block(destination:String)->bool:
	# 获取内部信号名称
	var dest_signal=_get_destination_signal(destination)
	return block_list.has(dest_signal)

## 冻结事件的添加订阅功能,但是可以正常取消订阅
func lock_event_relationship(destination:String)->void:
	# 获取内部信号名称
	var dest_signal=_get_destination_signal(destination)
	lock_list.append(dest_signal)

## 解冻事件的添加订阅功能
func unlock_event_relationship(destination:String)->void:
	# 获取内部信号名称
	var dest_signal=_get_destination_signal(destination)
	if lock_list.has(dest_signal):
		lock_list.erase(dest_signal)

## 判断信号的冻结状态
func event_is_lock(destination:String)->bool:
	var dest_signal=_get_destination_signal(destination)
	return lock_list.has(dest_signal)

请前往 登录/注册 即可发表您的看法…