xiandie/scene/entity/interactable.gd

208 lines
5.7 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

@tool
class_name Interactable2D extends Sprite2D
# interacted_times 增加后,再发出信号
signal interacted
signal interacted_with_key(key)
signal sign_mark_offset_updated
# sign_mark 节点在 ready 时会直接读取
@export var sign_mark_offset := Vector2.ZERO:
set(val):
sign_mark_offset = val
sign_mark_offset_updated.emit(val)
@export var enabled := true:
set(val):
enabled = val
if is_node_ready():
_check_sign_display()
@export var unrevealed_sign_texture: Texture2D
@export var unmatched_sign_texture: Texture2D
@export var matched_sign_texture: Texture2D
@export var mute_when_interacted := false
@export var mute_when_invalid := false
@export var one_shot := true
@export var one_shot_max_times := 1
@export var disable_prop_after_interacted := false
@export var interacted_texture: Texture2D
var prop_key := ""
var prop_key2 := ""
var prop_key3 := ""
@onready var sfx_invalid = $SfxInvalid as Sfx
@onready var sfx_success = $SfxSuccess as Sfx
@onready var sign_mark = %Sign as Sign
@onready var area2d = %Area2D as Area2D
var ground_archive: GroundArchive
# 尝试互动的次数
var tried_times: int:
set(val):
tried_times = val
ground_archive.set_pair(name, "tried_times", val)
# 成功互动的次数
var interacted_times: int:
set(val):
interacted_times = val
ground_archive.set_pair(name, "interacted_times", val)
static var item_config_res = preload("res://asset/dialogue/item_description.dialogue")
func _ready() -> void:
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)
sign_mark.enabled = enabled
# setup default value
ground_archive = ArchiveManager.archive.ground_archive()
tried_times = ground_archive.get_value(name, "tried_times", 0)
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():
var key = SceneManager.get_current_prop(false)
_set_sign_texture_to_prop(key)
# 根据当前 prop调整 sign 所显示的 texture
func _set_sign_texture_to_prop(key):
if tried_times == 0:
# 首次交互前 unrevealed
sign_mark.sprite2d.texture = unrevealed_sign_texture
return
# 目前默认都显示 matched_sign_texture
sign_mark.sprite2d.texture = matched_sign_texture
# if is_key_matched(key):
# sign_mark.sprite2d.texture = matched_sign_texture
# else:
# sign_mark.sprite2d.texture = unmatched_sign_texture
func _on_cancel(_body = null) -> void:
# 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()
tried_times += 1
if one_shot and interacted_times >= one_shot_max_times:
interact_mutex.unlock()
return
var key = SceneManager.get_current_prop(false)
if not is_key_matched(key):
if not mute_when_invalid:
sfx_invalid.play()
sign_mark.invalid_shake(matched_sign_texture, unmatched_sign_texture)
# SceneManager.on_toggle_invalid_prop()
interact_mutex.unlock()
return
if not mute_when_interacted:
sfx_success.play()
if disable_prop_after_interacted and key:
SceneManager.disable_prop_item(key)
interacted_times += 1
if interacted_texture:
texture = interacted_texture
# interacted_times 增加后,再发出信号
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()
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]
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),
}
]
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
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
return false