xiandie/scene/entity/interactable.gd

195 lines
5.3 KiB
GDScript3
Raw Normal View History

2025-01-12 12:15:18 +00:00
@tool
class_name Interactable2D extends Sprite2D
# interacted_times 增加后,再发出信号
signal interacted
signal interacted_with_key(key)
2025-01-12 12:15:18 +00:00
@export var enabled := true:
set(val):
enabled = val
if is_node_ready():
_check_sign_display()
2025-01-13 08:09:57 +00:00
@export var unmatched_sign_texture: Texture2D
@export var matched_sign_texture: Texture2D
@export var mute_when_interacted := false
@export var mute_when_invalid := false
2025-01-12 12:15:18 +00:00
@export var one_shot := true
@export var one_shot_max_times := 1
@export var disable_prop_after_interacted := false
@export var interacted_texture: Texture2D
2025-01-12 12:15:18 +00:00
var prop_key := ""
var prop_key2 := ""
var prop_key3 := ""
2025-01-13 08:09:57 +00:00
@onready var sfx_invalid = $SfxInvalid as Sfx
@onready var sfx_success = $SfxSuccess as Sfx
2025-01-08 00:51:09 +00:00
@onready var sign_mark = %Sign as Sign
@onready var area2d = %Area2D as Area2D
var ground_archive: GroundArchive
var interacted_times: int:
set(val):
interacted_times = val
ground_archive.set_pair(name, "interacted_times", val)
2025-01-12 12:15:18 +00:00
static var item_config_res = preload("res://asset/dialogue/item_description.dialogue")
func _ready() -> void:
2025-01-12 12:15:18 +00:00
if Engine.is_editor_hint():
return
area2d.body_entered.connect(_reset)
area2d.body_exited.connect(_on_cancel)
sign_mark.interacted.connect(_on_interacted)
sign_mark.cancel.connect(_on_cancel)
2025-01-13 08:09:57 +00:00
sign_mark.base_scale = sign_mark.scale
sign_mark.enabled = enabled
# setup default value
ground_archive = ArchiveManager.archive.ground_archive()
interacted_times = ground_archive.get_value(name, "interacted_times", 0)
if interacted_times and interacted_texture:
texture = interacted_texture
_check_sign_display()
func _check_sign_display():
sign_mark.enabled = enabled and (not one_shot or interacted_times < one_shot_max_times)
func _reset(_body = null) -> void:
_reset_sign_testure_to_prop()
var prop_hud = SceneManager.get_prop_hud() as PropHud
if not prop_hud.current_item_changed.is_connected(_set_sign_texture_to_prop):
prop_hud.current_item_changed.connect(_set_sign_texture_to_prop)
func _reset_sign_testure_to_prop():
2025-01-13 08:09:57 +00:00
var key = SceneManager.get_current_prop(false)
_set_sign_texture_to_prop(key)
2025-01-13 08:09:57 +00:00
# 根据当前 prop调整 sign 所显示的 texture
func _set_sign_texture_to_prop(key):
if is_key_matched(key):
2025-01-13 08:09:57 +00:00
sign_mark.sprite2d.texture = matched_sign_texture
else:
sign_mark.sprite2d.texture = unmatched_sign_texture
# if prop_hud.cached_inventory_textures.has(key):
# var prop_texture = prop_hud.cached_inventory_textures[key]
# sign_mark.draw_shadow = true
# else:
# sign_mark.sprite2d.texture = deaulte_sign_texture
# sign_mark.draw_shadow = false
# sign_mark.queue_redraw()
func _on_cancel(_body = null) -> void:
2025-01-13 08:09:57 +00:00
# disconnect signal
var prop_hud = SceneManager.get_prop_hud() as PropHud
if prop_hud and prop_hud.current_item_changed.is_connected(_set_sign_texture_to_prop):
prop_hud.current_item_changed.disconnect(_set_sign_texture_to_prop)
var interact_mutex = Mutex.new()
func is_key_matched(key) -> bool:
return (
# 第一个 prop_key 若空,则表示不需要匹配
not prop_key
or (
# 只要有一个 prop_key 匹配即可
(prop_key and key == prop_key)
or (prop_key2 and key == prop_key2)
or (prop_key3 and key == prop_key3)
)
)
func _on_interacted() -> void:
interact_mutex.lock()
if one_shot and interacted_times >= one_shot_max_times:
interact_mutex.unlock()
2025-01-12 12:15:18 +00:00
return
2025-01-13 08:09:57 +00:00
var key = SceneManager.get_current_prop(false)
if not is_key_matched(key):
if not mute_when_invalid:
sfx_invalid.play()
2025-01-13 08:09:57 +00:00
sign_mark.invalid_shake()
# SceneManager.on_toggle_invalid_prop()
interact_mutex.unlock()
2025-01-12 12:15:18 +00:00
return
if not mute_when_interacted:
sfx_success.play()
if disable_prop_after_interacted and key:
SceneManager.disable_prop_item(key)
2025-01-12 12:15:18 +00:00
interacted_times += 1
if interacted_texture:
texture = interacted_texture
# interacted_times 增加后,再发出信号
2025-01-12 12:15:18 +00:00
interacted.emit()
interacted_with_key.emit(key)
EventManager.prop_interacted(name, key, interacted_times)
# print("%s interacted with %s. total times: %s" % [name, key, interacted_times])
interact_mutex.unlock()
_check_sign_display()
_reset_sign_testure_to_prop()
2025-01-12 12:15:18 +00:00
func _get_property_list() -> Array[Dictionary]:
var items = []
if Engine.is_editor_hint():
var id = item_config_res.titles["PropItems"]
var current_line = item_config_res.lines[id]
while current_line:
if current_line.has("translation_key"):
items.append(current_line.translation_key)
if not current_line.has("next_id") or current_line.next_id == "end":
break
current_line = item_config_res.lines[current_line.next_id]
2025-01-12 12:15:18 +00:00
return [
{
"name": "prop_key",
"type": TYPE_STRING,
"hint": PROPERTY_HINT_ENUM_SUGGESTION,
"hint_string": ",".join(items),
},
{
"name": "prop_key2",
"type": TYPE_STRING,
"hint": PROPERTY_HINT_ENUM_SUGGESTION,
"hint_string": ",".join(items),
},
{
"name": "prop_key3",
"type": TYPE_STRING,
"hint": PROPERTY_HINT_ENUM_SUGGESTION,
"hint_string": ",".join(items),
2025-01-12 12:15:18 +00:00
}
]
func _get(property: StringName) -> Variant:
if property == "prop_key":
return prop_key
elif property == "prop_key2":
return prop_key2
elif property == "prop_key3":
return prop_key3
2025-01-12 12:15:18 +00:00
return null
func _set(property: StringName, value: Variant) -> bool:
if property == "prop_key":
prop_key = value
return true
elif property == "prop_key2":
prop_key2 = value
return true
elif property == "prop_key3":
prop_key3 = value
return true
2025-01-12 12:15:18 +00:00
return false